有時候咱們在用requests抓取頁面的時候,獲得的結果可能和在瀏覽器中看到的不同:在瀏覽器中能夠看到正常顯示的頁面數據,可是使用requests獲得的結果並無。這是由於requests獲取的都是原始的HTML文檔,而瀏覽器中的頁面則是通過JavaScript處理數據後生成的結果,這些數據的來源有多種,多是經過Ajax加載的,多是包含在HTML文檔中的,也多是通過JavaScript和特定算法計算後生成的。html
對於第一種狀況,數據加載是一種異步加載方式,原始的頁面最初不會包含某些數據,原始頁面加載完後,會再向服務器請求某個接口獲取數據,而後數據才被處理從而呈現到網頁上,這其實就是發送了一個Ajax請求。ajax
照Web發展的趨勢來看,這種形式的頁面愈來愈多。網頁的原始HTML文檔不會包含任何數據,數據都是經過Ajax統一加載後再呈現出來的,這樣在Web開發上能夠作到先後端分離,並且下降服務器直接渲染頁面帶來的壓力。算法
因此若是遇到這樣的頁面,直接利用requests等庫來抓取原始頁面,是沒法獲取到有效數據的,這時須要分析網頁後臺向接口發送的Ajax請求,若是能夠用requests來模擬Ajax請求,那麼就能夠成功抓取了。編程
因此,本章咱們的主要目的是瞭解什麼是Ajax以及如何去分析和抓取Ajax請求。後端
Ajax,全稱爲Asynchronous JavaScript and XML,即異步的JavaScript和XML。它不是一門編程語言,而是利用JavaScript在保證頁面不被刷新、頁面連接不改變的狀況下與服務器交換數據並更新部分網頁的技術。瀏覽器
對於傳統的網頁,若是想更新其內容,那麼必需要刷新整個頁面,但有了Ajax,即可以在頁面不被所有刷新的狀況下更新其內容。在這個過程當中,頁面其實是在後臺與服務器進行了數據交互,獲取到數據以後,再利用JavaScript改變網頁,這樣網頁內容就會更新了。bash
能夠到W3School上體驗幾個示例來感覺一下:www.w3school.com.cn/ajax/ajax_x…。服務器
瀏覽網頁的時候,咱們會發現不少網頁都有下滑查看更多的選項。好比,拿微博來講,咱們以個人我的的主頁爲例:m.weibo.cn/u/283067847…,切換到微博頁面,一直下滑,能夠發現下滑幾個微博以後,再向下就沒有了,轉而會出現一個加載的動畫,不一下子下方就繼續出現了新的微博內容,這個過程其實就是Ajax加載的過程,如圖6-1所示。微信
圖6-1 頁面加載過程網絡
咱們注意到頁面其實並無整個刷新,也就意味着頁面的連接沒有變化,可是網頁中卻多了新內容,也就是後面刷出來的新微博。這就是經過Ajax獲取新數據並呈現的過程。
初步瞭解了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… (二維碼自動識別)