<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          實(shí)戰(zhàn)|Python輕松實(shí)現(xiàn)動(dòng)態(tài)網(wǎng)頁(yè)爬蟲(附詳細(xì)源碼)

          共 6619字,需瀏覽 14分鐘

           ·

          2020-10-03 06:10

          用淺顯易懂的語(yǔ)言分享爬蟲、數(shù)據(jù)分析及可視化等干貨,希望人人都能學(xué)到新知識(shí)。




          項(xiàng)目背景



          事情是這樣的,前幾天我公眾號(hào)寫了篇爬蟲入門的實(shí)戰(zhàn)文章,叫做《實(shí)戰(zhàn)|手把手教你用Python爬蟲(附詳細(xì)源碼)》。發(fā)出去不到一天,一名從業(yè)10年的王律師找到了我,我雖然同意了他的微信申請(qǐng),但內(nèi)心是按奈不住的慌張。



          簡(jiǎn)單交流了下,原來(lái)他在自學(xué)爬蟲,但他發(fā)現(xiàn)翻頁(yè)的時(shí)候,url一直不變。其實(shí)他爬取的是較高難度的網(wǎng)頁(yè),也就是這次要詳細(xì)介紹的動(dòng)態(tài)網(wǎng)頁(yè)。一向樂(lè)于助人的J哥自然會(huì)給他指明方向,以最短的時(shí)間從青銅走向白銀。




          AJAX動(dòng)態(tài)加載網(wǎng)頁(yè)




          什么是動(dòng)態(tài)網(wǎng)頁(yè)


          J哥一向注重理論與實(shí)踐相結(jié)合,知其然也要知其所以然,才能以不變應(yīng)萬(wàn)變。


          所謂的動(dòng)態(tài)網(wǎng)頁(yè),是指跟靜態(tài)網(wǎng)頁(yè)相對(duì)的一種網(wǎng)頁(yè)編程技術(shù)。靜態(tài)網(wǎng)頁(yè),隨著html代碼的生成,頁(yè)面的內(nèi)容和顯示效果就基本上不會(huì)發(fā)生變化了——除非你修改頁(yè)面代碼。而動(dòng)態(tài)網(wǎng)頁(yè)則不然,頁(yè)面代碼雖然沒(méi)有變,但是顯示的內(nèi)容卻是可以隨著時(shí)間、環(huán)境或者數(shù)據(jù)庫(kù)操作的結(jié)果而發(fā)生改變的。——來(lái)源百度百科


          動(dòng)態(tài)網(wǎng)頁(yè)具有減少工作量、內(nèi)容更新快、可完成功能多等特點(diǎn),被很多公司所采用,比如狗東、某寶、某瓣、某乎等等。



          什么是AJAX


          隨著人們對(duì)動(dòng)態(tài)網(wǎng)頁(yè)加載速度的要求越來(lái)越高,AJAX技術(shù)應(yīng)運(yùn)而生并成為許多站點(diǎn)的首選。AJAX是一種用于創(chuàng)建快速動(dòng)態(tài)網(wǎng)頁(yè)的技術(shù),通過(guò)在后臺(tái)與服務(wù)器進(jìn)行少量數(shù)據(jù)交換,使網(wǎng)頁(yè)實(shí)現(xiàn)異步更新。這意味著在不重新加載整個(gè)網(wǎng)頁(yè)的情況下,可以對(duì)網(wǎng)頁(yè)的某部分進(jìn)行更新。



          如何爬取AJAX動(dòng)態(tài)加載網(wǎng)頁(yè)


          1. 解析接口

          只要是有數(shù)據(jù)發(fā)送過(guò)來(lái),那肯定是有發(fā)送到服務(wù)器的請(qǐng)求的吧。我們只需找出它悄悄加載出的頁(yè)面的真實(shí)請(qǐng)求即可。特點(diǎn):爬取速度快,爬取的數(shù)據(jù)干凈,有些網(wǎng)站解析難度較大。


          2. Selenium?

          selenium是什么呢?它本來(lái)是個(gè)自動(dòng)化測(cè)試工具,但是被廣泛的用戶拿去爬蟲了。它是一個(gè)工具,這個(gè)工具可以用代碼操作瀏覽器,比如控制瀏覽器的下滑、模擬鼠標(biāo)點(diǎn)擊等。特點(diǎn):代碼較簡(jiǎn)單,爬取速度慢,容易被封ip。




          項(xiàng)目實(shí)操



          怎么說(shuō)了那么多理論,說(shuō)實(shí)話J哥也不想那么啰嗦。可是吧,這些東西經(jīng)常會(huì)被問(wèn)到,干脆直接寫下來(lái),下次還有人問(wèn)就直接把這篇文章發(fā)給他,一勞永逸!




          OK,咱們繼續(xù)回到王律師的part。王律師作為一名資深律師,深知研究法院歷年公示的開(kāi)庭信息、執(zhí)行信息等對(duì)于提升業(yè)務(wù)能力具有重要作用。于是,他興高采烈地打開(kāi)了一個(gè)法院信息公示網(wǎng)頁(yè)。


          長(zhǎng)這樣:



          然后,他根據(jù)J哥之前寫的爬蟲入門文章去爬數(shù)據(jù),成功提取了第一頁(yè),內(nèi)心無(wú)比之激動(dòng)。



          緊接著,他加了個(gè)for循環(huán),想著花個(gè)幾分鐘時(shí)間把此網(wǎng)站2164頁(yè)共計(jì)32457條開(kāi)庭公告數(shù)據(jù)提取到excel里。


          然后,也就沒(méi)有然后了。各位看了前面的理論部分應(yīng)該也知道了,他這是 AJAX動(dòng)態(tài)加載的網(wǎng)頁(yè)。無(wú)論你怎么點(diǎn)擊下一頁(yè),url是不會(huì)變化的。你不信我點(diǎn)給你看看,左上角的url像山一樣矗立在那:




          解析接口


          既然如此,那我們就開(kāi)啟爬蟲的正確姿勢(shì)吧,先用解析接口的方法來(lái)寫爬蟲。


          首先,找到真實(shí)請(qǐng)求。右鍵檢查,點(diǎn)擊Network,選中XHR,刷新網(wǎng)頁(yè),選擇Name列表中的jsp文件。沒(méi)錯(cuò),就這么簡(jiǎn)單,真實(shí)請(qǐng)求就藏在里面。


          ?


          我們?cè)僮屑?xì)看看這個(gè)jsp,這簡(jiǎn)直是個(gè)寶啊。有真實(shí)請(qǐng)求url,有請(qǐng)求方法post,有Headers,還有Form Data,而From Data表示給url傳遞的參數(shù),通過(guò)改變參數(shù),咱們就可以獲得數(shù)據(jù)!為了安全,我把自個(gè)Cookie打了個(gè)馬賽克,機(jī)智的朋友也許發(fā)現(xiàn)了我順帶給自個(gè)打了個(gè)廣告。



          我們?cè)僮屑?xì)看看這些參數(shù),pagesnum參數(shù)不就是代表頁(yè)數(shù)嘛!王律師頓悟,原來(lái)他心心念念的翻頁(yè)在這里!跨過(guò)千山萬(wàn)水終于找到你!我們嘗試點(diǎn)擊翻頁(yè),發(fā)現(xiàn)只有pagesnum參數(shù)會(huì)變化。



          既然發(fā)現(xiàn)了它,那就趕緊抓住它。J哥以迅雷不及掩耳勢(shì)打開(kāi)PyCharm,導(dǎo)入了爬蟲所需的庫(kù)。


          1from?urllib.parse?import?urlencode
          2import?csv
          3import?random
          4import?requests
          5import?traceback
          6from?time?import?sleep
          7from?lxml?import?etree????#lxml為第三方網(wǎng)頁(yè)解析庫(kù),強(qiáng)大且速度快


          構(gòu)造真實(shí)請(qǐng)求,添加Headers。這里J哥沒(méi)有貼自己的User-Agent和Cookie,主要是一向膽小甚微的J哥害怕啊。


           1base_url?=?'http://www.hshfy.sh.cn/shfy/gweb2017/ktgg_search_content.jsp?'??#這里要換成對(duì)應(yīng)Ajax請(qǐng)求中的鏈接
          2
          3headers?=?{
          4????'Connection':?'keep-alive',
          5????'Accept':?'*/*',
          6????'X-Requested-With':?'XMLHttpRequest',
          7????'User-Agent':?'你的User-Agent',
          8????'Origin':?'http://www.hshfy.sh.cn',
          9????'Referer':?'http://www.hshfy.sh.cn/shfy/gweb2017/ktgg_search.jsp?zd=splc',
          10????'Accept-Language':?'zh-CN,zh;q=0.9',
          11????'Content-Type':?'application/x-www-form-urlencoded',
          12????'Cookie':?'你的Cookie'
          13}


          構(gòu)建get_page函數(shù),自變量為page,也就是頁(yè)數(shù)。以字典類型創(chuàng)建表單data,用post方式去請(qǐng)求網(wǎng)頁(yè)數(shù)據(jù)。這里要注意要對(duì)返回的數(shù)據(jù)解碼,編碼為'gbk',否則返回的數(shù)據(jù)會(huì)亂碼!另外我還加了異常處理優(yōu)化了下,以防意外發(fā)生。


           1def?get_page(page):
          2????n?=?3
          3????while?True:
          4????????try:
          5????????????sleep(random.uniform(1,?2))??#?隨機(jī)出現(xiàn)1-2之間的數(shù),包含小數(shù)
          6????????????data?=?{
          7????????????????'yzm':?'yxAH',
          8????????????????'ft':'',
          9????????????????'ktrqks':?'2020-05-22',
          10????????????????'ktrqjs':?'2020-06-22',
          11????????????????'spc':'',
          12????????????????'yg':'',
          13????????????????'bg':'',
          14????????????????'ah':'',
          15????????????????'pagesnum':?page
          16????????????}
          17????????????url?=?base_url?+?urlencode(data)
          18????????????print(url)
          19????????????try:
          20????????????????response?=?requests.request("POST",url,?headers?=?headers)
          21????????????????#print(response)
          22????????????????if?response.status_code?==?200:
          23????????????????????re?=?response.content.decode('gbk')
          24????????????????????#?print(re)
          25????????????????????return?re??#?解析內(nèi)容
          26????????????except?requests.ConnectionError?as?e:
          27????????????????print('Error',?e.args)??#?輸出異常信息
          28????????except?(TimeoutError,?Exception):
          29????????????n?-=?1
          30????????????if?n?==?0:
          31????????????????print('請(qǐng)求3次均失敗,放棄此url請(qǐng)求,檢查請(qǐng)求條件')
          32????????????????return
          33????????????else:
          34????????????????print('請(qǐng)求失敗,重新請(qǐng)求')
          35????????????????continue


          構(gòu)建parse_page函數(shù),對(duì)返回的網(wǎng)頁(yè)數(shù)據(jù)進(jìn)行解析,用Xpath提取所有字段內(nèi)容,保存為csv格式。有人會(huì)問(wèn)為啥J哥這么喜歡用Xpath,因?yàn)楹?jiǎn)單好用啊!!!這么簡(jiǎn)單的網(wǎng)頁(yè)結(jié)構(gòu)搞個(gè)正則大法裝x,J哥我做不到啊。


           1def?parse_page(html):
          2????try:
          3????????parse?=?etree.HTML(html)??#?解析網(wǎng)頁(yè)
          4????????items?=?parse.xpath('//*[@id="report"]/tbody/tr')
          5????????for?item?in?items[1:]:
          6????????????item?=?{
          7????????????????'a':?''.join(item.xpath('./td[1]/font/text()')).strip(),
          8????????????????'b':?''.join(item.xpath('./td[2]/font/text()')).strip(),
          9????????????????'c':?''.join(item.xpath('./td[3]/text()')).strip(),
          10????????????????'d':?''.join(item.xpath('./td[4]/text()')).strip(),
          11????????????????'e':?''.join(item.xpath('./td[5]/text()')).strip(),
          12????????????????'f':?''.join(item.xpath('./td[6]/div/text()')).strip(),
          13????????????????'g':?''.join(item.xpath('./td[7]/div/text()')).strip(),
          14????????????????'h':?''.join(item.xpath('./td[8]/text()')).strip(),
          15????????????????'i':?''.join(item.xpath('./td[9]/text()')).strip()
          16????????????}
          17????????????#print(item)
          18????????????try:
          19????????????????with?open('./law.csv',?'a',?encoding='utf_8_sig',?newline='')?as?fp:
          20????????????????????#?'a'為追加模式(添加)
          21????????????????????#?utf_8_sig格式導(dǎo)出csv不亂碼
          22????????????????????fieldnames?=?['a',?'b',?'c',?'d',?'e','f','g','h','i']
          23????????????????????writer?=?csv.DictWriter(fp,fieldnames)
          24????????????????????writer.writerow(item)
          25????????????except?Exception:
          26????????????????print(traceback.print_exc())??#代替print?e?來(lái)輸出詳細(xì)的異常信息
          27????except?Exception:
          28????????print(traceback.print_exc())


          最后,遍歷一下頁(yè)數(shù),調(diào)用一下函數(shù)。OK,搞定!


          1????for?page?in?range(1,5):??#這里設(shè)置想要爬取的頁(yè)數(shù)
          2????????html?=?get_page(page)
          3????????#print(html)
          4????????print("第"?+?str(page)?+?"頁(yè)提取完成")


          我們來(lái)看一下最終效果:




          Selenium


          好學(xué)的朋友可能還想看看Selenium是如何來(lái)爬AJAX動(dòng)態(tài)加載網(wǎng)頁(yè)的,J哥自然會(huì)滿足你的好奇心。于是趕緊新建了一個(gè)py文件,準(zhǔn)備趁勢(shì)追擊,用Selenium把這網(wǎng)站爬下來(lái)。


          首先,把相關(guān)庫(kù)導(dǎo)進(jìn)來(lái)。


          1from?lxml?import?etree
          2import?time
          3from?selenium?import?webdriver
          4from?selenium.?webdriver.support.wait?import?WebDriverWait
          5from?selenium.webdriver.support?import?expected_conditions?as?EC
          6from?selenium.webdriver.common.by?import?By


          然后,用chromedriver驅(qū)動(dòng)打開(kāi)這個(gè)網(wǎng)站。


          1def?main():
          2????#?爬取首頁(yè)url
          3????url?=?"http://www.hshfy.sh.cn/shfy/gweb2017/flws_list.jsp?ajlb=aYWpsYj3D8crCz"
          4????#?定義谷歌webdriver
          5????driver?=?webdriver.Chrome('./chromedriver')
          6????driver.maximize_window()??#?將瀏覽器最大化
          7????driver.get(url)


          于是,驚喜的發(fā)現(xiàn),報(bào)錯(cuò)了。J哥憑借著六級(jí)英語(yǔ)的詞匯儲(chǔ)量,居然看懂了!大概意思是我的驅(qū)動(dòng)和瀏覽器的版本不匹配,只支持79版本的瀏覽器。



          J哥很郁悶,因?yàn)槲乙郧芭老x用Selenium沒(méi)出現(xiàn)過(guò)這種問(wèn)題啊。J哥不甘心,于是打開(kāi)了谷歌瀏覽器看了下版本號(hào)。



          我丟!都更新到81版本啦!既然這樣,那就請(qǐng)好奇的小伙伴等J哥設(shè)置好瀏覽器自動(dòng)更新、重新下載最新驅(qū)動(dòng)后,下次再來(lái)聽(tīng)窩講Selenium爬蟲吧,記得關(guān)注此公眾號(hào),精彩不錯(cuò)過(guò)哦~




          結(jié) 語(yǔ)



          總結(jié)一下,對(duì)于AJAX動(dòng)態(tài)加載網(wǎng)頁(yè)爬蟲,一般就兩種方式:解析接口;Selenium。J哥推薦解析接口的方式,如果解析的是json數(shù)據(jù),就更好爬了。實(shí)在沒(méi)轍了再用Selenium吧


          參考鏈接:

          Ajax:https://www.w3school.com.cn/php/php_ajax_intro.asp;

          Ajax_json:https://www.jianshu.com/p/1897a8068dfb;

          Examples:https://www.zhihu.com/question/46528604?sort=created





          PS:在公眾號(hào)【小詹學(xué)Python】后臺(tái)回復(fù)"law"即可自動(dòng)獲取本項(xiàng)目完整代碼啦~


          由于微信平臺(tái)算法改版,公號(hào)內(nèi)容將不再以時(shí)間排序展示,如果大家想第一時(shí)間看到我們的推送,強(qiáng)烈建議星標(biāo)我們和給我們多點(diǎn)點(diǎn)【在看】。星標(biāo)具體步驟為:


          (1)點(diǎn)擊頁(yè)面最上方“小詹學(xué)Python”,進(jìn)入公眾號(hào)主頁(yè)。


          (2)點(diǎn)擊右上角的小點(diǎn)點(diǎn),在彈出頁(yè)面點(diǎn)擊“設(shè)為星標(biāo)”,就可以啦。


          感謝支持,比心。

          瀏覽 33
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  蜜芽亚洲av无码精品色午夜 | 在线观看国产黄 | 漂亮女大学一级毛片视频 | 欧美乱轮视 | 日韩久久精品视频 |