pyspider 爬蟲教程(2):AJAX 和 HTTP

發表於2016-09-04

在上一篇教程中,我們使用 self.crawl API 抓取豆瓣電影的 HTML 內容,並使用 CSS 選擇器解析了一些內容。不過,現在的網站通過使用 AJAX 等技術,在你與伺服器互動的同時,不用重新載入整個頁面。但是,這些互動手段,讓抓取變得稍微難了一些:你會發現,這些網頁在抓回來後,和瀏覽器中的並不相同。你需要的資訊並不在返回 HTML 程式碼中。

在這一篇教程中,我們會討論這些技術 和 抓取他們的方法。

AJAX

AJAX 是 Asynchronous JavaScript and XML(非同步的 JavaScript 和 XML)的縮寫。AJAX 通過使用原有的 web 標準元件,實現了在不重新載入整個頁面的情況下,與伺服器進行資料互動。例如在新浪微博中,你可以展開一條微博的評論,而不需要重新載入,或者開啟一個新的頁面。但是這些內容並不是一開始就在頁面中的(這樣頁面就太大了),而是在你點選的時候被載入進來的。這就導致了你抓取這個頁面的時候,並不能獲得這些評論資訊(因為你沒有『展開』)。

AJAX 的一種常見用法是使用 AJAX 載入 JSON 資料,然後在瀏覽器端渲染。如果能直接抓取到 JSON 資料,會比 HTML 更容易解析。

當一個網站使用了 AJAX 的時候,除了用 pyspider 抓取到的頁面和瀏覽器看到的不同以外。你在瀏覽器中開啟這樣的頁面,或者點選『展開』的時候,常常會看到『載入中』或者類似的圖示/動畫。例如,當你嘗試抓取:http://movie.douban.com/explore

pyspider 爬蟲教程(2):AJAX 和 HTTP

你會發現電影是『載入中…』

找到真實的請求

由於 AJAX 實際上也是通過 HTTP 傳輸資料的,所以我們可以通過 Chrome Developer Tools 找到真實的請求,直接發起真實請求的抓取就可以獲得資料了。

  1. 開啟一個新視窗
  2. Ctrl+Shift+I (在 Mac 上請按 Cmd+Opt+I) 開啟開發者工具。
  3. 切換到網路( Netwotk 皮膚)
  4. 在視窗中開啟 http://movie.douban.com/explore

在頁面載入的過程中,你會在皮膚中看到所有的資源請求。

pyspider 爬蟲教程(2):AJAX 和 HTTP

AJAX 一般是通過 XMLHttpRequest 物件介面傳送請求的,XMLHttpRequest 一般被縮寫為 XHR。點選網路皮膚上漏斗形的過濾按鈕,過濾出 XHR 請求。挨個檢視每個請求,通過訪問路徑和預覽,找到包含資訊的請求:http://movie.douban.com/j/searchX61Xsubjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0

pyspider 爬蟲教程(2):AJAX 和 HTTP

在豆瓣這個例子中,XHR 請求並不多,可以挨個檢視來確認。但在 XHR 請求較多的時候,可能需要結合觸發動作的時間,請求的路徑等資訊幫助在大量的請求中找到包含資訊的關鍵請求。這需要抓取或者前端的相關經驗。所以,有一個我一直在提的觀點,學習抓取的最好方法是:學會寫網站。

現在可以在新視窗中開啟 http://movie.douban.com/j/searchX67Xsubjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0,你會看到包含電影資料的 JSON 原始資料。推薦安裝 JSONViewFirfox版)外掛,這樣可以看到更好看的 JSON 格式,展開摺疊列等功能。然後,我們根據 JSON 資料,編寫一個提取電影名和評分的指令碼:

  • 你可以使用 response.json 將結果轉為一個 python 的 dict 物件

你可以在 http://demo.pyspider.org/debug/tutorial_douban_explore 獲得完整的程式碼,並進行除錯。指令碼中還有一個使用 PhantomJS 渲染的提取版本,將會在下一篇教程中介紹。

HTTP

HTTP 是用來傳輸網頁內容的協議。在前面的教程中,我們已經通過 self.crawl 介面提交了 URL 進行了抓取。這些抓取就是通過 HTTP 協議傳輸的。

在抓取過程中,你可能會遇到類似 403 Forbidden,或者需要登入的情況,這時候你就需要正確的 HTTP 引數進行抓取了。

一個典型的 HTTP 請求包如下,這個請求是發往 http://example.com/ 的:

  • 請求的第一行包含 method, path 和 HTTP 協議的版本資訊
  • 餘下的行被稱為 header,是以 key: value 的形式呈現的
  • 如果是 POST 請求,在請求結尾可能還會有 body 內容

你可以通過前面用過的 Chrome Developer Tools 工具檢視到這些資訊:

pyspider 爬蟲教程(2):AJAX 和 HTTP

在大多數時候,使用正確的 method, path, headersbody 總是能抓取到你需要的資訊的。

HTTP Method

HTTP Method 告訴伺服器對 URL 資源期望進行的操作。例如在開啟一個 URL 的時候使用的是 GET 方式,而在提交資料的時候一般使用 POST。

TODO: need example here

HTTP Headers

HTTP Headers 是請求所帶的一個引數列表,你可以在 這裡 找到完整的常用 Headers 列表。一些常用的需要注意的有:

User-Agent

UA 是標識你使用的瀏覽器,或抓取程式的一段字串。pyspider 使用的預設 UA 是 pyspider/VERSION (+http://pyspider.org/)。網站常用這個字串來區分使用者的作業系統和瀏覽器,以及判斷對方是否是爬蟲。所以在抓取的時候,常常會對 UA 進行偽裝。

在 pyspider 中,你可以通過 self.crawl(URL, headers={'User-Agent': 'pyspider'}),或者是 crawl_config = {'headers': {'User-Agent': 'xxxx'}} 來指定指令碼級別的 UA。詳細請檢視 API 文件

Referer

Referer 用於告訴伺服器,你訪問的上一個網頁是什麼。常常被用於防盜鏈,在抓取圖片的時候可能會用到。

X-Requested-With

當使用 XHR 傳送 AJAX 請求時會帶上的 Header,常被用於判斷是不是 AJAX 請求。例如在 北郵人論壇 中,你需要:

帶有 headers={'X-Requested-With': 'XMLHttpRequest'} 才能抓取到內容。

HTTP Cookie

雖然 Cookie 只是 HTTP Header 中的一個,但是因為非常重要,但是拿出來說一下。Cookie 被 HTTP 請求用來區分、追蹤使用者的身份,當你在一個網站登入的時候,就是通過寫入 Cookie 欄位來記錄登入狀態的。

當遇到需要登入的網站,你需要通過設定 Cookie 引數,來請求需要登入的內容。Cookie 可以通過開發者工具的請求皮膚,或者是資源皮膚中獲得。在 pyspider 中,你也可以使用 response.cookies 獲得返回的 cookie,並使用 self.crawl(URL, cookie={'key': 'value'}) 來設定請求的 Cookie 引數。

相關文章