【scrapy】學(xué)習(xí)Scrapy入門

Scrapy介紹

Scrapy是一個(gè)為了爬取網(wǎng)站數(shù)據(jù),提取結(jié)構(gòu)性數(shù)據(jù)而編寫的應(yīng)用框架。 可以應(yīng)用在包括數(shù)據(jù)挖掘,信息處理或存儲(chǔ)歷史數(shù)據(jù)等一系列的程序中。
所謂網(wǎng)絡(luò)爬蟲,就是一個(gè)在網(wǎng)上到處或定向抓取數(shù)據(jù)的程序,當(dāng)然,這種說(shuō)法不夠?qū)I(yè),更專業(yè)的描述就是,抓取特定網(wǎng)站網(wǎng)頁(yè)的HTML數(shù)據(jù)。抓取網(wǎng)頁(yè)的一般方法是,定義一個(gè)入口頁(yè)面,然后一般一個(gè)頁(yè)面會(huì)有其他頁(yè)面的URL,于是從當(dāng)前頁(yè)面獲取到這些URL加入到爬蟲的抓取隊(duì)列中,然后進(jìn)入到新頁(yè)面后再遞歸的進(jìn)行上述的操作,其實(shí)說(shuō)來(lái)就跟深度遍歷或廣度遍歷一樣。
Scrapy 使用 Twisted這個(gè)異步網(wǎng)絡(luò)庫(kù)來(lái)處理網(wǎng)絡(luò)通訊,架構(gòu)清晰,并且包含了各種中間件接口,可以靈活的完成各種需求。

整體架構(gòu)

  • 引擎(Scrapy Engine),用來(lái)處理整個(gè)系統(tǒng)的數(shù)據(jù)流處理,觸發(fā)事務(wù)。
  • 調(diào)度器(Scheduler),用來(lái)接受引擎發(fā)過(guò)來(lái)的請(qǐng)求,壓入隊(duì)列中,并在引擎再次請(qǐng)求的時(shí)候返回。
  • 下載器(Downloader),用于下載網(wǎng)頁(yè)內(nèi)容,并將網(wǎng)頁(yè)內(nèi)容返回給蜘蛛。
  • 蜘蛛(Spiders),蜘蛛是主要干活的,用它來(lái)制訂特定域名或網(wǎng)頁(yè)的解析規(guī)則。編寫用于分析response并提取item(即獲取到的item)或額外跟進(jìn)的URL的類。 每個(gè)spider負(fù)責(zé)處理一個(gè)特定(或一些)網(wǎng)站。
  • 項(xiàng)目管道(Item Pipeline),負(fù)責(zé)處理有蜘蛛從網(wǎng)頁(yè)中抽取的項(xiàng)目,他的主要任務(wù)是清晰、驗(yàn)證和存儲(chǔ)數(shù)據(jù)。當(dāng)頁(yè)面被蜘蛛解析后,將被發(fā)送到項(xiàng)目管道,并經(jīng)過(guò)幾個(gè)特定的次序處理數(shù)據(jù)。
  • 下載器中間件(Downloader Middlewares),位于Scrapy引擎和下載器之間的鉤子框架,主要是處理Scrapy引擎與下載器之間的請(qǐng)求及響應(yīng)。
  • 蜘蛛中間件(Spider Middlewares),介于Scrapy引擎和蜘蛛之間的鉤子框架,主要工作是處理蜘蛛的響應(yīng)輸入和請(qǐng)求輸出。
  • 調(diào)度中間件(Scheduler Middlewares),介于Scrapy引擎和調(diào)度之間的中間件,從Scrapy引擎發(fā)送到調(diào)度的請(qǐng)求和響應(yīng)。

爬取流程

上圖綠線是數(shù)據(jù)流向,首先從初始URL開始,Scheduler會(huì)將其交給Downloader進(jìn)行下載,下載之后會(huì)交給Spider進(jìn)行分析,Spider分析出來(lái)的結(jié)果有兩種:一種是需要進(jìn)一步抓取的鏈接,例如之前分析的“下一頁(yè)”的鏈接,這些東西會(huì)被傳回Scheduler;另一種是需要保存的數(shù)據(jù),它們則被送到Item Pipeline那里,那是對(duì)數(shù)據(jù)進(jìn)行后期處理(詳細(xì)分析、過(guò)濾、存儲(chǔ)等)的地方。另外,在數(shù)據(jù)流動(dòng)的通道里還可以安裝各種中間件,進(jìn)行必要的處理。

數(shù)據(jù)流

Scrapy中的數(shù)據(jù)流由執(zhí)行引擎控制,其過(guò)程如下:

  1. 引擎打開一個(gè)網(wǎng)站(open a domain),找到處理該網(wǎng)站的Spider并向該spider請(qǐng)求第一個(gè)要爬取的URL(s)。
  2. 引擎從Spider中獲取到第一個(gè)要爬取的URL并在調(diào)度器(Scheduler)以Request調(diào)度。
  3. 引擎向調(diào)度器請(qǐng)求下一個(gè)要爬取的URL。
  4. 調(diào)度器返回下一個(gè)要爬取的URL給引擎,引擎將URL通過(guò)下載中間件(請(qǐng)求(request)方向)轉(zhuǎn)發(fā)給下載器(Downloader)。
  5. 一旦頁(yè)面下載完畢,下載器生成一個(gè)該頁(yè)面的Response,并將其通過(guò)下載中間件(返回(response)方向)發(fā)送給引擎。
  6. 引擎從下載器中接收到Response并通過(guò)Spider中間件(輸入方向)發(fā)送給Spider處理。
  7. Spider處理Response并返回爬取到的Item及(跟進(jìn)的)新的Request給引擎。
  8. 引擎將(Spider返回的)爬取到的Item給Item Pipeline,將(Spider返回的)Request給調(diào)度器。
  9. (從第二步)重復(fù)直到調(diào)度器中沒(méi)有更多地request,引擎關(guān)閉該網(wǎng)站。

Scrapy項(xiàng)目基本流程

默認(rèn)的Scrapy項(xiàng)目結(jié)構(gòu)

使用全局命令startproject創(chuàng)建項(xiàng)目,在project_name文件夾下創(chuàng)建一個(gè)名為project_name的Scrapy項(xiàng)目。

scrapy startproject myproject

雖然可以被修改,但所有的Scrapy項(xiàng)目默認(rèn)有類似于下邊的文件結(jié)構(gòu):

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

scrapy.cfg 存放的目錄被認(rèn)為是 項(xiàng)目的根目錄 。該文件中包含python模塊名的字段定義了項(xiàng)目的設(shè)置。

定義要抓取的數(shù)據(jù)

Item 是保存爬取到的數(shù)據(jù)的容器;其使用方法和python字典類似, 并且提供了額外保護(hù)機(jī)制來(lái)避免拼寫錯(cuò)誤導(dǎo)致的未定義字段錯(cuò)誤。
類似在ORM中做的一樣,您可以通過(guò)創(chuàng)建一個(gè) scrapy.Item 類, 并且定義類型為 scrapy.Field 的類屬性來(lái)定義一個(gè)Item。
首先根據(jù)需要從dmoz.org(DMOZ網(wǎng)站是一個(gè)著名的開放式分類目錄(Open DirectoryProject),由來(lái)自世界各地的志愿者共同維護(hù)與建設(shè)的最大的全球目錄社區(qū))獲取到的數(shù)據(jù)對(duì)item進(jìn)行建模。 我們需要從dmoz中獲取名字,url,以及網(wǎng)站的描述。 對(duì)此,在item中定義相應(yīng)的字段。編輯items.py 文件:

import scrapy

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

使用項(xiàng)目命令genspider創(chuàng)建Spider

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

在當(dāng)前項(xiàng)目中創(chuàng)建spider。
這僅僅是創(chuàng)建spider的一種快捷方法。該方法可以使用提前定義好的模板來(lái)生成spider。您也可以自己創(chuàng)建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數(shù)據(jù)的Spider

Spider是用戶編寫用于從單個(gè)網(wǎng)站(或者一些網(wǎng)站)爬取數(shù)據(jù)的類。
其包含了一個(gè)用于下載的初始URL,如何跟進(jìn)網(wǎng)頁(yè)中的鏈接以及如何分析頁(yè)面中的內(nèi)容, 提取生成 item 的方法。
為了創(chuàng)建一個(gè)Spider,您必須繼承 scrapy.Spider 類,且定義以下三個(gè)屬性:

  • name: 用于區(qū)別Spider。 該名字必須是唯一的,您不可以為不同的Spider設(shè)定相同的名字。
  • start_urls: 包含了Spider在啟動(dòng)時(shí)進(jìn)行爬取的url列表。 因此,第一個(gè)被獲取到的頁(yè)面將是其中之一。 后續(xù)的URL則從初始的URL獲取到的數(shù)據(jù)中提取。
  • parse() 是spider的一個(gè)方法。 被調(diào)用時(shí),每個(gè)初始URL完成下載后生成的 Response 對(duì)象將會(huì)作為唯一的參數(shù)傳遞給該函數(shù)。 該方法負(fù)責(zé)解析返回的數(shù)據(jù)(response data),提取數(shù)據(jù)(生成item)以及生成需要進(jìn)一步處理的URL的 Request 對(duì)象。
import scrapy

class DmozSpider(scrapy.spider.Spider):
    name = "dmoz"   #唯一標(biāo)識(shí),啟動(dòng)spider時(shí)即指定該名稱
    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)

進(jìn)行爬取

執(zhí)行項(xiàng)目命令crawl,啟動(dòng)Spider:

scrapy crawl dmoz

在這個(gè)過(guò)程中:
Scrapy為Spider的 start_urls 屬性中的每個(gè)URL創(chuàng)建了 scrapy.Request 對(duì)象,并將 parse 方法作為回調(diào)函數(shù)(callback)賦值給了Request。
Request對(duì)象經(jīng)過(guò)調(diào)度,執(zhí)行生成 scrapy.http.Response 對(duì)象并送回給spider parse() 方法。

通過(guò)選擇器提取數(shù)據(jù)

Selectors選擇器簡(jiǎn)介:
Scrapy提取數(shù)據(jù)有自己的一套機(jī)制。它們被稱作選擇器(seletors),因?yàn)樗麄兺ㄟ^(guò)特定的 XPath 或者 CSS 表達(dá)式來(lái)“選擇” HTML文件中的某個(gè)部分。
XPath 是一門用來(lái)在XML文件中選擇節(jié)點(diǎn)的語(yǔ)言,也可以用在HTML上。 CSS 是一門將HTML文檔樣式化的語(yǔ)言。選擇器由它定義,并與特定的HTML元素的樣式相關(guān)連。

XPath表達(dá)式的例子和含義:

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

提取數(shù)據(jù):
觀察HTML源碼并確定合適的XPath表達(dá)式。
在查看了網(wǎng)頁(yè)的源碼后,您會(huì)發(fā)現(xiàn)網(wǎng)站的信息是被包含在 第二個(gè) <ul> 元素中。
我們可以通過(guò)這段代碼選擇該頁(yè)面中網(wǎng)站列表里所有 <li> 元素:
response.xpath('//ul/li')

Item 對(duì)象是自定義的python字典。 您可以使用標(biāo)準(zhǔn)的字典語(yǔ)法來(lái)獲取到其每個(gè)字段的值。
一般來(lái)說(shuō),Spider將會(huì)將爬取到的數(shù)據(jù)以 Item 對(duì)象返回。所以為了將爬取的數(shù)據(jù)返回,我們最終的代碼將是:

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

現(xiàn)在對(duì)dmoz.org進(jìn)行爬取將會(huì)產(chǎn)生 DmozItem 對(duì)象。

保存數(shù)據(jù)

最簡(jiǎn)單存儲(chǔ)爬取的數(shù)據(jù)的方式是使用 Feed exports:

scrapy crawl dmoz -o items.json

該命令將采用 JSON 格式對(duì)爬取的數(shù)據(jù)進(jìn)行序列化,生成 items.json 文件。
如果需要對(duì)爬取到的item做更多更為復(fù)雜的操作,您可以編寫 Item Pipeline 。類似于我們?cè)趧?chuàng)建項(xiàng)目時(shí)對(duì)Item做的,用于您編寫自己的 tutorial/pipelines.py 也被創(chuàng)建。不過(guò)如果您僅僅想要保存item,您不需要實(shí)現(xiàn)任何的pipeline。

補(bǔ)充提示:Windows平臺(tái)安裝Scrapy的特別要求

Windows specific installation notes
Windows平臺(tái)下,安裝Scrapy之前首先要進(jìn)行以下操作:

  • 安裝OpenSSL
    Win32 OpenSSL page中下載安裝Visual C++ 2008 redistributables和對(duì)應(yīng)的OpenSSL安裝包,并把其可執(zhí)行文件目錄“*\openssl-win32\bin”加入到環(huán)境變量Path中
  • 安裝Scrapy依賴的二進(jìn)制包
    pywin32
    Twisted
    zope.interface
    lxml
    pyOpenSSL

小結(jié)

第一篇關(guān)于Scrapy的文章主要依據(jù)Scrapy 0.24的中文文檔,了解、熟悉Scrapy的使用和基本概念,在后面的相關(guān)文章中,將進(jìn)一步加入自己的思考和自行編寫的程序,期待能在這個(gè)過(guò)程中提高自己,也希望能對(duì)看到這些文章的讀者有用。

參考資料

Scrapy架構(gòu)概覽
初窺Scrapy
Scrapy入門教程
如何入門 Python 爬蟲

轉(zhuǎn)載請(qǐng)注明作者Jason Ding及其出處
Github博客主頁(yè)(http://jasonding1354.github.io/)
CSDN博客(http://blog.csdn.net/jasonding1354)
簡(jiǎn)書主頁(yè)(http://www.lxweimin.com/users/2bd9b48f6ea8/latest_articles)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • scrapy學(xué)習(xí)筆記(有示例版) 我的博客 scrapy學(xué)習(xí)筆記1.使用scrapy1.1創(chuàng)建工程1.2創(chuàng)建爬蟲模...
    陳思煜閱讀 12,776評(píng)論 4 46
  • scrapy是python最有名的爬蟲框架之一,可以很方便的進(jìn)行web抓取,并且提供了很強(qiáng)的定制型,這里記錄簡(jiǎn)單學(xué)...
    bomo閱讀 2,166評(píng)論 1 11
  • 這兩天摸索了下scrapy,剛看文檔的時(shí)候覺(jué)得有點(diǎn)生無(wú)可戀,scrapy框架個(gè)人還是覺(jué)得比較難懂的,需要學(xué)習(xí)的地方...
    Treehl閱讀 5,676評(píng)論 7 10
  • 眼下真是個(gè)“網(wǎng)紅”大爆發(fā)的年頭,一夜之間,保持平庸若許年的田宗琦陡然就紅了,并且紅到了一衣帶水的東瀛日本。作...
    奧寺閱讀 3,216評(píng)論 0 0
  • 開始挑戰(zhàn)啦~~~學(xué)著輸出,首先我要讀"跟TED學(xué)表達(dá)",這本書有很多TED的演講和演講時(shí)該注意的細(xì)節(jié),從表達(dá)情感,...
    全欣全歷閱讀 186評(píng)論 0 0