有時候我們在用requests抓取頁面的時候,得到的結果可能和在瀏覽器中看到的不一樣:在瀏覽器中可以看到正常顯示的頁面資料,但是使用requests得到的結果並沒有。這是因為requests獲取的都是原始的HTML文件,而瀏覽器中的頁面則是經過JavaScript處理資料後生成的結果,這些資料的來源有多種,可能是通過Ajax載入的,可能是包含在HTML文件中的,也可能是經過JavaScript和特定演算法計算後生成的。
對於第一種情況,資料載入是一種非同步載入方式,原始的頁面最初不會包含某些資料,原始頁面載入完後,會再向伺服器請求某個介面獲取資料,然後資料才被處理從而呈現到網頁上,這其實就是傳送了一個Ajax請求。
照Web發展的趨勢來看,這種形式的頁面越來越多。網頁的原始HTML文件不會包含任何資料,資料都是通過Ajax統一載入後再呈現出來的,這樣在Web開發上可以做到前後端分離,而且降低伺服器直接渲染頁面帶來的壓力。
所以如果遇到這樣的頁面,直接利用requests等庫來抓取原始頁面,是無法獲取到有效資料的,這時需要分析網頁後臺向介面傳送的Ajax請求,如果可以用requests來模擬Ajax請求,那麼就可以成功抓取了。
所以,本章我們的主要目的是瞭解什麼是Ajax以及如何去分析和抓取Ajax請求。
Ajax,全稱為Asynchronous JavaScript and XML,即非同步的JavaScript和XML。它不是一門程式語言,而是利用JavaScript在保證頁面不被重新整理、頁面連結不改變的情況下與伺服器交換資料並更新部分網頁的技術。
對於傳統的網頁,如果想更新其內容,那麼必須要重新整理整個頁面,但有了Ajax,便可以在頁面不被全部重新整理的情況下更新其內容。在這個過程中,頁面實際上是在後臺與伺服器進行了資料互動,獲取到資料之後,再利用JavaScript改變網頁,這樣網頁內容就會更新了。
可以到W3School上體驗幾個示例來感受一下:www.w3school.com.cn/ajax/ajax_x…。
1. 例項引入
瀏覽網頁的時候,我們會發現很多網頁都有下滑檢視更多的選項。比如,拿微博來說,我們以我的個人的主頁為例:m.weibo.cn/u/283067847…,切換到微博頁面,一直下滑,可以發現下滑幾個微博之後,再向下就沒有了,轉而會出現一個載入的動畫,不一會兒下方就繼續出現了新的微博內容,這個過程其實就是Ajax載入的過程,如圖6-1所示。
圖6-1 頁面載入過程
我們注意到頁面其實並沒有整個重新整理,也就意味著頁面的連結沒有變化,但是網頁中卻多了新內容,也就是後面刷出來的新微博。這就是通過Ajax獲取新資料並呈現的過程。
2. 基本原理
初步瞭解了Ajax之後,我們再來詳細瞭解它的基本原理。傳送Ajax請求到網頁更新的這個過程可以簡單分為以下3步:
(1) 傳送請求; (2) 解析內容; (3) 渲染網頁。
下面我們分別來詳細介紹這幾個過程。
傳送請求
我們知道JavaScript可以實現頁面的各種互動功能,Ajax也不例外,它也是由JavaScript實現的,實際上執行了如下程式碼:
1234567891011121314var xmlhttp;if (window.XMLHttpRequest) { // code for IE7+, Firefox, Chrome, Opera, Safari xmlhttp=new XMLHttpRequest();} else {// code for IE6, IE5 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.getElementById("myDiv").innerHTML=xmlhttp.responseText; }}xmlhttp.open("POST","/ajax/",true);xmlhttp.send();複製程式碼
這是JavaScript對Ajax最底層的實現,實際上就是新建了XMLHttpRequest
物件,然後呼叫onreadystatechange
屬性設定了監聽,然後呼叫open()
和send()
方法向某個連結(也就是伺服器)傳送了請求。前面用Python實現請求傳送之後,可以得到響應結果,但這裡請求的傳送變成JavaScript來完成.由於設定了監聽,所以當伺服器返回響應時,onreadystatechange
對應的方法便會被觸發,然後在這個方法裡面解析響應內容即可。
解析內容
得到響應之後,onreadystatechange
屬性對應的方法便會被觸發,此時利用xmlhttp
的responseText
屬性便可取到響應內容。這類似於Python中利用requests向伺服器發起請求,然後得到響應的過程。那麼返回內容可能是HTML,可能是JSON,接下來只需要在方法中用JavaScript進一步處理即可。比如,如果是JSON的話,可以進行解析和轉化。
渲染網頁
JavaScript有改變網頁內容的能力,解析完響應內容之後,就可以呼叫JavaScript來針對解析完的內容對網頁進行下一步處理了。比如,通過document.getElementById().innerHTML
這樣的操作,便可以對某個元素內的原始碼進行更改,這樣網頁顯示的內容就改變了,這樣的操作也被稱作DOM操作,即對Document網頁文件進行操作,如更改、刪除等。
上例中,document.getElementById("myDiv").innerHTML=xmlhttp.responseText
便將ID
為myDiv
的節點內部的HTML程式碼更改為伺服器返回的內容,這樣myDiv
元素內部便會呈現出伺服器返回的新資料,網頁的部分內容看上去就更新了。
我們觀察到,這3個步驟其實都是由JavaScript完成的,它完成了整個請求、解析和渲染的過程。
再回想微博的下拉重新整理,這其實就是JavaScript向伺服器傳送了一個Ajax請求,然後獲取新的微博資料,將其解析,並將其渲染在網頁中。
因此,我們知道,真實的資料其實都是一次次Ajax請求得到的,如果想要抓取這些資料,需要知道這些請求到底是怎麼傳送的,發往哪裡,發了哪些引數。如果我們知道了這些,不就可以用Python模擬這個傳送操作,獲取到其中的結果了嗎?
在下一節中,我們就來了解下到哪裡可以看到這些後臺Ajax操作,去了解它到底是怎麼傳送的,傳送了什麼引數。
本資源首發於崔慶才的個人部落格靜覓: Python3網路爬蟲開發實戰教程 | 靜覓
如想了解更多爬蟲資訊,請關注我的個人微信公眾號:進擊的Coder
weixin.qq.com/r/5zsjOyvEZ… (二維碼自動識別)