一開(kāi)始參考:
https://blog.csdn.net/qq_16546829/article/details/79511997
后來(lái)?yè)Q了:
https://blog.csdn.net/five_east_west/article/details/108627097
Ajax動(dòng)態(tài)分析
待抓取的微博內(nèi)容:https://m.weibo.cn/u/1742566624
準(zhǔn)備工作:安裝好 requests 庫(kù)、lxml 庫(kù)
在cmd 中輸入
因?yàn)槲抑耙呀?jīng)安裝好這兩個(gè)庫(kù),所以在此安裝的時(shí)候是顯示的下圖的內(nèi)容:
打開(kāi)Chrome瀏覽器,我們進(jìn)入這個(gè)網(wǎng)站:https://m.weibo.cn/u/1742566624撞秋。鼠標(biāo)右鍵,選擇查看網(wǎng)頁(yè)源代碼嚣鄙,這時(shí)候我們會(huì)發(fā)現(xiàn)網(wǎng)頁(yè)源代碼中并沒(méi)有顯示出來(lái)我們?cè)谑醉?yè)看到的那些文字內(nèi)容吻贿,這就說(shuō)明這個(gè)網(wǎng)頁(yè)是Ajax動(dòng)態(tài)加載的。(下圖中左邊為展現(xiàn)給我能夠看到的網(wǎng)頁(yè)哑子,而右邊則是網(wǎng)頁(yè)源代碼)
我們到右邊隨意選擇一條內(nèi)容到左邊進(jìn)行搜索都不會(huì)有結(jié)果舅列,這里以“煙火人間,風(fēng)味長(zhǎng)存卧蜓≌室”為栗子進(jìn)行搜索:
我們看到源代碼中并沒(méi)有出現(xiàn)我們搜索的內(nèi)容,所以該網(wǎng)頁(yè)是Ajax動(dòng)態(tài)加載的弥奸。
??Ajax宠叼,全稱為Asynchronous JavaScript and XML,即異步的JavaScript和XML其爵。它不是一門(mén)編程語(yǔ)言冒冬,而是利用JavaScript在保證頁(yè)面不被刷新、頁(yè)面鏈接不改變的情況下與服務(wù)器交換數(shù)據(jù)并更新部分網(wǎng)頁(yè)的技術(shù)摩渺。
對(duì)于傳統(tǒng)的網(wǎng)頁(yè)简烤,如果想更新其內(nèi)容,那么必須要刷新整個(gè)頁(yè)面摇幻,但有了Ajax横侦,便可以在頁(yè)面不被全部刷新的情況下更新其內(nèi)容。在這個(gè)過(guò)程中绰姻,頁(yè)面實(shí)際上是在后臺(tái)與服務(wù)器進(jìn)行了數(shù)據(jù)交互枉侧,獲取到數(shù)據(jù)之后,再利用JavaScript改變網(wǎng)頁(yè)狂芋,這樣網(wǎng)頁(yè)內(nèi)容就會(huì)更新了榨馁。
可以到W3School上體驗(yàn)幾個(gè)示例來(lái)感受一下:http://www.w3school.com.cn/ajax/ajax_xmlhttprequest_send.asp。
其實(shí)很多網(wǎng)頁(yè)都是這樣的帜矾,我們把網(wǎng)頁(yè)接著往下滑翼虫,會(huì)不斷的刷新加載新的內(nèi)容呈現(xiàn)在我們眼前。
既然我們已經(jīng)知道它是用Ajax動(dòng)態(tài)加載的屡萤,我們就來(lái)分析一波它是如何進(jìn)行數(shù)據(jù)交換的珍剑。
鼠標(biāo)右鍵,選擇檢查(或者按下鍵盤(pán)上的F12)死陆,進(jìn)入開(kāi)發(fā)者模式招拙。網(wǎng)頁(yè)的樣式便展示在了我們眼前。
在Elements中我們能看到網(wǎng)頁(yè)源代碼,右側(cè)是節(jié)點(diǎn)的內(nèi)容别凤,但這并不是我們想要的內(nèi)容饰序,如果按照常規(guī)的網(wǎng)頁(yè)請(qǐng)求并提取網(wǎng)頁(yè)標(biāo)簽中的數(shù)據(jù)是無(wú)法得到我們想要的內(nèi)容的。
我們轉(zhuǎn)到Network闻妓,選擇Network下的XHR菌羽,我們會(huì)看到以下內(nèi)容(第一次進(jìn)入是沒(méi)有這些內(nèi)容的,刷新一下網(wǎng)頁(yè)就好了):
隨著我們不斷的滾動(dòng)鼠標(biāo)滾輪由缆,XHR下加載的內(nèi)容越來(lái)越多注祖,我們會(huì)看到一個(gè)getIndex開(kāi)頭的請(qǐng)求,點(diǎn)開(kāi)它均唉,可以看到它的詳細(xì)信息
我們看到Request Headers它里面有一個(gè)參數(shù)是X-Requested-With: XMLHttpRequest是晨。通過(guò)這個(gè)參數(shù)我們可以更加肯定它是Ajax動(dòng)態(tài)加載的。然后點(diǎn)一下 Headers 旁邊的 Preview舔箭,它里面的數(shù)據(jù)是 json(類似python字典的一種字符串) 格式的罩缴。
點(diǎn)開(kāi)cards下面有10條內(nèi)容,我們?cè)谶M(jìn)到下面9條內(nèi)容中的mblog里面去一 一查看层扶,我們會(huì)發(fā)現(xiàn)箫章,微博正文中包含的文字都包含在了raw_text中
(其實(shí)圖片也包含在這個(gè)請(qǐng)求中,想要把圖片下載下來(lái)的看客朋友可以自己去研究研究圖片的鏈接)镜会。既然已經(jīng)找到我們想要的東西了檬寂,就開(kāi)始寫(xiě)B(tài)UG吧,把這些文字給“抓”下來(lái)戳表,放到自己的“口袋”中桶至。
我們用requests.get(url)來(lái)請(qǐng)求網(wǎng)頁(yè),因?yàn)槲覀円?qǐng)求的網(wǎng)頁(yè)已經(jīng)不是開(kāi)頭給出的那個(gè)網(wǎng)頁(yè)了匾旭,而是通過(guò)我們分析之后找到的那個(gè)Ajax的網(wǎng)頁(yè)請(qǐng)求镣屹。所以我們真正請(qǐng)求的應(yīng)該是這個(gè)網(wǎng)頁(yè)https://m.weibo.cn/api/container/getIndex?uid=1742566624&t=0&luicode=10000011&lfid=100103type%3D1%26q%3D%E6%80%9D%E6%83%B3%E8%81%9A%E7%84%A6&type=uid&value=1742566624&containerid=1076031742566624,打開(kāi)這個(gè)網(wǎng)頁(yè)我們會(huì)發(fā)現(xiàn)价涝,密密麻麻的字符女蜈、數(shù)字,我們?cè)跒g覽器中隨便找一個(gè)json數(shù)據(jù)在線解析網(wǎng)址http://json.cn/飒泻,這里的這個(gè)就可以鞭光,將上面網(wǎng)頁(yè)的內(nèi)容復(fù)制到j(luò)son網(wǎng)頁(yè)中我們就可以看到整齊的json數(shù)據(jù)了,很像python中的字典型式泞遗。
在jupyter中這樣寫(xiě):
我們直接將它轉(zhuǎn)成json格式,在jupyter中打印出來(lái)席覆,隨時(shí)查看網(wǎng)頁(yè)返回的信息是個(gè)什么樣子的東西史辙。(爬蟲(chóng)、數(shù)據(jù)分析等建議使用jupyter,方便隨時(shí)查看結(jié)果)
運(yùn)行上述代碼聊倔,得到以下輸出:
不難發(fā)現(xiàn)晦毙,這個(gè)數(shù)據(jù)就和我們之前在 Preview 中看到的數(shù)據(jù)是一樣的,說(shuō)明我們拿到的就是我們想要的數(shù)據(jù)耙蔑,接下來(lái)將我們要的微博正文內(nèi)容從這個(gè)字典從取出來(lái)就行了见妒。代碼如下:
運(yùn)行結(jié)果如下:
因?yàn)閏ards是一個(gè)列表,它里面包含了十條數(shù)據(jù)甸陌,所以我們用一個(gè)for循環(huán)來(lái)遍歷整個(gè)列表须揣,將數(shù)據(jù)從提取出來(lái),因?yàn)槲覀兎祷氐臄?shù)據(jù)是字典類型的钱豁,所以我們可以直接用get來(lái)提取數(shù)據(jù)耻卡,或者按照鍵值對(duì)來(lái)索引(建議使用get,如果沒(méi)有當(dāng)前鍵而進(jìn)行索引會(huì)報(bào)錯(cuò)牲尺,而get是返回一個(gè)空值卵酪,不會(huì)使程序出錯(cuò)停下來(lái))。就這樣谤碳,我們提取了“第一頁(yè)”的十條數(shù)據(jù)溃卡,但這個(gè)數(shù)據(jù)量往往不能滿足我們的需求。
如果我們一個(gè)網(wǎng)頁(yè)一個(gè)網(wǎng)頁(yè)的去復(fù)制粘貼到到我們的腳本中蜒简,10個(gè)可能問(wèn)題還不大瘸羡,先找到getIndex然后將網(wǎng)頁(yè)復(fù)制,粘貼到腳本中臭蚁,總共三步最铁,10個(gè)網(wǎng)頁(yè)也就30步,可如果是100個(gè)網(wǎng)頁(yè)呢垮兑?這時(shí)候處理起來(lái)就比較麻煩了冷尉。所以我們需要找到一個(gè)構(gòu)造網(wǎng)頁(yè)的“好方法”,讓腳本它自己去“ 尋 找 網(wǎng) 頁(yè) ” → “ 復(fù) 制 ” → “ 粘 貼 ” “尋找網(wǎng)頁(yè)”\rightarrow“復(fù)制”\rightarrow“粘貼”“尋找網(wǎng)頁(yè)”→“復(fù)制”→“粘貼”系枪,一般面對(duì)這種重復(fù)的工作我們都可以交給程序來(lái)完成雀哨。所以我們現(xiàn)在要做的就是”教會(huì)“我們的爬蟲(chóng)腳本去做這個(gè)事情。
在回過(guò)頭來(lái)看看我們請(qǐng)求的網(wǎng)頁(yè):https://m.weibo.cn/api/container/getIndex?uid=1742566624&t=0&luicode=10000011&lfid=100103type%3D1%26q%3D%E6%80%9D%E6%83%B3%E8%81%9A%E7%84%A6&type=uid&value=1742566624&containerid=1076031742566624這是我們請(qǐng)求的第一個(gè)網(wǎng)頁(yè)私爷,我們?cè)賮?lái)看看第二個(gè)我們要請(qǐng)求的網(wǎng)頁(yè)長(zhǎng)得怎么樣:https://m.weibo.cn/api/container/getIndex?uid=1742566624&t=0&luicode=10000011&lfid=100103type%3D1%26q%3D%E6%80%9D%E6%83%B3%E8%81%9A%E7%84%A6&type=uid&value=1742566624&containerid=1076031742566624&since_id=4551744417694196雾棺。第二個(gè)網(wǎng)頁(yè)好像和第一個(gè)網(wǎng)頁(yè)不太一樣,它比第一個(gè)網(wǎng)頁(yè)要多出一個(gè)小尾巴since_id衬浑,其實(shí)我們?cè)偃タ吹谌齻€(gè)捌浩、第四個(gè)、第五個(gè)……從第二個(gè)網(wǎng)頁(yè)開(kāi)始工秩,它們都有了一個(gè)since_id的參數(shù)尸饺,所以我們只要在第一個(gè)網(wǎng)頁(yè)的基礎(chǔ)上給往后的每個(gè)網(wǎng)頁(yè)都加上一個(gè)since_id的參數(shù)就行进统。但是好像每個(gè)網(wǎng)頁(yè)對(duì)應(yīng)的since_id 都是不一樣的,所以我們?nèi)绻窍牒a一個(gè)的方法貌似是行不通的浪听。但是螟碎,它這個(gè)網(wǎng)頁(yè)畢竟是人寫(xiě)的,不是神創(chuàng)的迹栓,所以它這個(gè)since_id一定是有辦法通過(guò)我們聰明的小腦袋瓜”造“出來(lái)的掉分。
既然它這個(gè)網(wǎng)頁(yè)的since_id要被瀏覽器抓到,并不斷請(qǐng)求下一頁(yè)數(shù)據(jù)克伊,那么這個(gè)since_id被我們自己找出來(lái)也不會(huì)是難事酥郭。
果然,我們可以在json數(shù)據(jù)的cardlistInfo中找到一個(gè)since_id的鍵
我們將這個(gè)since_id和下一個(gè)網(wǎng)頁(yè)中的since_id 進(jìn)行比較答毫,它兩就是一樣的(我這里截的是首頁(yè)的since_id褥民,隨著時(shí)間變化這個(gè)since_id也會(huì)變化,看客朋友看到的和我的不一樣是正常的)洗搂,我們像提取文本信息一樣用get將since_id 獲取下來(lái)∠担現(xiàn)在我們找到了這個(gè)since_id 的構(gòu)造規(guī)律,我們就可以來(lái)請(qǐng)求多頁(yè)的網(wǎng)頁(yè)數(shù)據(jù)了耘拇,我們只要教會(huì)我們的爬蟲(chóng)腳本如何利用我們?yōu)樗页鰜?lái)的since_id來(lái)構(gòu)造網(wǎng)頁(yè)撵颊,它就能不斷的獲取網(wǎng)頁(yè)上的內(nèi)容了。
??構(gòu)造網(wǎng)頁(yè)的代碼如下:
urlencode是在urllib.parse中的方法惫叛,以下是官方文檔:
函數(shù)中傳入的since_id就是我們?yōu)榕老x(chóng)找到的since_id倡勇。然后我們把構(gòu)造好的網(wǎng)頁(yè)返回給網(wǎng)頁(yè)請(qǐng)求函數(shù),在解析提取我們要的內(nèi)容以及since_id嘉涌,這樣就可以一直不停的循環(huán)下去了妻熊。
??寫(xiě)個(gè)爬蟲(chóng),應(yīng)該不會(huì)只是為了爬一爬數(shù)據(jù)仑最,而且我們?nèi)绻麓芜€要用這個(gè)數(shù)據(jù)又要重新爬扔役,也會(huì)很麻煩,所以我們將我們從網(wǎng)絡(luò)上”竊取“下來(lái)的東西”藏“起來(lái)警医。這里我們用記事本將這些文本數(shù)據(jù)存下來(lái)(當(dāng)然也可以寫(xiě)到數(shù)據(jù)庫(kù)里面去亿胸,感興趣的看客老爺可以自己去網(wǎng)上搜搜寫(xiě)入數(shù)據(jù)庫(kù)的操作)。保存數(shù)據(jù)代碼如下:
因?yàn)槲覀冞@里抓取的是思想聚焦的微博文章预皇,所以寫(xiě)入的標(biāo)題就是”思想聚焦的微博正文“侈玄,然后每寫(xiě)完一行都空一行(這樣看起來(lái)工整一些)參數(shù)newline就是這個(gè)作用。
到這兒我們的爬蟲(chóng)也就寫(xiě)完了吟温,感興趣的可以做做詞云圖序仙、做一下情感分析等……
完整代碼:
在這個(gè)腳本腳本中我們?cè)O(shè)置了請(qǐng)求頭,讓我們的爬蟲(chóng)看上去更像是瀏覽器在訪問(wèn)鲁豪。
運(yùn)行結(jié)果:
我們檢查網(wǎng)頁(yè)源代碼時(shí)诱桂,發(fā)現(xiàn)源代碼中沒(méi)有我們?cè)诰W(wǎng)頁(yè)上看到的信息時(shí)我們就要想到它時(shí)Ajax動(dòng)態(tài)加載的洋丐。對(duì)于Ajax的網(wǎng)頁(yè)的抓取我們應(yīng)該要去分析它的動(dòng)態(tài)加載包呈昔,而不是直接請(qǐng)求它的源代碼挥等,通過(guò)構(gòu)造Ajax網(wǎng)頁(yè)網(wǎng)址來(lái)實(shí)現(xiàn)多頁(yè)信息的抓取,不同的網(wǎng)站它的url的構(gòu)造方法不一樣堤尾,這一點(diǎn)需要看客朋友自己去找規(guī)律肝劲,構(gòu)造url」Γ看完這篇文章如果你覺(jué)得你會(huì)爬取Ajax的網(wǎng)頁(yè)了辞槐,可以去試試爬取今日頭條上面的內(nèi)容,它也是Ajax加載的粘室。
??提取網(wǎng)頁(yè)信息的方法也是有很多種榄檬,只是在這個(gè)栗子中我們這個(gè)恰巧是字典形式,如果遇到其他情況我們要隨機(jī)應(yīng)變衔统,自己最熟悉的信息提取方式將網(wǎng)頁(yè)信息抓取下來(lái)鹿榜。就介紹到這里吧,有些簡(jiǎn)陋锦爵,但大致能看舱殿。
————————————————————————————————————————
但是遇到有展開(kāi)全文的博文時(shí),
通過(guò)判斷text后面是否有“全文”兩字险掀,若有沪袭,則導(dǎo)出前面的那串?dāng)?shù)字,通過(guò)新的地址(全文地址)樟氢,拿到全文冈绊。(常常有tag,爬下來(lái)的全文中還存在很多地址埠啃,需要后續(xù)刪減
代碼:
用此函數(shù)在main中代替上文get_infos(html)
(有點(diǎn)小錯(cuò)誤還需在改正