Scrapy學習篇(五)之Spiders


Spiders

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

對spider來說,爬取的循環類似如下:

  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。

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

scrapy為我們提供了如下的一些spider類來應對不同的爬取需求。

  • 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就是繼承自該類,現在我們詳細的了解該類的一些常用的屬性和方法,具體的詳盡的信息可以參照官方文檔。

  • 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官方文檔,或者在以后需要的時候去查閱也可以。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM