Scrapy學習篇(五)之Spiders

Spiders

Spider類定義瞭如何爬取某個網站。包括了爬取的動做(例如:是否跟進連接)以及如何從網頁的內容中提取結構化數據(爬取item)。簡而言之,Spider就是你定義爬取的動做及分析某個網頁(或者是有些網頁)的地方。html

對spider來講,爬取的循環相似以下:node

  1. 以初始的URL初始化Request,並設置回調函數。當該request下載完畢並返回時,將生成response,並做爲參數傳給該回調函數。spider中初始的request是經過調用start_requests() 來獲取。start_requests() 讀取start_urls中的URL,並以parse爲回調函數生成 Request。正則表達式

  2. 在回調函數內分析返回的(網頁)內容,返回 Item 對象、dict、 Request 或者一個包括三者的可迭代容器。 返回的Request對象以後會通過Scrapy處理,下載相應的內容,並調用設置的callback函數(函數可相同)。數據庫

  3. 在回調函數內,您可使用 選擇器(Selectors) (您也可使用BeautifulSoup, lxml 或者您想用的任何解析器) 來分析網頁內容,並根據分析的數據生成item。dom

  4. 最後,由spider返回的item將被存到數據庫(由某些 Item Pipeline 處理)或使用 Feed exports 存入到文件中。scrapy

scrapy爲咱們提供了以下的一些spider類來應對不一樣的爬取需求。ide

  • scrapy.spiders.Spider
    Spider是最簡單的spider。每一個其餘的spider必須繼承自該類(包括Scrapy自帶其餘spider以及你本身編寫的spider)。Spider僅僅提供了 start_requests()的默認實現,讀取並請求spider屬性中的 start_urls, 並根據返回的結果(resulting responses)調用spider的 parse 方法。
  • scrapy.spiders.CrawlSpider
    爬取通常網站經常使用的spider。其定義了一些規則(rule)來提供跟進link的方便的機制。好比一些網站的url一般是這樣的http://www.example.com/123.html, http://www.example.com/456.html 博客類的網站一般會這樣,咱們能夠直接使用這個類提供的Rule來進行網址匹配。固然咱們也能夠實現本身的spider。
  • scrapy.spiders.XMLFeedSpider
    XMLFeedSpider被設計用於經過迭代各個節點來分析XML源(XML feed)。 迭代器能夠從 iternodes , xml , html 選擇。 鑑於 xml 以及 html 迭代器須要先讀取全部DOM再分析而引發的性能問題, 通常仍是推薦使用 iternodes 。 不過使用 html 做爲迭代器能有效應對錯誤的XML。
  • scrapy.spiders.CSVFeedSpider
    該spider除了其按行遍歷而不是節點以外其餘和XMLFeedSpider十分相似。 而其在每次迭代時調用的是 parse_row() 。
  • scrapy.spiders.SitemapSpider
    SitemapSpider使您爬取網站時能夠經過 Sitemaps 來發現爬取的URL。其支持嵌套的sitemap,並能從 robots.txt 中獲取sitemap的url。

這裏咱們着重學習前面兩種,也是很是經常使用的兩種。函數

scrapy.Spider

class scrapy.spiders.Spider
在這以前,咱們寫的爬蟲中,其實已經用到了這個類,咱們自定義的spider就是繼承自該類,如今咱們詳細的瞭解該類的一些經常使用的屬性和方法,具體的詳盡的信息能夠參照官方文檔。post

  • name
    定義spider名字的字符串(string)。spider的名字定義了Scrapy如何定位(並初始化)spider,因此其必須是惟一的。name是spider最重要的屬性,並且必須。
    通常就是以網站的URL去掉先後綴來命名,如www.baidu.com咱們的name就能夠爲baidu,簡單明瞭。
  • allowed_domains
    可選。包含了spider容許爬取的域名(domain)列表(list)。 當 OffsiteMiddleware 啓用時, 域名不在列表中的URL不會被跟進。
  • start_urls
    URL列表。當沒有制定特定的URL時,spider將從該列表中開始進行爬取。 所以,第一個被獲取到的頁面的URL將是該列表之一。 後續的URL將會從獲取到的數據中提取。
  • start_requests()
    該方法必須返回一個可迭代對象(iterable)。該對象包含了spider用於爬取的第一個Request。該方法僅僅會被Scrapy調用一次,能夠將其實現爲生成器。
    該方法的默認實現是使用 start_urls 的url生成Request。咱們能夠重寫該方法來實現定製。好比咱們想要一開始就實現一個post請求,經過默認的方法可定是不行的。所以咱們重寫該方法以下。性能

    class MySpider(scrapy.Spider):
        name = 'myname'
    
        def start_requests(self):
            return [scrapy.FormRequest("http://www.example.com/login",
                                       formdata={'user': 'john', 'pass': 'secret'},
                                       callback=self.logged_in)]
    
        def logged_in(self, response):
            print('登錄成功')
            pass
  • parse(response)
    當response沒有指定回調函數時,該方法是Scrapy處理下載的response的默認方法。parse 負責處理response並返回處理的數據以及(/或)跟進的URL。
    該方法及其餘的Request回調函數必須返回一個包含 Request、dict 或 Item 的可迭代的對象。簡單的來講,所謂的回調函數,其實就是告訴spider,在拿到了網站的response之後,交給誰來進行處理後面的頁面的解析工做。
  • closed(reason)
    當spider關閉時,該函數被調用。

經常使用的Spider的屬性和方法就是這些,下面是一個綜合的例子。

import scrapy
from myproject.items import MyItem

class MySpider(scrapy.Spider):
    name = 'cnblog'
    allowed_domains = ['cnblogs.com']

    start_urls = ['http://www.cnblogs.com.com/123.html',
                  'http://www.cnblogs.com.com/234.html', 
                  'http://www.cnblogs.com.com/345.html'
                  ]
                  
    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        for h3 in response.xpath('//h3').extract():
            item = MyItem()
            item['title'] = h3
            yield item

        for url in response.xpath('//a/@href').extract():
            yield scrapy.Request(url, callback=self.parse)

請注意看,咱們能夠在start_requests()方法裏面請求多個URL,這會造成一個請求隊列,而且可使用一樣的解析方法對response進行解析,parse()方法的返回結果能夠也僅能夠有兩種,官方文檔上面說明是三種,其實item和字典咱們算作一種,兩種返回值的例子都包含在上面,一種是item或者說是字典,scrapy會將item交給item pipeline去進行後續的處理,包括數據的清洗,存儲;另外一種是Request,此時scrapy會將這個請求放入調度器請求隊列,後續會對其進行請求解析。scrapy的引擎也是經過返回的兩種類型來區別是交給pipeline仍是scheduler進行後續的處理。

scrapy.CrawlSpider

class scrapy.spiders.CrawlSpider
在爬取一些特殊類型的網站時,好比一些博客類網站,其網頁的連接都會有一些特殊的形式,簡單的例子,博客園的博客內容,http://www.cnblogs.com/cnkai/p/7397421.html,http://www.cnblogs.com/cnkai/p/7396835.html好比咱們想爬取個人博客內容,會發現,除了最後的幾個數字不一樣,其餘的內容是相同的,所以,咱們就能夠經過這個類來進行自動抓取類似的連接,而無需咱們本身定義。
CrawlSpider類定義了以下的屬性和方法。

  • rules
    一個包含一個(或多個) Rule 對象的集合(list)。 每一個 Rule 對爬取網站的動做定義了特定表現。 Rule對象在下邊會介紹。 若是多個rule匹配了相同的連接,則根據他們在本屬性中被定義的順序,第一個會被使用。
  • parse_start_url(response)
    當start_url的請求返回時,該方法被調用。 該方法分析最初的返回值並必須返回一個 Item 對象或者 一個 Request 對象或者 一個可迭代的包含兩者對象。

CrawlSpider須要配合scrapy.spiders.Rule類來實現定義規則
下面介紹scrapy.spiders.Rule
class scrapy.spiders.Rule(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)

  • link_extractor
    這是一個 Link Extractor 對象。 其定義瞭如何從爬取到的頁面提取連接。

  • callback
    這是一個callable或string(該spider中同名的函數將會被調用)。 從link_extractor中每獲取到連接時將會調用該函數。該回調函數接受一個response做爲其第一個參數, 並返回一個包含 Item 以及(或) Request 對象(或者這二者的子類)的列表(list)
  • cb_kwargs
    包含傳遞給回調函數的參數(keyword argument)的字典。
  • follow
    是一個布爾(boolean)值,指定了根據該規則從response提取的連接是否須要跟進。 若是 callback 爲None, follow 默認設置爲 True ,不然默認爲 False 。
  • process_links
    是一個callable或string(該spider中同名的函數將會被調用)。 從link_extractor中獲取到連接列表時將會調用該函數。該方法主要用來過濾。
  • process_request
    是一個callable或string(該spider中同名的函數將會被調用)。 該規則提取到每一個request時都會調用該函數。該函數必須返回一個request或者None。 (用來過濾request)

下面是一個詳細的樣例

import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor

class MySpider(CrawlSpider):
    name = 'cnblog'
    allowed_domains = []
    start_urls = ['http://www.cnblogs.com']

    rules = (
        Rule(LinkExtractor(allow=('http://www.cnblogs.com/\w+/p/\d+.html', )), callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        print(response.url)

簡單的解釋:
rules()中的allow=('http://www.cnblogs.com/\w+/p/\d+.html', )表示咱們須要匹配的格式,其中包含了正則表達式,\w+表示匹配任意的字母數字下劃線漢字至少一次,\d+表示匹配任意的數字至少一次,callback設置回調函數,follow=True表示跟進response裏面的連接,最終的結果就是提取出全部的知足要求的鏈接,並打印出來,這個數量會很龐大,若是你的爬蟲沒有被ban的話,這裏我簡單的運行一下,能夠看到下面的連接被打印了出來。且這些連接是知足咱們要求的格式。

總結

這一節主要是學習了scrapy的Spiders類,着重學習了scrapy.Spiderscrapy.CrawlSpider兩個類,這兩個也是咱們用的頻度比較高的兩個類,這兩個須要咱們重點的掌握,其餘的幾個這裏並無詳細的解釋,有興趣的能夠去查閱scrapy官方文檔,或者在之後須要的時候去查閱也能夠。

相關文章
相關標籤/搜索