1. 程式人生 > >pyspider 爬蟲教程(一):HTML 和 CSS 選擇器

pyspider 爬蟲教程(一):HTML 和 CSS 選擇器

 

 

雖然以前寫過 如何抓取WEB頁面如何從 WEB 頁面中提取資訊。但是感覺還是需要一篇 step by step 的教程,不然沒有一個總體的認識。不過,沒想到這個教程居然會變成一篇譯文,在這個爬蟲教程系列文章中,會以實際的例子,由淺入深討論爬取(抓取和解析)的一些關鍵問題。

在 教程一 中,我們將要爬取的網站是豆瓣電影:http://movie.douban.com/

你可以在: http://demo.pyspider.org/debug/tutorial_douban_movie 獲得完整的程式碼,和進行測試。

開始之前

由於教程是基於 pyspider 的,你可以安裝一個 pyspider(

Quickstart,也可以直接使用 pyspider 的 demo 環境: http://demo.pyspider.org/

你還應該至少對全球資訊網是什麼有一個簡單的認識:

  • 全球資訊網是一個由許多互相連結的超文字頁面(以下簡稱網頁)組成的系統。
  • 網頁使用網址(URL)定位,並連結彼此
  • 網頁使用 HTTP 協議傳輸
  • 網頁使用 HTML 描述外觀和語義

所以,爬網頁實際上就是:

  1. 找到包含我們需要的資訊的網址(URL)列表
  2. 通過 HTTP 協議把頁面下載回來
  3. 從頁面的 HTML 中解析出需要的資訊
  4. 找到更多這個的 URL,回到 2 繼續

選取一個開始網址

既然我們要爬所有的電影,首先我們需要抓一個電影列表,一個好的列表應該:

  • 包含足夠多的電影的 URL
  • 通過翻頁,可以遍歷到所有的電影
  • 一個按照更新時間排序的列表,可以更快抓到最新更新的電影

我們在 http://movie.douban.com/ 掃了一遍,發現並沒有一個列表能包含所有電影,只能退而求其次,通過抓取分類下的所有的標籤列表頁,來遍歷所有的電影: http://movie.douban.com/tag/

建立一個專案

在 pyspider 的 dashboard 的右下角,點選 "Create" 按鈕

Creating a project

替換 on_start 函式的 self.crawl 的 URL:

@every(minutes=24 * 60)
def on_start(self): self.crawl('http://movie.douban.com/tag/', callback=self.index_page) 
  • self.crawl 告訴 pyspider 抓取指定頁面,然後使用 callback 函式對結果進行解析。
  • @every 修飾器,表示 on_start 每天會執行一次,這樣就能抓到最新的電影了。

點選綠色的 run 執行,你會看到 follows 上面有一個紅色的 1,切換到 follows 面板,點選綠色的播放按鈕:

Run ont step

Tag 列表頁

tag 列表頁 中,我們需要提取出所有的 電影列表頁 的 URL。你可能已經發現了,sample handler 已經提取了非常多大的 URL,所有,一種可行的提取列表頁 URL 的方法就是用正則從中過濾出來:

import re
...

    @config(age=10 * 24 * 60 * 60)
    def index_page(self, response): for each in response.doc('a[href^="http"]').items(): if re.match("http://movie.douban.com/tag/\w+", each.attr.href, re.U): self.crawl(each.attr.href, callback=self.list_page) 
  • 由於 電影列表頁和 tag列表頁長的並不一樣,在這裡新建了一個 callbackself.list_page
  • @config(age=10 * 24 * 60 * 60) 在這表示我們認為 10 天內頁面有效,不會再次進行更新抓取

由於 pyspider 是純 Python 環境,你可以使用 Python 強大的內建庫,或者你熟悉的第三方庫對頁面進行解析。不過更推薦使用 CSS選擇器。

電影列表頁

再次點選 run 讓我們進入一個電影列表頁(list_page)。在這個頁面中我們需要提取:

CSS選擇器

CSS選擇器,顧名思義,是 CSS 用來定位需要設定樣式的元素 所使用的表示式。既然前端程式設計師都使用 CSS選擇器 為頁面上的不同元素設定樣式,我們也可以通過它定位需要的元素。你可以在 CSS 選擇器參考手冊 這裡學習更多的 CSS選擇器 語法。

在 pyspider 中,內建了 response.docPyQuery 物件,讓你可以使用類似 jQuery 的語法操作 DOM 元素。你可以在 PyQuery 的頁面上找到完整的文件。

CSS Selector Helper

在 pyspider 中,還內建了一個 CSS Selector Helper,當你點選頁面上的元素的時候,可以幫你生成它的 CSS選擇器 表示式。你可以點選 Enable CSS selector helper 按鈕,然後切換到 web 頁面:

css selector helper

開啟後,滑鼠放在元素上,會被黃色高亮,點選後,所有擁有相同 CSS選擇器 表示式的元素會被高亮。表示式會被插入到 python 程式碼當前游標位置。建立下面的程式碼,將游標停留在單引號中間:

def list_page(self, response):
    for each in response.doc('').items(): 

點選一個電影的連結,CSS選擇器 表示式將會插入到你的程式碼中,如此重複,插入翻頁的連結:

def list_page(self, response):
    for each in response.doc('HTML>BODY>DIV#wrapper>DIV#content>DIV.grid-16-8.clearfix>DIV.article>DIV>TABLE TR.item>TD>DIV.pl2>A').items(): self.crawl(each.attr.href, callback=self.detail_page) # 翻頁 for each in response.doc('HTML>BODY>DIV#wrapper>DIV#content>DIV.grid-16-8.clearfix>DIV.article>DIV.paginator>A').items(): self.crawl(each.attr.href, callback=self.list_page) 
  • 翻頁是一個到自己的 callback 回撥

電影詳情頁

再次點選 run,follow 到詳情頁。使用 css selector helper 分別新增電影標題,打分和導演:

def detail_page(self, response):
    return { "url": response.url, "title": response.doc('HTML>BODY>DIV#wrapper>DIV#content>H1>SPAN').text(), "rating": response.doc('HTML>BODY>DIV#wrapper>DIV#content>DIV.grid-16-8.clearfix>DIV.article>DIV.indent.clearfix>DIV.subjectwrap.clearfix>DIV#interest_sectl>DIV.rating_wrap.clearbox>P.rating_self.clearfix>STRONG.ll.rating_num').text(), "導演": [x.text() for x in response.doc('a[rel="v:directedBy"]').items()], } 

注意,你會發現 css selector helper 並不是總是能提取到合適的 CSS選擇器 表示式。你可以在 Chrome Dev Tools 的幫助下,寫一個合適的表示式:

Chrome Dev Tools

右鍵點選需要提取的元素,點選審查元素。你並不需要像自動生成的表示式那樣寫出所有的祖先節點,只要寫出那些能區分你不需要的元素的關鍵節點的屬性就可以了。不過這需要抓取和網頁前端的經驗。所以,學習抓取的最好方法就是學會這個頁面/網站是怎麼寫的。

你也可以在 Chrome Dev Tools 的 Javascript Console 中,使用 $$(a[rel="v:directedBy"]) 測試 CSS Selector。

開始抓取

  1. 使用 run 單步除錯你的程式碼,對於用一個 callback 最好使用多個頁面型別進行測試。然後儲存。
  2. 回到 Dashboard,找到你的專案
  3. status 修改為 DEBUGRUNNING
  4. run 按鈕

pyspider index page