爬取Ajax動態載入和翻頁時url不變的網頁

這兩天投了一家公司的爬蟲實習生,筆試題是完成一個爬蟲的小需求。網站沒有什麼反爬的高級技巧。但是有非常常見的,並不是針對我們爬蟲的,卻讓我們新手很難理解的ajax動態載入技術和乍一看不明白的翻頁時不變的url。還有一些小坑,特此總結一下。希望大家也能收穫一些東西。

1 . 什麼是 AJAX ?

AJAX = 非同步 JavaScript 和 XML。

AJAX 是一種用於創建快速動態網頁的技術。

通過在後台與伺服器進行少量數據交換,AJAX 可以使網頁實現非同步更新。這意味著可以在不重新載入整個網頁的情況下,對網頁的某部分進行更新。

傳統的網頁(不使用 AJAX)如果需要更新內容,必需重載整個網頁面。

幾個常見的用到ajax的場景。

比如你在逛知乎,你沒有刷新過網頁,但是你卻能看到你關注的用戶或者話題有了新動態的消息提示。

還比如,我們在看視頻時,可以看到下面的評論沒有完全全部載入出來,而是你向下拖動一點,它給你載入一點。

為什麼要用到ajax呢?

從上述場景你應該也可以發現它的優點,

第一,方便與用戶的交互,不用重新載入整個網頁,就可以實現刷新,不用中斷用戶的行為。你正在看程序員如何找對象呢,此時來個消息推送,整個網頁被刷新了,你說你氣不氣!

第二個呢,還是你在看程序員如何找對象,但是此時通信狀況不好啊。回答載入不出來,頁面就空白的卡那了,回答載入不出來,你說急不急!那這樣咯,先給你看幾個回答,在你看的時候我再悄悄的載入其它的數據,那不就解決了嗎?就跟吃飯一個道理,你點了一桌子菜,難道菜全做好了再給你上嗎?肯定不會的呀,做好一道上一道嘛,對不對。

第三,從服務端的發送過來的ajax數據,體積比較小。瀏覽器知道怎麼渲染它,這樣就減輕了服務端的壓力,讓客戶端,也就是瀏覽器承擔了一些任務。

Ajax技術的核心是XMLHttpRequest對象(簡稱XHR),可以通過使用XHR對象獲取到伺服器的數據,然後再通過DOM將數據插入到頁面中呈現。雖然名字中包含XML,但Ajax通訊與數據格式無關,所以我們的數據格式可以是XML或JSON等格式。

XMLHttpRequest對象用於在後台與伺服器交換數據,具體作用如下:

  • 在不重新載入頁面的情況下更新網頁
  • 在頁面已載入後從伺服器請求數據
  • 在頁面已載入後從伺服器接收數據
  • 在後台向伺服器發送數據

ajax不是我們的重點,想深入學習的朋友自行了解,ajax的核心機制XMLHttpRequest去吧。我們爬數據來著的哈。

2. Ajax對爬蟲有什麼影響?

還是對應著上述的場景,我爬蟲肯定要爬取一個完整數據。但是你一次就只教我兩種找對象的方法。還不夠我舉一反三呢,萬一其中還有幾個段子,那這樣的數據不具有完整性,不夠全面。但是不滑動瀏覽器,數據不出來怎麼辦?

更坑爹是什麼,ajax載入出來的數據是通過瀏覽器渲染給我們的呀,源代碼不一定能找到我們要的數據。那該腫么辦!瀏覽器知道怎麼載入, 我們不知道呀!

3.如何爬取這樣的ajax動態載入的網頁。

其實有好多種方法。

1. Selenium + PhantomJs

PhantomJS是一個無界面的,可腳本編程的WebKit瀏覽器引擎。它原生支持多種web 標準:DOM 操作,CSS選擇器,JSON,Canvas 以及SVG。它的作用是和瀏覽器類似,可以渲染js處理的頁面。

selenium是什麼呢?它本來是個自動化測試工具,但是被廣泛的用戶爬蟲啊。它是一個工具,這個工具可以用代碼操作瀏覽器。比如控制瀏覽器的下滑之類。不過我並不是很熟悉,以前了解過一點。

不過,我沒用這種方法。為啥呢,因為慢。操作瀏覽器的時間加起來好多好多了唄,而且又不是沒有更好的辦法。

2. 自己找,找真實請求。

只要是有數據發送過來,那肯定是有發送到伺服器的請求的吧。我們只需找出它悄悄載入出的頁面的真實請求在哪發送的。

那這次的需求舉例。

我需要拿到它的型號, Part Number。

按照常理,Ctrl + U,查看網頁源代碼。Ctrl + F,查找型號。

0 條!!! 源代碼沒有數據。那我們來分析network, 請求在哪咯。

打開開發者工具,快捷鍵F12,不行就Fn + F12.

標紅的1, network, 在其中可以看到伺服器載入過來的資源。

標紅的2, 是一個過濾器,你可以按照文件格式篩選。

標紅的3,是載入過來的具體文件。

我們要做的,就是在伺服器發送過來的具體文件中找到我們需要的數據。

在XHR中找到feature-search.ket中,選擇response查看它的響應。也是是伺服器發過來的json文件的內容。

至於為什麼是XHR, 前面已經解釋了。往前找。

而我們前面也提到過了XML HttpRequest 是ajax的核心機制。想深入了解的同學請自行查找資料。

再進行初步的篩選後,我們還需自己仔細的查看每個文件的response是否有我們需要的內容。

這是feature-search.ket的response,典型的json的k-v的鍵值對結構。在截取的一小段json格式的代碼中,我們可以看到有我們需要的型號信息, 在k == PARTNUMBER , 對應的value裡面。

這裡推薦一個json在線校驗網址。一個大神告訴我的。

在線JSON校驗格式化工具(Be JSON)

其實也很好找,我們獲得頁面必然是有請求,有提交給伺服器的數據。from data 就是我們提交的數據。 Request URL: 數據提交的url地址, 我們向這個url去提交數據。

截取其中的response中的部分代碼。

"searchInfo": {n "page": 1,n "totalRow": 3321,n "totalNotiRow": 0,n "pageLimit": 10,n "rowLimit": 20,n "rowStart": 0,n "rowEnd": 20,n "rowNum": 0,n "searchType": "",n "searchKey": "",n "searchKeyEnc": "",n "searchSubType": "",n "searchSubKey": "",n "searchStartDate": "",n "searchEndDate": "",n "searchGubunType": "",n "searchGubunType2": "",n "searchGubunType3": "",n "searchGubunType4": "",n "searchGubunType5": "",n "delSeq": null,n "fileUploadSeq": "",n "filExpl": "",n "fileMenuCd": "",n "partNumber": "",n "categoryDepth": 1,n "categoryCd": "CA01",n "attrId": "",n "spSeries": "",n "selectCategory": "",n "totalCategoryRow": 0,n "spCategoryCode": "",n "spPartStyle": null,n "spTabSize": null,n "spNoOfPole": null,n "spPitch": null,n "spWaterProof": null,n "spLanceType": null,n "spSUBSuppliy": null,n "spMountWayApE": null,n "spInterface": null,n "spCodingNColor": null,n "spPinNShape": null,n "spImpedance": null,n "spSoldering": null,n "spConnCombDir": null,n "spFlameLevel": null,n "spGWITMaterAt": null,n "spConntHeight": null,n "spCableConMeth": null,n "spActuatorLctn": null,n "spTabThickness": null,n "spWireRangeMm": null,n "spPlating": null,n "spTermPrezType": null,n "spMaterialMark": null,n "spTerminalType": null,n "spStudSize": null,n "spPermitVolt": null,n "spMainChipset": null,n "spFrequency": null,n "spDcpower": null,n "spLockTConn": null,n "spLockingType": null,n "spSealType": null,n "spOptimumTemp": null,n "spWireRangeAWG": null,n "spConnectorType": nulln },n

4. 瀏覽器的地址欄中的URL不變,如何翻頁。

相信心細的同學已經發現了。Headers中的request method 中顯示我們使用的是POST方法。

而且FROM Data 中有一個參數,page。

我在具體實現時採用的requests庫。使用requests.post(), 去post的需要提交的參數即可。這樣就可以實現爬蟲的自動翻頁。

熟悉http協議的同學,應該知道,get 和 post 方法的區別。

POST 和 GET

W3school 裡面已經講的很清楚明白了。反正,如果在我們翻頁時,或者執行某個頁面上的操作,如果在url不變的情況下,數據已經被刷新或者改變,我們就該考慮。採用的POST的方法提交。

像這樣,我們在知乎搜索編程,url中可以看到多了編程,說明這是get方法。POST方法比GET更安全。畢竟,沒人願意自己的密碼,手機號都顯示在瀏覽器的URL欄中。

到這裡,我們對需要爬取的網頁的基本規律已經分析的比較清楚了。剩餘就是實際上的一些操作了。

總結:

另外在這次的爬取的過程中,發現了產品信號和詳情頁信息對應的錯位情況。

在這裡提醒大家,就算在爬取到信息後,也要仔細查看數據的正確性。

考慮到網路中眾多的複雜情況,比如產品型號拿到了,需要的詳情頁信息有可能並不存在。那麼我們通過構造產品型號構造的產品詳情頁的URL,取不到響應的詳情信息。

本來是1,2,3,4,5,6,7,8,9 相互對應的,如果 2, 3, 4, 5的詳情頁信息缺失,就會造成信息對應錯位。

畢竟數據方面的工作,一不小心就會造成重大損失。所以,一定在爬取之後核對信息,寫代碼時,考慮到其他方面的眾多因素。

最後附上github源碼: github

requests 爬取數據, mysql存儲。

另外,爬蟲的夥伴們。對人家的伺服器,手下留情。。。

推薦閱讀:

【Python爬蟲實戰】——爬取今日頭條美女圖片
爬蟲軟體|軟體的簡單使用(二)
數據採集技術指南 第一篇 技術棧總覽
校長,我要上車——python模擬登錄熊貓TV
從零開始寫Python爬蟲 --- 3.1 Selenium模擬瀏覽器

TAG:爬虫 | Python | requests |