本文通過(guò)示例簡(jiǎn)要介紹一下使用Scrapy抓取網(wǎng)站內(nèi)容的基本方法和流程。
繼續(xù)閱讀之前請(qǐng)確保已安裝了scrapy。
基本安裝方法為:pip install scrapy
我們已經(jīng)在之前的文章中初步介紹了scrapy,本文是前文的進(jìn)一步拓展。
本文主要包含如下幾部分:
1,創(chuàng)建一個(gè)scrapy項(xiàng)目
2,編寫(xiě)一個(gè)爬蟲(chóng)(或蜘蛛spider,本文中含義相同)類用于爬取網(wǎng)站頁(yè)面并提取數(shù)據(jù)
3,使用命令行導(dǎo)出爬到的數(shù)據(jù)
4,遞歸地爬取子頁(yè)面
5,了解并使用spider支持的參數(shù)
我們測(cè)試的網(wǎng)站為quotes.toscrape.com,這是一個(gè)收錄名人警句的站點(diǎn)。Let's go!
創(chuàng)建爬蟲(chóng)項(xiàng)目
Scrapy將爬蟲(chóng)代碼各模塊及配置組織為一個(gè)項(xiàng)目。Scrapy安裝成功后,你可以在shell中使用如下命令創(chuàng)建一個(gè)新的項(xiàng)目:
scrapy startproject tutorial
這將會(huì)創(chuàng)建一個(gè)tutorial目錄,該目錄的文件結(jié)構(gòu)如下所示:

編寫(xiě)蜘蛛類
Spiders是Scrapy中需要定義的實(shí)現(xiàn)爬取功能的類。
每個(gè)spider繼承自Spider基類。
spider主要定義了一些起始url,并負(fù)責(zé)解析web頁(yè)面元素,從中提前所需數(shù)據(jù)。
也可以產(chǎn)生新的url訪問(wèn)請(qǐng)求。
下邊這段代碼就是我們所定義的spider,將其保存為quotes_spider.py,放在項(xiàng)目的tutorial/spiders/目錄下。
import scrapy
class QuotesSpider(scrapy.Spider):
????name = "quotes"
????def start_requests(self):
????????urls = [ 'http://quotes.toscrape.com/page/1/', 'http://quotes.toscrape.com/page/2/', ]
????????for url in urls:
????????????yield scrapy.Request(url=url, callback=self.parse)
????def parse(self, response):
????????page = response.url.split("/")[-2]
????????filename = 'quotes-%s.html' % page
????????with open(filename, 'wb') as f:
????????????f.write(response.body)
????????self.log('Saved file %s' % filename)?
在我們的代碼中,QuotesSpider繼承自scrapy.Spider,并定義了一些屬性和方法:
name:用于在項(xiàng)目中唯一標(biāo)識(shí)一個(gè)spider。項(xiàng)目中可以包含多個(gè)spider,其name必須唯一。
start_requests():用于產(chǎn)生初始的url,爬蟲(chóng)從這些頁(yè)面開(kāi)始爬行。
????????這個(gè)函數(shù)需要返回一個(gè)包含Request對(duì)象的iterable,可以是一個(gè)列表(list)或者一個(gè)生成器(generator)。我們的例子中返回的是一個(gè)生成器。
parse():是一個(gè)回調(diào)函數(shù),用于解析訪問(wèn)url得到的頁(yè)面.
????參數(shù)response包含了頁(yè)面的詳細(xì)內(nèi)容,并提供了諸多從頁(yè)面中提取數(shù)據(jù)的方法。
????我們通常在parse中將提取的數(shù)據(jù)封裝為dict,查找新的url,并為這些url產(chǎn)生新的Request,以繼續(xù)爬取。
運(yùn)行蜘蛛
Spider定義好了之后,我們可以在項(xiàng)目的頂層目錄,即最頂層的tutorial,執(zhí)行如下命令來(lái)運(yùn)行這個(gè)spider:
scrapy crawl quotes
這個(gè)命令會(huì)在項(xiàng)目的spiders目錄中查找并運(yùn)行name為quotes的Spider.
它會(huì)向quotes.toscrape.com這個(gè)網(wǎng)站發(fā)起HTTP請(qǐng)求,并獲取如下響應(yīng):
...
2016-12-16 21:24:05 [scrapy.core.engine] INFO: Spider opened
2016-12-16 21:24:05 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2016-12-16 21:24:05 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (404) <GET http://quotes.toscrape.com/robots.txt> (referer: None)
2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/1/> (referer: None)
2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://quotes.toscrape.com/page/2/> (referer: None)
2016-12-16 21:24:05 [quotes] DEBUG: Saved file quotes-1.html
2016-12-16 21:24:05 [quotes] DEBUG: Saved file quotes-2.html
2016-12-16 21:24:05 [scrapy.core.engine] INFO: Closing spider (finished)
...
這些輸出告訴我們,爬蟲(chóng)已成功訪問(wèn)了一些url,并將其內(nèi)容保存為html文件。
這正是我們?cè)趐arse()中定義的功能。
底層執(zhí)行邏輯
Scrapy統(tǒng)一調(diào)度由spider的start_requests()方法產(chǎn)生的Request。
每當(dāng)Request請(qǐng)求完成之后,Scrapy便創(chuàng)建一個(gè)與之相應(yīng)的Response,并將這個(gè)Response作為參數(shù)傳遞給Request關(guān)聯(lián)的回調(diào)函數(shù)(callback),由回調(diào)函數(shù)來(lái)解析這個(gè)web響應(yīng)頁(yè)面,從中提取數(shù)據(jù),或發(fā)起新的http請(qǐng)求。
這個(gè)流程由Scrapy內(nèi)部實(shí)現(xiàn),我們只需要在spider中定義好需要訪問(wèn)的url,以及如何處理頁(yè)面響應(yīng)就行了。
start_requests的簡(jiǎn)寫(xiě)
除了使用start_requests()產(chǎn)生請(qǐng)求對(duì)象Request之外,我們還可以使用一個(gè)簡(jiǎn)單的方法來(lái)生成Request。
那就是在spider中定義一個(gè)start_urls列表,將開(kāi)始時(shí)需要訪問(wèn)的url放置其中。如下所示:
import scrapy
class QuotesSpider(scrapy.Spider):
????name="quotes"
????start_urls=['http://quotes.toscrape.com/page/1/','http://quotes.toscrape.com/page/2/',]
????def parse(self,response):
????????page=response.url.split("/")[-2]
????????filename='quotes-%s.html' % page
????????with open(filename,'wb') as f:
????????????f.write(response.body)
實(shí)際上,spider仍然會(huì)去調(diào)用默認(rèn)的start_requests()方法,在這個(gè)方法里讀取start_urls,并生成Request。
這個(gè)簡(jiǎn)版的請(qǐng)求初始化方法也沒(méi)有顯式地將回調(diào)函數(shù)parse和Request對(duì)象關(guān)聯(lián)。
很容易想到,scrapy內(nèi)部為我們做了關(guān)聯(lián):parse是scrapy默認(rèn)的Request回調(diào)函數(shù)。
數(shù)據(jù)提取
我們得到頁(yè)面響應(yīng)后,最重要的工作就是如何從中提取數(shù)據(jù)。
這里先介紹一下Scrapy shell這個(gè)工具.
它是scrapy內(nèi)置的一個(gè)調(diào)試器,可以方便地拉取一個(gè)頁(yè)面,測(cè)試數(shù)據(jù)提取方法是否可行。
scrapy shell的執(zhí)行方法為:
scrapy shell 'http://quotes.toscrape.com/page/1/'
直接在后面加上要調(diào)試頁(yè)面的url就行了,注意需要用引號(hào)包括url。
回車(chē)后會(huì)得到如下輸出:

我們接下來(lái)就可以在shell中測(cè)試如何提取頁(yè)面元素了。
可以使用Response.css()方法來(lái)選取頁(yè)面元素:
>>> response.css('title')
[<Selector xpath='descendant-or-self::title' data='<title>Quotes to Scrape</title>'>]
css()返回結(jié)果是一個(gè)selector列表,每個(gè)selector都是對(duì)頁(yè)面元素是封裝,它提供了一些用于獲取元素?cái)?shù)據(jù)的方法。
我們可以通過(guò)如下方法獲取html title的內(nèi)容:
>>> response.css('title::text').getall()
['Quotes to Scrape']
這里,我們?cè)赾ss查詢中向title添加了::text,其含義是只獲取<title>標(biāo)簽中的文本,而不是整個(gè)<title>標(biāo)簽:
>>> response.css('title').getall()
['<title>Quotes to Scrape</title>']
不加::text就是上邊這個(gè)效果。
另外,getall()返回的是一個(gè)列表,這是由于通過(guò)css選取的元素可能是多個(gè)。
如果只想獲取第一個(gè),可以用get():
>>> response.css('title::text').get()
'Quotes to Scrape'
還可以通過(guò)下標(biāo)引用css返回的某個(gè)selector:
>>> response.css('title::text')[0].get()
'Quotes to Scrape'
如果css選擇器沒(méi)有匹配到頁(yè)面元素,get()會(huì)返回None。
除了get()和getall(),我們還可以使用re()來(lái)實(shí)現(xiàn)正則提?。?/p>
>>> response.css('title::text').re(r'Quotes.*')
['Quotes to Scrape']
>>> response.css('title::text').re(r'Q\w+')
['Quotes']
>>> response.css('title::text').re(r'(\w+) to (\w+)')
['Quotes', 'Scrape']
所以,數(shù)據(jù)提取的重點(diǎn)就在于如何找到合適的css選擇器。
常用的方法是借助于瀏覽器的開(kāi)發(fā)者工具進(jìn)行分析。在chrome中可以通過(guò)F12打開(kāi)開(kāi)發(fā)者工具。
XPath簡(jiǎn)介
除了css,Scrapy還支持使用XPath來(lái)選取頁(yè)面元素
>>> response.xpath('//title')
[<Selector xpath='//title' data='<title>Quotes to Scrape</title>'>]
>>> response.xpath('//title/text()').get()
'Quotes to Scrape'
XPath表達(dá)式功能強(qiáng)大,它是Scrapy中選擇器實(shí)現(xiàn)的基礎(chǔ),css在scrapy底層也會(huì)轉(zhuǎn)換為XPath。
相較于css選擇器,XPath不僅能解析頁(yè)面結(jié)構(gòu),還可以讀取元素內(nèi)容。
可以通過(guò)XPath方便地獲取到頁(yè)面上“下一頁(yè)”這樣的url,很適于爬蟲(chóng)這種場(chǎng)景。
我們會(huì)在后續(xù)的Scrapy選取器相關(guān)內(nèi)容進(jìn)一步了解其用法,當(dāng)然網(wǎng)上也有很多這方面的資料可供查閱。
提取警句和作者
通過(guò)上邊的介紹,我們已經(jīng)初步了解了如何選取頁(yè)面元素,如何提取數(shù)據(jù)。
接下來(lái)繼續(xù)完善這個(gè)spider,我們將從測(cè)試站點(diǎn)頁(yè)面獲取更多信息。
打開(kāi)http://quotes.toscrape.com/,在開(kāi)發(fā)者工具中查看單條警句的源碼如下所示:
<divclass="quote">
????<spanclass="text">“The world as we have created it is a process of our? ? thinking. It cannot be changed without changing our thinking.”</span>
<span>by<smallclass="author">Albert Einstein</small><ahref="/author/Albert-Einstein">(about)</a></span>
<divclass="tags">Tags:
????<aclass="tag"href="/tag/change/page/1/">change</a>
????<aclass="tag"href="/tag/deep-thoughts/page/1/">deep-thoughts</a>????
????<aclass="tag"href="/tag/thinking/page/1/">thinking</a>
????<aclass="tag"href="/tag/world/page/1/">world</a>
????</div>
</div>
現(xiàn)在我們打開(kāi)scrapy shell來(lái)測(cè)試一下如何提取其中的元素。
$ scrapy shell 'http://quotes.toscrape.com'
shell獲取到頁(yè)面內(nèi)容后,我們通過(guò)css選取器可以得到頁(yè)面中的警句列表:
>>> response.css("div.quote")
[<Selector xpath="descendant-or-self::div[@class and contains(concat(' ', normalize-space(@class), ' '), ' quote ')]" data='<div class="quote" itemscope itemtype...'>,
<Selector xpath="descendant-or-self::div[@class and contains(concat(' ', normalize-space(@class), ' '), ' quote ')]" data='<div class="quote" itemscope itemtype...'>,
...]
由于頁(yè)面中有很多警句,這個(gè)結(jié)果是一個(gè)包含很多selector對(duì)象的列表。
我們可以通過(guò)索引獲取第一個(gè)selector,然后調(diào)用其中的方法得到元素內(nèi)容。
>>> quote=response.css("div.quote")[0]
通過(guò)quote對(duì)象就可以提取其中的文字、作者和標(biāo)簽等內(nèi)容,這同樣是使用css選擇器來(lái)實(shí)現(xiàn)的。
>>> text=quote.css("span.text::text").get()
>>> text'“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”'
>>> author=quote.css("small.author::text").get()
>>> author'Albert Einstein'
頁(yè)面上每個(gè)警句都打了若干標(biāo)簽,我們可以通過(guò)getall()來(lái)獲取這些標(biāo)簽字符串:
>>> tags=quote.css("div.tags a.tag::text").getall()
>>> tags['change', 'deep-thoughts', 'thinking', 'world']
既然我們已經(jīng)獲取了第一個(gè)quote的內(nèi)容,我們同樣可以通過(guò)循環(huán)來(lái)獲取當(dāng)前頁(yè)面所有quote的內(nèi)容:
>>> for quote in response.css("div.quote"):
????????????text=quote.css("span.text::text").get()
? ? ? ? ????author=quote.css("small.author::text").get()
? ? ? ? ? ? tags=quote.css("div.tags a.tag::text").getall()
? ? ? ? ? ? print(dict(text=text,author=author,tags=tags))
>>>
{'text': '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”', 'author': 'Albert Einstein', 'tags': ['change', 'deep-thoughts', 'thinking', 'world']}
{'text': '“It is our choices, Harry, that show what we truly are, far more than our abilities.”', 'author': 'J.K. Rowling', 'tags': ['abilities', 'choices']}...
在spider代碼中提取數(shù)據(jù)
在了解了如何使用scrapy shell提取頁(yè)面元素后,我們重新回到之前編寫(xiě)的spider代碼。
到目前為止,我們的spider僅僅將頁(yè)面響應(yīng)Response.body一股腦保存到了HTML文件中。我們需要對(duì)它進(jìn)行完善,以保存有意義的數(shù)據(jù)。
Scrapy Spider通常會(huì)在解析頁(yè)面之后返回一些包含數(shù)據(jù)的dict,這些dict可用于后續(xù)的處理流程。
我們可以通過(guò)在回調(diào)函數(shù)中使用yield來(lái)返回這些dict。
import scrapy
class QuotesSpider(scrapy.Spider):
????name="quotes"
????start_urls=['http://quotes.toscrape.com/page/1/','http://quotes.toscrape.com/page/2/',]
????def parse(self,response):
????????for quote in response.css('div.quote'):
????????????yield{'text':quote.css('span.text::text').get(),
????????????????'author':quote.css('small.author::text').get(),
????????????????'tags':quote.css('div.tags a.tag::text').getall(),}
運(yùn)行這個(gè)spider,會(huì)在日志中得到如下輸出:
2016-09-1918:57:19 [scrapy.core.scraper] DEBUG: Scraped from <200http://quotes.toscrape.com/page/1/>? {'tags':['life','love'],'author':'André Gide','text':'“It is better to be hated for what you are than to be loved for what you are not.”'}
2016-09-1918:57:19 [scrapy.core.scraper] DEBUG: Scraped from <200http://quotes.toscrape.com/page/1/>? {'tags':['edison','failure','inspirational','paraphrased'],'author':'Thomas A. Edison','text':"“I have not failed. I've just found 10,000 ways that won't work.”"}
存儲(chǔ)數(shù)據(jù)
Scrapy支持將數(shù)據(jù)存儲(chǔ)到各種存儲(chǔ)系統(tǒng)中,最簡(jiǎn)單的方法是將其保存文件文件。可通過(guò)如下命令實(shí)現(xiàn):
scrapy crawl quotes -o quotes.json
這會(huì)以JSON格式保存提取的數(shù)據(jù),并且是以append的方式寫(xiě)入文件。
如果同時(shí)執(zhí)行多次這個(gè)命令,寫(xiě)入到相同文件的數(shù)據(jù)會(huì)相互覆蓋,造成數(shù)據(jù)破壞!
Scrapy提供了JSON Lines的寫(xiě)入方式,可以避免上述覆蓋的情況。
scrapy crawl quotes -o quotes.jl
這種格式的文件是按行來(lái)保存JSON對(duì)象的。
除了JSON,Scrapy還支持csv、xml等存儲(chǔ)格式。
如果存儲(chǔ)邏輯比較復(fù)雜,還可以通過(guò)scrapy提供的Item流水線(pipeline)來(lái)拆解存儲(chǔ)過(guò)程,將每個(gè)存儲(chǔ)步驟封裝為一個(gè)pipeline,由scrapy引擎來(lái)調(diào)度執(zhí)行。這方面的內(nèi)容會(huì)在后續(xù)文章中一起學(xué)習(xí)。
追蹤鏈接
目前我們實(shí)現(xiàn)的spider只從兩個(gè)頁(yè)面獲取數(shù)據(jù),如果想要自動(dòng)獲取整個(gè)網(wǎng)站的數(shù)據(jù),我們還需要提取頁(yè)面上的其他鏈接,產(chǎn)生新的爬取請(qǐng)求。
我們了解一下跟蹤頁(yè)面鏈接的方法。
首先要在頁(yè)面中找到要進(jìn)一步爬取的鏈接。
在測(cè)試網(wǎng)站頁(yè)面上,可以看到列表右下有一個(gè)“Next”鏈接,其HTML源碼為:
<ulclass="pager">
????<liclass="next">
????????<ahref="/page/2/">Next<spanaria-hidden="true">→</span></a>
????</li>
</ul>
使用scrapy shell測(cè)試一下如何提取這個(gè)鏈接:
>>> response.css('li.next a').get()
'<a href="/page/2/">Next <span aria-hidden="true">→</span></a>'
我們使用css('li.next a')得到了這個(gè)鏈接的selector,并通過(guò)get()得到了整個(gè)鏈接元素。
顯然這數(shù)據(jù)有點(diǎn)冗余,我們需要的是鏈接的href屬性值。
這個(gè)值可以通過(guò)scrapy提供的css擴(kuò)展語(yǔ)法獲得:
>>> response.css('li.next a::attr(href)').get()
'/page/2/'
也可以通過(guò)訪問(wèn)selector的attrib屬性獲?。?/p>
>>> response.css('li.next a').attrib['href']
'/page/2/'
接下來(lái),我們將這個(gè)提取過(guò)程整合到spider代碼中,以實(shí)現(xiàn)遞歸跟蹤頁(yè)面鏈接。
import scrapy
class QuotesSpider(scrapy.Spider):
????name="quotes"
????start_urls=['http://quotes.toscrape.com/page/1/',]
????def parse(self,response):
????????for quote in response.css('div.quote'):
????????????yield{'text':quote.css('span.text::text').get(),
????????????????'author':quote.css('small.author::text').get(),
????????????????'tags':quote.css('div.tags a.tag::text').getall(),}
????????next_page=response.css('li.next a::attr(href)').get()
????????if next_page is not None:
????????????next_page=response.urljoin(next_page)
????????????yield scrapy.Request(next_page,callback=self.parse)
現(xiàn)在我們的初始url為第一頁(yè)。
parse()函數(shù)提取完第一頁(yè)上所有的警句之后,繼續(xù)查找頁(yè)面上的“Next”鏈接。
如果找到,就產(chǎn)生一個(gè)新的請(qǐng)求,并關(guān)聯(lián)自己為這個(gè)Request的回調(diào)函數(shù)。
這樣就可以遞歸地訪問(wèn)整個(gè)網(wǎng)站,直到最后一頁(yè)。
這就是Scrapy跟蹤頁(yè)面鏈接的機(jī)制:
用戶負(fù)責(zé)解析這些鏈接,通過(guò)yield產(chǎn)生新的請(qǐng)求Request,并給Request關(guān)聯(lián)一個(gè)處理函數(shù)callback。Scrapy負(fù)責(zé)調(diào)度這些Request,自動(dòng)發(fā)送請(qǐng)求,并通過(guò)callback處理響應(yīng)消息。
創(chuàng)建Requests的快捷方法
除了直接創(chuàng)建一個(gè)scrapy.Request對(duì)象,我們還可以使用response.follow來(lái)簡(jiǎn)化生成Request的方法。
import scrapy
class QuotesSpider(scrapy.Spider):
????name="quotes"
????start_urls=['http://quotes.toscrape.com/page/1/',]
????def parse(self,response):
????????for quote in response.css('div.quote'):
????????????yield{'text':quote.css('span.text::text').get(),
????????????????'author':quote.css('span small::text').get(),
????????????????'tags':quote.css('div.tags a.tag::text').getall(),}
????????next_page=response.css('li.next a::attr(href)').get()
????????if next_page is not None:
????????????yield response.follow(next_page,callback=self.parse)
follow可以直接通過(guò)相對(duì)路徑生成url,不需要再調(diào)用urljoin()。這和頁(yè)面上的href寫(xiě)法一致,很方便。
follow還支持直接傳入url對(duì)應(yīng)的selector,而不需調(diào)用get()提取url字符串。
for href in response.css('ul.pager a::attr(href)'):
????yield response.follow(href,callback=self.parse)
對(duì)<a>標(biāo)簽,還可以進(jìn)一步簡(jiǎn)化:
for a in response.css('ul.pager a'):
????yield response.follow(a,callback=self.parse)
這是因?yàn)閒ollow會(huì)自動(dòng)使用<a>的href屬性。
我們還可以使用follow_all從可迭代對(duì)象中批量創(chuàng)建Request:
#aonchors包含多個(gè)<a>選擇器
anchors=response.css('ul.pager a')
yield from response.follow_all(anchors,callback=self.parse)
follow_all也支持簡(jiǎn)化寫(xiě)法:
yield from response.follow_all(css='ul.pager a',callback=self.parse)
更多示例
我們?cè)倏匆粋€(gè)spider,其作用是獲取所有警句的作者信息。
import scrapy
class AuthorSpider(scrapy.Spider):
????name='author'
????start_urls=['http://quotes.toscrape.com/']
????def parse(self,response):
????????author_page_links=response.css('.author + a')
????????????yield from response.follow_all(author_page_links,self.parse_author)
????????pagination_links=response.css('li.next a')
????????yield from response.follow_all(pagination_links,self.parse)
????def parse_author(self,response):
????????def extract_with_css(query):
????????????return response.css(query).get(default='').strip()
????????yield{'name':extract_with_css('h3.author-title::text'),
????????????'birthdate':extract_with_css('.author-born-date::text'),
????????????'bio':extract_with_css('.author-description::text'),}
這個(gè)spider從測(cè)試站點(diǎn)主頁(yè)開(kāi)始爬取。
提取這個(gè)頁(yè)面上所有的author鏈接,并產(chǎn)生新的Request;提取頁(yè)面上的Next鏈接,產(chǎn)生對(duì)應(yīng)的Request。
通過(guò)parse_author提取作者信息。在parse_author中我們定義了一個(gè)helper函數(shù)供提取數(shù)據(jù)使用。
值得注意的是,某個(gè)作者可能有多條警句,而每條警句單獨(dú)包含了這個(gè)作者的標(biāo)簽。我們可能會(huì)提取多個(gè)相同作者的url。但實(shí)際上,Scrapy并不會(huì)對(duì)相同的url發(fā)起多次請(qǐng)求,它會(huì)自動(dòng)進(jìn)行去重處理,這在一定程度上會(huì)減輕爬蟲(chóng)對(duì)網(wǎng)站的壓力。
使用spider參數(shù)
我們可以通過(guò)scrapy命令行的-a選項(xiàng)來(lái)向spider傳遞一些參數(shù)。比如:
scrapy crawl quotes-oquotes-humor.json -a tag=humor
這里,-a之后,tag為參數(shù)名,humor為參數(shù)值。
這些參數(shù)會(huì)傳遞給spider的__init__方法,并成為spider的屬性。
我們可以在spider中獲取這些屬性,并根據(jù)其值處理不同的業(yè)務(wù)。
import scrapy
class QuotesSpider(scrapy.Spider):
????name="quotes"
????def start_requests(self):
????????url='http://quotes.toscrape.com/'
????????tag=getattr(self,'tag',None)
????????if tag is not None:
????????????url=url+'tag/'+tag
????????yield scrapy.Request(url,self.parse)
????def parse(self,response):
????????for quote in response.css('div.quote'):
????????yield{'text':quote.css('span.text::text').get(),
????????????'author':quote.css('small.author::text').get(),}
????????next_page=response.css('li.next a::attr(href)').get()
????????if next_page is not None:
????????????yield response.follow(next_page,self.parse)
在上邊的代碼中,如果啟動(dòng)時(shí)傳入tag參數(shù)(值為humor),我們就會(huì)在初始化url中追加“tag/humor”,這樣就只會(huì)爬取標(biāo)簽為humor的頁(yè)面:http://quotes.toscrape.com/tag/humor。
結(jié)語(yǔ)
本文“詳盡的”介紹了scrapy的基礎(chǔ)知識(shí),Scrapy還有跟多特性無(wú)法在一篇文章中全部介紹。
我們后續(xù)會(huì)繼續(xù)學(xué)習(xí)Scrapy的方方面面,并在實(shí)踐中不斷理解和掌握。
【歡迎關(guān)注RealPython,訪問(wèn)realpython.cn一起學(xué)Python】