1. 程式人生 > >Python 爬蟲 (六) -- Scrapy 框架學習

Python 爬蟲 (六) -- Scrapy 框架學習

本文希望達到以下目標:

  1. 簡要介紹Scarpy
  2. 閱讀官網入門文件並實現文件中的範例
  3. 使用Scarpy優豆瓣爬蟲的抓取
  4. 制定下一步學習目標

初學Scrapy, 如有翻譯不當, 或者程式碼錯誤, 請指出, 非常感謝

1. Scrapy簡介

Scrapy是一個為了爬取網站資料,提取結構性資料而編寫的應用框架。 可以應用在包括資料探勘,資訊處理或儲存歷史資料等一系列的程式中。
其最初是為了頁面抓取 (更確切來說, 網路抓取 )所設計的, 也可以應用在獲取API所返回的資料(例如 Amazon Associates Web Services ) 或者通用的網路爬蟲。Scrapy用途廣泛,可以用於資料探勘、監測和自動化測試

Scrapy 使用了 Twisted非同步網路庫來處理網路通訊。整體架構大致如下

Scrapy Architecture

Scrapy

Scrapy主要包括了以下元件:

  • 引擎(Scrapy): 用來處理整個系統的資料流處理, 觸發事務(框架核心)
  • 排程器(Scheduler): 用來接受引擎發過來的請求, 壓入佇列中, 並在引擎再次請求的時候返回. 可以想像成一個URL(抓取網頁的網址或者說是連結)的優先佇列, 由它來決定下一個要抓取的網址是什麼, 同時去除重複的網址
  • 下載器(Downloader): 用於下載網頁內容, 並將網頁內容返回給蜘蛛(Scrapy下載器是建立在twisted這個高效的非同步模型上的)
  • 爬蟲(Spiders): 爬蟲是主要幹活的, 用於從特定的網頁中提取自己需要的資訊, 即所謂的實體(Item)。使用者也可以從中提取出連結,讓Scrapy繼續抓取下一個頁面
  • 專案管道(Pipeline): 負責處理爬蟲從網頁中抽取的實體,主要的功能是持久化實體、驗證實體的有效性、清除不需要的資訊。當頁面被爬蟲解析後,將被髮送到專案管道,並經過幾個特定的次序處理資料。
  • 下載器中介軟體(Downloader Middlewares): 位於Scrapy引擎和下載器之間的框架,主要是處理Scrapy引擎與下載器之間的請求及響應。
  • 爬蟲中介軟體(Spider Middlewares): 介於Scrapy引擎和爬蟲之間的框架,主要工作是處理蜘蛛的響應輸入和請求輸出。
  • 排程中介軟體(Scheduler Middewares): 介於Scrapy引擎和排程之間的中介軟體,從Scrapy引擎傳送到排程的請求和響應。

Scrapy執行流程大概如下:

  1. 首先,引擎從排程器中取出一個連結(URL)用於接下來的抓取
  2. 引擎把URL封裝成一個請求(Request)傳給下載器,下載器把資源下載下來,並封裝成應答包(Response)
  3. 然後,爬蟲解析Response
  4. 若是解析出實體(Item),則交給實體管道進行進一步的處理。
  5. 若是解析出的是連結(URL),則把URL交給Scheduler等待抓取

2. 安裝Scrapy

使用以下命令:

Python
12345678910111213141516171819202122 sudo pip install virtualenv#安裝虛擬環境工具virtualenv ENV#建立一個虛擬環境目錄source./ENV/bin/active#啟用虛擬環境pip install Scrapy#驗證是否安裝成功pip list#輸出如下cffi(0.8.6)cryptography(0.6.1)cssselect(0.9.1)lxml(3.4.1)pip(1.5.6)pycparser(2.10)pyOpenSSL(0.14)queuelib(1.2.2)Scrapy(0.24.4)setuptools(3.6)six(1.8.0)Twisted(14.0.2)w3lib(1.10.0)wsgiref(0.1.2)zope.interface(4.1.1)

3. Scrapy Tutorial

在抓取之前, 你需要新建一個Scrapy工程. 進入一個你想用來儲存程式碼的目錄,然後執行:

Python
1 $scrapy startproject tutorial

這個命令會在當前目錄下建立一個新目錄 tutorial, 它的結構如下:

Python
123456789 .├──scrapy.cfg└──tutorial├──__init__.py├──items.py├──pipelines.py├──settings.py└──spiders└──__init__.py

這些檔案主要是:

  • scrapy.cfg: 專案配置檔案
  • tutorial/: 專案python模組, 之後您將在此加入程式碼
  • tutorial/items.py: 專案items檔案
  • tutorial/pipelines.py: 專案管道檔案
  • tutorial/settings.py: 專案配置檔案
  • tutorial/spiders: 放置spider的目錄

3.1. 定義Item

Items是將要裝載抓取的資料的容器,它工作方式像 python 裡面的字典,但它提供更多的保護,比如對未定義的欄位填充以防止拼寫錯誤。

通過建立scrapy.Item類, 並且定義型別為 scrapy.Field 的類屬性來宣告一個Item.

我們通過將需要的item模型化,來控制從 dmoz.org 獲得的站點資料,比如我們要獲得站點的名字,url 和網站描述,我們定義這三種屬性的域。在 tutorial 目錄下的 items.py 檔案編輯

Python
12345678 fromscrapy.item importItem,FieldclassDmozItem(Item):# define the fields for your item here like:name=Field()description=Field()url=Field()

3.2. 編寫Spider

Spider 是使用者編寫的類, 用於從一個域(或域組)中抓取資訊, 定義了用於下載的URL的初步列表, 如何跟蹤連結,以及如何來解析這些網頁的內容用於提取items。

要建立一個 Spider,繼承 scrapy.Spider 基類,並確定三個主要的、強制的屬性:

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

這個方法負責解析返回的資料、匹配抓取的資料(解析為 item )並跟蹤更多的 URL。

在 /tutorial/tutorial/spiders 目錄下建立 dmoz_spider.py

Python
1234567891011121314 importscrapyclassDmozSpider(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/"]defparse(self,response):filename=response.url.split("/")[-2]withopen(filename,'wb')asf:f.write(response.body)

3.3. 爬取

當前專案結構

Python
123456789 ├──scrapy.cfg└──tutorial├──__init__.py├──items.py├──pipelines.py├──settings.py└──spiders├──__init__.py└──dmoz_spider.py

到專案根目錄, 然後執行命令:

Python
1 $scrapy crawl dmoz

執行結果:

Python
1234567891011121314151617181920212223242526272829303132 2014-12-1509:30:59+0800[scrapy]INFO:Scrapy0.24.4started(bot:tutorial)2014-12-1509:30:59+0800[scrapy]INFO:Optional features available:ssl,http112014-12-1509:30:59+0800[scrapy]INFO:Overridden settings:{'NEWSPIDER_MODULE':'tutorial.spiders','SPIDER_MODULES':['tutorial.spiders'],'BOT_NAME':'tutorial'}2014-12-1509:30:59+0800[scrapy]INFO:Enabled extensions:LogStats,TelnetConsole,CloseSpider,WebService,CoreStats,SpiderState2014-12-1509:30:59+0800[scrapy]INFO:Enabled downloader middlewares:HttpAuthMiddleware,DownloadTimeoutMiddleware,UserAgentMiddleware,RetryMiddleware,DefaultHeadersMiddleware,MetaRefreshMiddleware,HttpCompressionMiddleware,RedirectMiddleware,CookiesMiddleware,ChunkedTransferMiddleware,DownloaderStats2014-12-1509:30:59+0800[scrapy]INFO:Enabled spider middlewares:HttpErrorMiddleware,OffsiteMiddleware,RefererMiddleware,UrlLengthMiddleware,DepthMiddleware2014-12-1509:30:59+0800[scrapy]INFO:Enabled item pipelines:2014-12-1509:30:59+0800[dmoz]INFO:Spider opened2014-12-1509:30:59+0800[dmoz]INFO:Crawled0pages(at0pages/min),scraped0items(at0items/min)2014-12-1509:30:59+0800[scrapy]DEBUG:Telnet console listening on127.0.0.1:60232014-12-1509:30:59+0800[scrapy]DEBUG:Web service listening on127.0.0.1:60802014-12-1509:31:00+0800[dmoz]DEBUG:Crawled(200)<GET http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/>(referer:None)2014-12-1509:31:00+0800[dmoz]DEBUG:Crawled(200)<GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/>(referer:None)2014-12-1509:31:00+0800[dmoz]INFO:Closing spider(finished)2014-12-1509:31:00+0800[dmoz]INFO:Dumping Scrapy stats:{'downloader/request_bytes':516,'downloader/request_count':2,'downloader/request_method_count/GET':2,'downloader/response_bytes':16338,'downloader/response_count':2,'downloader/response_status_count/200':2,'finish_reason':'finished','finish_time':datetime.datetime(2014,12,15,1,31,0,666214),'log_count/DEBUG':4,'log_count/INFO':7,'response_received_count':2,'scheduler/dequeued':2,'scheduler/dequeued/memory':2,'scheduler/enqueued':2,'scheduler/enqueued/memory':2,'start_time':datetime.datetime(2014,12,15,1,30,59,533207)}2014-12-1509:31:00+0800[dmoz]INFO:Spider closed(finished)

3.4. 提取Items

3.4.1. 介紹Selector

從網頁中提取資料有很多方法。Scrapy使用了一種基於 XPath 或者 CSS 表示式機制: Scrapy Selectors

出XPath表示式的例子及對應的含義:

  • /html/head/title: 選擇HTML文件中 標籤內的 元素
  • /html/head/title/text(): 選擇 元素內的文字
  • //td: 選擇所有的 元素
  • //div[@class=”mine”]: 選擇所有具有