1. 程式人生 > >Scrapy:Python的爬蟲框架----原理介紹

Scrapy:Python的爬蟲框架----原理介紹

Scrapy介紹

Scrapy是一個為了爬取網站資料,提取結構性資料而編寫的應用框架。 可以應用在包括資料探勘,資訊處理或儲存歷史資料等一系列的程式中。
所謂網路爬蟲,就是一個在網上到處或定向抓取資料的程式,當然,這種說法不夠專業,更專業的描述就是,抓取特定網站網頁的HTML資料。抓取網頁的一般方法是,定義一個入口頁面,然後一般一個頁面會有其他頁面的URL,於是從當前頁面獲取到這些URL加入到爬蟲的抓取佇列中,然後進入到新頁面後再遞迴的進行上述的操作,其實說來就跟深度遍歷或廣度遍歷一樣。
Scrapy 使用 Twisted這個非同步網路庫來處理網路通訊,架構清晰,並且包含了各種中介軟體介面,可以靈活的完成各種需求。

整體架構


  • 引擎(Scrapy Engine),用來處理整個系統的資料流處理,觸發事務。
  • 排程器(Scheduler),用來接受引擎發過來的請求,壓入佇列中,並在引擎再次請求的時候返回。
  • 下載器(Downloader),用於下載網頁內容,並將網頁內容返回給蜘蛛。
  • 蜘蛛(Spiders),蜘蛛是主要幹活的,用它來制訂特定域名或網頁的解析規則。編寫用於分析response並提取item(即獲取到的item)或額外跟進的URL的類。 每個spider負責處理一個特定(或一些)網站。
  • 專案管道(Item Pipeline),負責處理有蜘蛛從網頁中抽取的專案,他的主要任務是清晰、驗證和儲存資料。當頁面被蜘蛛解析後,將被髮送到專案管道,並經過幾個特定的次序處理資料。
  • 下載器中介軟體(Downloader Middlewares),位於Scrapy引擎和下載器之間的鉤子框架,主要是處理Scrapy引擎與下載器之間的請求及響應。
  • 蜘蛛中介軟體(Spider Middlewares),介於Scrapy引擎和蜘蛛之間的鉤子框架,主要工作是處理蜘蛛的響應輸入和請求輸出。
  • 排程中介軟體(Scheduler Middlewares),介於Scrapy引擎和排程之間的中介軟體,從Scrapy引擎傳送到排程的請求和響應。

爬取流程

上圖綠線是資料流向,首先從初始URL開始,Scheduler會將其交給Downloader進行下載,下載之後會交給Spider進行分析,Spider分析出來的結果有兩種:一種是需要進一步抓取的連結,例如之前分析的“下一頁”的連結,這些東西會被傳回Scheduler;另一種是需要儲存的資料,它們則被送到Item Pipeline那裡,那是對資料進行後期處理(詳細分析、過濾、儲存等)的地方。另外,在資料流動的通道里還可以安裝各種中介軟體,進行必要的處理。

資料流

Scrapy中的資料流由執行引擎控制,其過程如下:

  1. 引擎開啟一個網站(open a domain),找到處理該網站的Spider並向該spider請求第一個要爬取的URL(s)。
  2. 引擎從Spider中獲取到第一個要爬取的URL並在排程器(Scheduler)以Request排程。
  3. 引擎向排程器請求下一個要爬取的URL。
  4. 排程器返回下一個要爬取的URL給引擎,引擎將URL通過下載中介軟體(請求(request)方向)轉發給下載器(Downloader)。
  5. 一旦頁面下載完畢,下載器生成一個該頁面的Response,並將其通過下載中介軟體(返回(response)方向)傳送給引擎。
  6. 引擎從下載器中接收到Response並通過Spider中介軟體(輸入方向)傳送給Spider處理。
  7. Spider處理Response並返回爬取到的Item及(跟進的)新的Request給引擎。
  8. 引擎將(Spider返回的)爬取到的Item給Item Pipeline,將(Spider返回的)Request給排程器。
  9. (從第二步)重複直到排程器中沒有更多地request,引擎關閉該網站。

Scrapy專案基本流程

預設的Scrapy專案結構

使用全域性命令startproject建立專案,在project_name資料夾下建立一個名為project_name的Scrapy專案。

scrapy startproject myproject

雖然可以被修改,但所有的Scrapy專案預設有類似於下邊的檔案結構:

scrapy.cfg
myproject/
    __init__.py
    items.py
    pipelines.py
    settings.py
    spiders/
        __init__.py
        spider1.py
        spider2.py
        ...

scrapy.cfg 存放的目錄被認為是 專案的根目錄 。該檔案中包含python模組名的欄位定義了專案的設定。

定義要抓取的資料

Item 是儲存爬取到的資料的容器;其使用方法和python字典類似, 並且提供了額外保護機制來避免拼寫錯誤導致的未定義欄位錯誤。
類似在ORM中做的一樣,您可以通過建立一個 scrapy.Item 類, 並且定義型別為 scrapy.Field 的類屬性來定義一個Item。
首先根據需要從dmoz.org(DMOZ網站是一個著名的開放式分類目錄(Open DirectoryProject),由來自世界各地的志願者共同維護與建設的最大的全球目錄社群)獲取到的資料對item進行建模。 我們需要從dmoz中獲取名字,url,以及網站的描述。 對此,在item中定義相應的欄位。編輯items.py 檔案:

import scrapy

class DmozItem(scrapy.Item):
    title = scrapy.Field()
    link = scrapy.Field()
    desc = scrapy.Field()

使用專案命令genspider建立Spider

scrapy genspider [-t template] <name> <domain>

在當前專案中建立spider。
這僅僅是建立spider的一種快捷方法。該方法可以使用提前定義好的模板來生成spider。您也可以自己建立spider的原始碼檔案。

$ scrapy genspider -l
Available templates:
  basic
  crawl
  csvfeed
  xmlfeed

$ scrapy genspider -d basic
import scrapy

class $classname(scrapy.Spider):
    name = "$name"
    allowed_domains = ["$domain"]
    start_urls = (
        'http://www.$domain/',
        )

    def parse(self, response):
        pass

$ scrapy genspider -t basic example example.com
Created spider 'example' using template 'basic' in module:
  mybot.spiders.example

編寫提取item資料的Spider

Spider是使用者編寫用於從單個網站(或者一些網站)爬取資料的類。
其包含了一個用於下載的初始URL,如何跟進網頁中的連結以及如何分析頁面中的內容, 提取生成 item 的方法。
為了建立一個Spider,您必須繼承 scrapy.Spider 類,且定義以下三個屬性:

  • name: 用於區別Spider。 該名字必須是唯一的,您不可以為不同的Spider設定相同的名字。
  • start_urls: 包含了Spider在啟動時進行爬取的url列表。 因此,第一個被獲取到的頁面將是其中之一。 後續的URL則從初始的URL獲取到的資料中提取。
  • parse() 是spider的一個方法。 被呼叫時,每個初始URL完成下載後生成的 Response 物件將會作為唯一的引數傳遞給該函式。 該方法負責解析返回的資料(response data),提取資料(生成item)以及生成需要進一步處理的URL的 Request 物件。
import scrapy

class DmozSpider(scrapy.spider.Spider):
    name = "dmoz"    #唯一標識,啟動spider時即指定該名稱
    allowed_domains = ["dmoz.org"]
    start_urls = [
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
        "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"
    ]

    def parse(self, response):
        filename = response.url.split("/")[-2]
        with open(filename, 'wb') as f:
            f.write(response.body)

進行爬取

執行專案命令crawl,啟動Spider:

scrapy crawl dmoz

在這個過程中:
Scrapy為Spider的 start_urls 屬性中的每個URL建立了 scrapy.Request 物件,並將 parse 方法作為回撥函式(callback)賦值給了Request。
Request物件經過排程,執行生成 scrapy.http.Response 物件並送回給spider parse() 方法。

通過選擇器提取資料

Selectors選擇器簡介:
Scrapy提取資料有自己的一套機制。它們被稱作選擇器(seletors),因為他們通過特定的 XPath 或者 CSS 表示式來“選擇” HTML檔案中的某個部分。
XPath 是一門用來在XML檔案中選擇節點的語言,也可以用在HTML上。 CSS 是一門將HTML文件樣式化的語言。選擇器由它定義,並與特定的HTML元素的樣式相關連。

XPath表示式的例子和含義:

  • /html/head/title: 選擇HTML文件中 <head> 標籤內的 <title> 元素
  • /html/head/title/text(): 選擇上面提到的 <title> 元素的文字
  • //td: 選擇所有的 <td> 元素
  • //div[@class="mine"]: 選擇所有具有 class="mine" 屬性的 div 元素

提取資料:
觀察HTML原始碼並確定合適的XPath表示式。
在查看了網頁的原始碼後,您會發現網站的資訊是被包含在 第二個

  • 元素中。
    我們可以通過這段程式碼選擇該頁面中網站列表裡所有
  • 元素:
    response.xpath('//ul/li')

    Item 物件是自定義的python字典。 您可以使用標準的字典語法來獲取到其每個欄位的值。
    一般來說,Spider將會將爬取到的資料以 Item 物件返回。所以為了將爬取的資料返回,我們最終的程式碼將是:

    import scrapy
    
    from tutorial.items import DmozItem
    
    class DmozSpider(scrapy.Spider):
        name = "dmoz"
        allowed_domains = ["dmoz.org"]
        start_urls = [
            "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
            "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"
        ]
    
        def parse(self, response):
            for sel in response.xpath('//ul/li'):
                item = DmozItem()
                item['title'] = sel.xpath('a/text()').extract()
                item['link'] = sel.xpath('a/@href').extract()
                item['desc'] = sel.xpath('text()').extract()
                yield item

    現在對dmoz.org進行爬取將會產生 DmozItem 物件。

    儲存資料

    最簡單儲存爬取的資料的方式是使用 Feed exports:

    scrapy crawl dmoz -o items.json

    該命令將採用 JSON 格式對爬取的資料進行序列化,生成 items.json 檔案。
    如果需要對爬取到的item做更多更為複雜的操作,您可以編寫 Item Pipeline 。類似於我們在建立專案時對Item做的,用於您編寫自己的 tutorial/pipelines.py 也被建立。不過如果您僅僅想要儲存item,您不需要實現任何的pipeline。

    補充提示:Windows平臺安裝Scrapy的特別要求

    • 安裝OpenSSL
      Win32 OpenSSL page中下載安裝Visual C++ 2008 redistributables和對應的OpenSSL安裝包,並把其可執行檔案目錄“*\openssl-win32\bin”加入到環境變數Path中

    小結

    第一篇關於Scrapy的文章主要依據Scrapy 0.24的中文文件,瞭解、熟悉Scrapy的使用和基本概念,在後面的相關文章中,將進一步加入自己的思考和自行編寫的程式,期待能在這個過程中提高自己,也希望能對看到這些文章的讀者有用。

    參考資料