天天看點

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

在上一篇教程《pyspider 爬蟲教程 (1):html 和 css 選擇》中,我們使用 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 找到真實的請求,直接發起真實請求的抓取就可以獲得資料了。

打開一個新視窗

按 ctrl+shift+i (在 mac 上請按 cmd+opt+i) 打開開發者工具。

切換到網絡( netwotk 面闆)

在視窗中打開 http://movie.douban.com/explore

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

pyspider爬蟲教程 (2):AJAX和HTTP
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 原始資料。推薦安裝 jsonview(firfox版)插件,這樣可以看到更好看的 json 格式,展開折疊列等功能。然後,我們根據

json 資料,編寫一個提取電影名和評分的腳本:

class handler(basehandler): 

    def on_start(self): 

        self.crawl('http://movie.douban.com/j/search_subjects?type=movie&tag=%e7%83%ad%e9%97%a8&sort=recommend&page_limit=20&page_start=0', 

                   callback=self.json_parser) 

    def json_parser(self, response): 

        return [{ 

            "title": x['title'], 

            "rate": x['rate'], 

            "url": x['url'] 

        } for x in response.json['subjects']]  

你可以使用 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/ 的:

get / http/1.1 

host: example.com 

connection: keep-alive 

cache-control: max-age=0 

accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 

user-agent: mozilla/5.0 (macintosh; intel mac os x 10_10_1) applewebkit/537.36 (khtml, like gecko) chrome/40.0.2214.45 safari/537.36 

referer: http://en.wikipedia.org/wiki/example.com 

accept-encoding: gzip, deflate, sdch 

accept-language: zh-cn,zh;q=0.8 

if-none-match: "359670651" 

if-modified-since: fri, 09 aug 2013 23:54:35 gmt  

請求的第一行包含 method, path 和 http 協定的版本資訊

餘下的行被稱為 header,是以 key: value 的形式呈現的

如果是 post 請求,在請求結尾可能還會有 body 内容

你可以通過前面用過的 chrome developer tools 工具檢視到這些資訊:

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

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

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 請求。例如在 北郵人論壇 中,你需要:

def on_start(self): 

        self.crawl('http://bbs.byr.cn/board/python', 

                   headers={'x-requested-with': 'xmlhttprequest'}, 

                   callback=self.index_page)  

帶有 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 參數。

作者:佚名

來源:51cto