用ChatGpt 實(shí)現(xiàn)一次簡單的 python 新手爬蟲

前言

1.適合有一定程序思維的速成者。
2.適合有其他語言基礎(chǔ)的速成者相叁。

爬蟲流程

1.明確需求
就是你要從哪個(gè)網(wǎng)址拿到什么信息,本次我們需要yelp 的二級(jí)網(wǎng)址拿到商戶的商戶名,電話须尚,地址哄尔,訪問鏈接假消。
2.分析網(wǎng)址
查找你所需要的內(nèi)容的相關(guān)熟悉。
3.開發(fā)調(diào)試
vscode 或者 pycharm
3.輸出文檔
輸出csv文檔

開始搞活

1.先看下需求
需要在yelp網(wǎng)址上查找固定的幾個(gè)美國州 ['FL','GA','IL','IN','MD','MA','MI', 'NJ','NY','NC','OH','PA','SC','TN','TX','VA']內(nèi) "All You Can Eat" l類型的店鋪信息.
如下圖所示岭接,具體鏈接為https://www.yelp.com/search?find_desc=All+You+Can+Eat&find_loc=FL

image.png

可以看到總21頁富拗,每頁10條,除了正常要獲取的10條商戶信息外還有,數(shù)量不固定的廣告位鸣戴。為了好爬取信息啃沪,我這邊直接忽略廣告位的信息。直接爬取每頁最多10條的商戶信息窄锅。

2.點(diǎn)擊第二頁查看下不同頁數(shù)的 訪問規(guī)律:
https://www.yelp.com/search?find_desc=All+You+Can+Eat&find_loc=FL&start=10
每頁start+10

3.接著查看 我們需要的數(shù)據(jù)在哪個(gè)位置
打開瀏覽器的F12 進(jìn)入調(diào)試模式创千,建議google瀏覽器


image.png

通過初步分析發(fā)現(xiàn)我們要的數(shù)據(jù)在這邊,看過去class name都是固定的,也有我們要的列表點(diǎn)擊進(jìn)去的二級(jí)url追驴。


image.png

或者通過這種方式查找
image.png

通過觀察發(fā)現(xiàn)數(shù)據(jù)在<Script>標(biāo)簽下面
image.png

下面這個(gè)是列表的名稱和地址


image.png

本文通過的是爬取Script標(biāo)簽數(shù)據(jù)械哟,來獲取二級(jí)網(wǎng)址。

4.獲取到二級(jí)網(wǎng)址后殿雪,我們繼續(xù)分析二級(jí)網(wǎng)址內(nèi)容
如下圖所示暇咆,電話,地址都有了丙曙。


image.png

通過f12 看看這些東西在哪里


image.png

看上圖就可以直接看出name,telephone,address

5.東西都查找完了爸业,這個(gè)時(shí)候,如何提取亏镰,如何編寫代碼呢沃呢,對(duì)于不熟悉python的人來說,chatGpt就可以派上用場了,哪里報(bào)錯(cuò)了拆挥,就問chatGpt薄霜,邊問邊搞。
比如:
如何獲取scrpt 標(biāo)簽中的內(nèi)容


image.png

如何爬取script標(biāo)簽中的指定內(nèi)容(正則)


image.png

只要你懂的問纸兔,就有結(jié)果惰瓜。

接下來我們用chatGpt來邊問邊寫代碼.
先看看代碼主體流程

# 程序結(jié)構(gòu)
class xxxSpider(object):
    def __init__(self):
        # 定義常用變量,比如url或計(jì)數(shù)變量等
       
    def get_html(self):
        # 獲取響應(yīng)內(nèi)容函數(shù),使用隨機(jī)User-Agent
   
    def parse_html(self):
        # 使用正則表達(dá)式來解析頁面,提取數(shù)據(jù)
   
    def write_html(self):
        # 將提取的數(shù)據(jù)按要求保存汉矿,csv崎坊、MySQL數(shù)據(jù)庫等
       
    def run(self):
        # 主函數(shù),用來控制整體邏輯
       
if __name__ == '__main__':
    # 程序開始運(yùn)行時(shí)間
    spider = xxxSpider()
    spider.run()

基本上的爬蟲流程就是這樣的洲拇,定義url奈揍,獲取url的內(nèi)容,解析url赋续,把獲取到的東西寫到文件中存儲(chǔ)男翰。

具體的代碼如下:
csv 文件工具 csvUtil.py

import csv
def writeCsv(name,urls):
    with open(name+'.csv', 'w', newline='') as csvfile:
        writer = csv.writer(csvfile)
        #構(gòu)建字段名稱,也就是key
        # 寫入表頭
        writer.writerow(['url'])
        # 寫入每個(gè) URL
        for url in urls:
            writer.writerow([url])
def initShopCsv(name):
    with open(name+'.csv', 'w', newline='') as csvfile:
        writer = csv.writer(csvfile)
        #構(gòu)建字段名稱纽乱,也就是key
        # 寫入表頭
        writer.writerow(['ShopName',"Phone","Address","Url"])
        
def writeShopCsv(data,name):
    with open(name+'.csv', 'a', newline='', encoding='utf-8') as csvfile:
        writer = csv.writer(csvfile)
        # 寫入每個(gè)
        writer.writerow(data)
        print("寫入數(shù)據(jù):"+str(data))

常量類address_info.py

states=['FL','GA','IL','IN','MD','MA','MI',
                  'NJ','NY','NC','OH','PA','SC','TN','TX','VA']

主體代碼 yelp.py

from urllib import parse
import time
import random
from fake_useragent import UserAgent
import requests
from lxml import etree
from bs4 import BeautifulSoup
import re
import json
import csvUtil
from static.address_info import states
#忽略ssl報(bào)錯(cuò)
requests.packages.urllib3.disable_warnings()
import concurrent.futures

class openTableSpider(object):
    #1.初始化蛾绎,設(shè)置基地址
    def __init__(self):
        self.url='https://www.yelp.com/search?{}'
     
    #2.搜索店面,加入頭部信息,查詢時(shí)間理應(yīng)大于當(dāng)前時(shí)間,否則容易被發(fā)現(xiàn)不是人工點(diǎn)擊
    #查找到收尋的店明的列表信息
    def searchShopHtml(self,url,state,size):
        #參數(shù)信息
        params={
            'find_desc':"All You Can Eat",
            'find_loc':state,
            'start':size
        }
        #格式化信息
        full_url=url.format(parse.urlencode(params))
        print(""+full_url)
        ua=UserAgent()
        # req=requests.Request(url=full_url,)
        respone=requests.get(url=full_url,headers={'User-Agent':'AdsBot-Google'},verify=False)
       # 使用 BeautifulSoup 解析 HTML
        soup = BeautifulSoup(respone.text, 'html.parser')
        # 查找所有的 <script> 標(biāo)簽
        script_tags = soup.find_all('script')
        # 輸出每個(gè) <script> 標(biāo)簽的內(nèi)容
        for script in script_tags:
            script_str=script.string
            # 關(guān)鍵字   businessUrl /biz 開頭
            if script_str and 'businessUrl' in script_str:
                # print("開始:"+script_str)
                #查找到相應(yīng)的訪問url
                link_match=re.findall(r'"businessUrl":"([^"]+)"',script_str)
                if link_match:
                    format_urls=[x for x in link_match if "ad_business_id" not in x]
                    # 去重
                    urls = list(set(format_urls))
                    # print(len(urls))
                    print(str(urls))
                    # csvUtil.writeCsv(shopName,link_match)
                    return urls
                   
       
     # 3.解析查找到的每家店的url,并且獲取到店面和電話號(hào)碼鸦列,以及地址租冠。
    def parse_Url(self,url,state):
        url="https://www.yelp.com/"+url
     
        print("Start doing "+url)
        ua=UserAgent()
        respone=requests.get(url=url,headers={'User-Agent':ua.random},verify=False)
        # 使用 BeautifulSoup 解析 HTML
        soup = BeautifulSoup(respone.text, 'html.parser')
        # 查找所有的 <script> 標(biāo)簽
        script_tags = soup.find_all('script')
        # 輸出每個(gè) <script> 標(biāo)簽的內(nèi)容
        # 找到name,phone,address 數(shù)據(jù)的位置,發(fā)現(xiàn)在 script標(biāo)簽底下
        # name window.__INITIAL_STATE__   restaurantProfile  restaurant  name   address  
        #  phone=  contactInformation   formattedPhoneNumber
        #  address address":{Phone number
        for script in script_tags:
            script_str=script.string
            address=name=phone=""
            if script_str and 'telephone' in script_str:
                # print(script_str)
                m_address = re.search( r'"address":{(.*?)},', script_str)
                if m_address:
                    # {"line1":"5115 Wilshire Blvd","line2":"","state":"CA","city":"Los Angeles","postCode":"90036","country":"United States","__typename":"Address"},
                    temp=m_address.group(1)
                    # print(temp)
                    try:
                        streetAddress = re.search(r'"streetAddress":"([^"]*)"', temp).group(1)
                        addressLocality = re.search( r'"addressLocality":"([^"]*)"', temp).group(1)
                        addressCountry = re.search( r'"addressCountry":"([^"]*)"', temp).group(1)
                        addressRegion = re.search( r'"addressRegion":"([^"]*)"', temp).group(1)
                        postalCode = re.search(r'"postalCode":"([^"]*)"', temp).group(1)
                        address=streetAddress.replace("\\n","")+","+addressLocality+","+addressRegion+","+postalCode
                        print(address)
                        # flag=any(item.upper() in state.upper() for item in openTableAddress)
                        # # 如果不在地址池中的店薯嗤,則不記錄下來
                        # if flag is False:
                        #     return
                    except  Exception as e:
                        address=streetAddress+","+addressLocality+","+addressRegion+","+postalCode
                        print("地址解析異常:", e)
                    
                m_name = re.search( r'"name":"(.*?)",', script_str)
                if m_name:
                    name=m_name.group(1)
                    # print(name)
                m_phone = re.search( r'telephone":"(.*?)",', script_str)
                if m_phone:
                    phone=m_phone.group(1)
                    # print(phone)
                data=[name,phone,address,url] 
                csvUtil.writeShopCsv(data=data,name=state)                   
        
    # 4.一個(gè)一個(gè)流程
    def doTransaction(self,state,page):
        urls=self.searchShopHtml(self.url,state,page)
        if not urls:
            return
        print(len(urls))
        while len(urls)%10==0:
            print(len(urls))
            new_urls=[]
            reptry=0
            page+=10
            reptry=0
            #重試10次
            while(reptry<10):
                try:
                    new_urls = self.searchShopHtml(spider.url,state, page)
                    break
                except  Exception as e:
                        print("發(fā)生了其他異常:", e)
                        # 重試一次
                        reptry+=1
                        time.sleep(random.randint(5,10))
             # 如果沒有新的URLs顽爹,即查詢結(jié)果為空,終止循環(huán)
            if not new_urls:
                break
            urls += new_urls
            time.sleep(random.randint(5,10))                
            
        count=0     
        #重試10次
        for url in urls:
            reptry=0
            while(reptry<10):
                try:
                    self.parse_Url(url,state) 
                    count+=1
                    print(state+" deal count "+str(count))
                    break
                except  Exception as e:
                    print("發(fā)生了其他異常:", e)
                    reptry+=1
                finally:
                    time.sleep(random.randint(3,10))     
    
    #5.入口函數(shù)
    def run(self):
        
        for state in states:
              csvUtil.initShopCsv(state)
        # 創(chuàng)建線程池并并發(fā)執(zhí)行任務(wù)
        with concurrent.futures.ThreadPoolExecutor() as executor:
        # 使用executor.map并發(fā)執(zhí)行任務(wù)骆姐,傳遞參數(shù)列表
            executor.map(self.doTransaction, states, [0] * len(states))
        print("All tasks have been submitted.")
        # # 單線程處理
        # threads = []
        # for state in states:
        #      print(state)
        #      csvUtil.initShopCsv(state)
        #      thread = threading.Thread(target=)
        #      thread.start()
        #      threads.append(thread)
       
        # # 等待所有線程完成
        # for thread in threads:
        #     thread.join()
      
if __name__=='__main__':
    start=time.time()
    spider=openTableSpider() #實(shí)例化一個(gè)對(duì)象spider
    # spider.searchShopHtml(spider.url,"New York",0) #調(diào)用入口函數(shù)
    # spider.parse_Url("biz/zen-korean-bbq-duluth?osq=All+You+Can+Eat+Buffet","GEORGIA") 
    spider.run()
    end=time.time()
    #查看程序執(zhí)行時(shí)間
    print('執(zhí)行時(shí)間:%.2f'%(end-start)) 

具體內(nèi)容查看注釋,有不懂操作的直接問gpt

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末镜粤,一起剝皮案震驚了整個(gè)濱河市捏题,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌繁仁,老刑警劉巖涉馅,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件归园,死亡現(xiàn)場離奇詭異黄虱,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)庸诱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門捻浦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人桥爽,你說我怎么就攤上這事朱灿。” “怎么了钠四?”我有些...
    開封第一講書人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵盗扒,是天一觀的道長。 經(jīng)常有香客問我缀去,道長侣灶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任缕碎,我火速辦了婚禮褥影,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘咏雌。我一直安慰自己凡怎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開白布赊抖。 她就那樣靜靜地躺著统倒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪氛雪。 梳的紋絲不亂的頭發(fā)上檐薯,一...
    開封第一講書人閱讀 50,084評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音注暗,去河邊找鬼坛缕。 笑死,一個(gè)胖子當(dāng)著我的面吹牛捆昏,可吹牛的內(nèi)容都是我干的赚楚。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼骗卜,長吁一口氣:“原來是場噩夢啊……” “哼宠页!你這毒婦竟也來了左胞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤举户,失蹤者是張志新(化名)和其女友劉穎烤宙,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俭嘁,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡躺枕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了供填。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拐云。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖近她,靈堂內(nèi)的尸體忽然破棺而出叉瘩,到底是詐尸還是另有隱情,我是刑警寧澤粘捎,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布薇缅,位于F島的核電站,受9級(jí)特大地震影響攒磨,放射性物質(zhì)發(fā)生泄漏泳桦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一咧纠、第九天 我趴在偏房一處隱蔽的房頂上張望蓬痒。 院中可真熱鬧,春花似錦漆羔、人聲如沸梧奢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽亲轨。三九已至,卻和暖如春鸟顺,著一層夾襖步出監(jiān)牢的瞬間惦蚊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來泰國打工讯嫂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蹦锋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓欧芽,卻偏偏與公主長得像莉掂,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子千扔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容