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

在上一篇教程中,咱們使用 self.crawl API 抓取豆瓣電影的 HTML 內容,並使用 CSS 選擇器解析了一些內容。不過,如今的網站經過使用 AJAX 等技術,在你與服務器交互的同時,不用從新加載整個頁面。可是,這些交互手段,讓抓取變得稍微難了一些:你會發現,這些網頁在抓回來後,和瀏覽器中的並不相同。你須要的信息並不在返回 HTML 代碼中。html

在這一篇教程中,咱們會討論這些技術 和 抓取他們的方法。(英文版:AJAX-and-more-HTTP前端

AJAX

AJAX 是 Asynchronous JavaScript and XML(異步的 JavaScript 和 XML)的縮寫。AJAX 經過使用原有的 web 標準組件,實現了在不從新加載整個頁面的狀況下,與服務器進行數據交互。例如在新浪微博中,你能夠展開一條微博的評論,而不須要從新加載,或者打開一個新的頁面。可是這些內容並非一開始就在頁面中的(這樣頁面就太大了),而是在你點擊的時候被加載進來的。這就致使了你抓取這個頁面的時候,並不能得到這些評論信息(由於你沒有『展開』)。python

AJAX 的一種常見用法是使用 AJAX 加載 JSON 數據,而後在瀏覽器端渲染。若是能直接抓取到 JSON 數據,會比 HTML 更容易解析。web

當一個網站使用了 AJAX 的時候,除了用 pyspider 抓取到的頁面和瀏覽器看到的不一樣之外。你在瀏覽器中打開這樣的頁面,或者點擊『展開』的時候,經常會看到『加載中』或者相似的圖標/動畫。例如,當你嘗試抓取:http://movie.douban.com/exploreajax

douban explore

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

找到真實的請求

因爲 AJAX 實際上也是經過 HTTP 傳輸數據的,因此咱們能夠經過 Chrome Developer Tools 找到真實的請求,直接發起真實請求的抓取就能夠得到數據了。json

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

在頁面加載的過程當中,你會在面板中看到全部的資源請求。api

douban explore network panel

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瀏覽器

douban explore xhr preview

在豆瓣這個例子中,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 數據,編寫一個提取電影名和評分的腳本:

pythonclass 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/ 的:

httpGET / 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 工具查看到這些信息:

request headers

在大多數時候,使用正確的 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 請求。例如在 北郵人論壇 中,你須要:

pythondef 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 參數。


原文:http://blog.binux.me/2015/01/pyspider-tutorial-level-2-ajax-and-more-http/

相關文章
相關標籤/搜索