Spider類定義瞭如何爬取某個網站。包括了爬取的動做(例如:是否跟進連接)以及如何從網頁的內容中提取結構化數據(爬取item)。簡而言之,Spider就是你定義爬取的動做及分析某個網頁(或者是有些網頁)的地方。html
對spider來講,爬取的循環相似以下:node
以初始的URL初始化Request,並設置回調函數。當該request下載完畢並返回時,將生成response,並做爲參數傳給該回調函數。spider中初始的request是經過調用start_requests() 來獲取。start_requests() 讀取start_urls中的URL,並以parse爲回調函數生成 Request。正則表達式
在回調函數內分析返回的(網頁)內容,返回 Item 對象、dict、 Request 或者一個包括三者的可迭代容器。 返回的Request對象以後會通過Scrapy處理,下載相應的內容,並調用設置的callback函數(函數可相同)。數據庫
在回調函數內,您可使用 選擇器(Selectors) (您也可使用BeautifulSoup, lxml 或者您想用的任何解析器) 來分析網頁內容,並根據分析的數據生成item。dom
最後,由spider返回的item將被存到數據庫(由某些 Item Pipeline 處理)或使用 Feed exports 存入到文件中。scrapy
scrapy爲咱們提供了以下的一些spider類來應對不一樣的爬取需求。ide
http://www.example.com/123.html
, http://www.example.com/456.html
博客類的網站一般會這樣,咱們能夠直接使用這個類提供的Rule來進行網址匹配。固然咱們也能夠實現本身的spider。這裏咱們着重學習前面兩種,也是很是經常使用的兩種。函數
class scrapy.spiders.Spider
在這以前,咱們寫的爬蟲中,其實已經用到了這個類,咱們自定義的spider就是繼承自該類,如今咱們詳細的瞭解該類的一些經常使用的屬性和方法,具體的詳盡的信息能夠參照官方文檔。post
www.baidu.com
咱們的name就能夠爲baidu
,簡單明瞭。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
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進行後續的處理。
class scrapy.spiders.CrawlSpider
在爬取一些特殊類型的網站時,好比一些博客類網站,其網頁的連接都會有一些特殊的形式,簡單的例子,博客園的博客內容,http://www.cnblogs.com/cnkai/p/7397421.html
,http://www.cnblogs.com/cnkai/p/7396835.html
好比咱們想爬取個人博客內容,會發現,除了最後的幾個數字不一樣,其餘的內容是相同的,所以,咱們就能夠經過這個類來進行自動抓取類似的連接,而無需咱們本身定義。
CrawlSpider類定義了以下的屬性和方法。
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 對象。 其定義瞭如何從爬取到的頁面提取連接。
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.Spider
和scrapy.CrawlSpider
兩個類,這兩個也是咱們用的頻度比較高的兩個類,這兩個須要咱們重點的掌握,其餘的幾個這裏並無詳細的解釋,有興趣的能夠去查閱scrapy官方文檔,或者在之後須要的時候去查閱也能夠。