Scrapy架構(gòu)概覽
要探究清楚Spider Middleware呻右,首先得對Scrapy框架的整體架構(gòu)有個大致的認(rèn)識肆捕,如下圖所示:
1己儒,組件(Components)
Scrapy 引擎(Engine)
引擎負(fù)責(zé)控制數(shù)據(jù)流在系統(tǒng)中所有組件中流動客峭,并在相應(yīng)動作發(fā)生時觸發(fā)事件示血。 詳細(xì)內(nèi)容查看下面的數(shù)據(jù)流(Data Flow)部分。
調(diào)度器(Scheduler)
調(diào)度器從引擎接受request并將他們?nèi)腙?duì)亚亲,以便之后引擎請求他們時提供給引擎。
下載器(Downloader)
下載器負(fù)責(zé)獲取頁面數(shù)據(jù)并提供給引擎腐缤,而后提供給spider捌归。
Spiders
Spider是Scrapy用戶編寫用于分析response并提取item(即獲取到的item)或額外跟進(jìn)的URL的類。 每個spider負(fù)責(zé)處理一個特定(或一些)網(wǎng)站岭粤,我們前面幾篇文章中惜索,通過Scrapy框架實(shí)現(xiàn)的爬蟲例子都是在Spiders這個組件中實(shí)現(xiàn)。 更多內(nèi)容請看 Spiders 剃浇。
管道(Item Pipeline)
Item Pipeline負(fù)責(zé)處理被spider提取出來的item巾兆。典型的處理有清理、 驗(yàn)證及持久化(例如存取到數(shù)據(jù)庫中)虎囚。 更多內(nèi)容查看 Item Pipeline 角塑。
下載器中間件(Downloader Middlewares)
下載器中間件是在引擎及下載器之間的特定鉤子(specific hook),處理Downloader傳遞給引擎的response淘讥,以及引擎?zhèn)鬟f給Downloader的request,(介于reuqest和response之間) 其提供了一個簡便的機(jī)制圃伶,通過插入自定義代碼來擴(kuò)展Scrapy功能。更多內(nèi)容請看 Downloader Middleware 。
Spider中間件(Spider Middlewares)
Spider中間件是在引擎及Spider之間的特定鉤子(specific hook)窒朋,處理spider的輸入(response)和輸出(items及requests)搀罢。 其提供了一個簡便的機(jī)制,通過插入自定義代碼來擴(kuò)展Scrapy功能侥猩。更多內(nèi)容請看 Spider Middleware 榔至。
2,數(shù)據(jù)流(Data flow)
Scrapy中的數(shù)據(jù)流由執(zhí)行引擎控制欺劳,其過程如下:
1唧取,引擎從Spiders中獲取到最初的要爬取的請求(Requests)。
2杰标,引擎安排請求(Requests)到調(diào)度器中兵怯,并向調(diào)度器請求下一個要爬取的請求(Requests)。
3腔剂,調(diào)度器返回下一個要爬取的請求(Requests)給引擎媒区。
4,引擎將上步中得到的請求(Requests)通過下載器中間件(Downloader Middlewares)發(fā)送給下載器(Downloader )掸犬,這個過程中下載器中間件(Downloader Middlewares)中的process_request()函數(shù)會被調(diào)用到袜漩。
5,一旦頁面下載完畢湾碎,下載器生成一個該頁面的Response宙攻,并將其通過下載中間件(Downloader Middlewares)發(fā)送給引擎,這個過程中下載器中間件(Downloader Middlewares)中的process_response()函數(shù)會被調(diào)用到介褥。
6座掘,引擎從下載器中得到上步中的Response并通過Spider中間件(Spider Middlewares)發(fā)送給Spider處理,這個過程中Spider中間件(Spider Middlewares)中的process_spider_input()函數(shù)會被調(diào)用到柔滔。
7溢陪,Spider處理Response并通過Spider中間件(Spider Middlewares)返回爬取到的Item及(跟進(jìn)的)新的Request給引擎,這個過程中Spider中間件(Spider Middlewares)的process_spider_output()函數(shù)會被調(diào)用到睛廊。
8形真,引擎將上步中Spider處理的其爬取到的Item給Item 管道(Pipeline),將Spider處理的Request發(fā)送給調(diào)度器超全,并向調(diào)度器請求可能存在的下一個要爬取的請求(Requests)咆霜。
9,(從第二步)重復(fù)直到調(diào)度器中沒有更多的請求(Requests)嘶朱。
二蛾坯,Spider中間件(Spider Middlewares)
Spider中間件是介入到Scrapy中的spider處理機(jī)制的鉤子框架,可以插入自定義功能來處理發(fā)送給 Spiders 的response疏遏,以及spider產(chǎn)生的item和request偿衰。
1挂疆,激活Spider中間件(Spider Middlewares)
要啟用Spider中間件(Spider Middlewares),可以將其加入到 SPIDER_MIDDLEWARES 設(shè)置中下翎。 該設(shè)置是一個字典缤言,鍵為中間件的路徑,值為中間件的順序(order)视事。
樣例:
SPIDER_MIDDLEWARES = {
'myproject.middlewares.CustomSpiderMiddleware': 543,
}
SPIDER_MIDDLEWARES 設(shè)置會與Scrapy定義的 SPIDER_MIDDLEWARES_BASE 設(shè)置合并(但不是覆蓋)胆萧, 而后根據(jù)順序(order)進(jìn)行排序,最后得到啟用中間件的有序列表: 第一個中間件是最靠近引擎的俐东,最后一個中間件是最靠近spider的跌穗。
關(guān)于如何分配中間件的順序請查看 SPIDER_MIDDLEWARES_BASE 設(shè)置,而后根據(jù)您想要放置中間件的位置選擇一個值虏辫。 由于每個中間件執(zhí)行不同的動作蚌吸,您的中間件可能會依賴于之前(或者之后)執(zhí)行的中間件,因此順序是很重要的砌庄。
如果您想禁止內(nèi)置的(在 SPIDER_MIDDLEWARES_BASE 中設(shè)置并默認(rèn)啟用的)中間件羹唠, 您必須在項(xiàng)目的 SPIDER_MIDDLEWARES設(shè)置中定義該中間件,并將其值賦為 None 娄昆。 例如佩微,如果您想要關(guān)閉off-site中間件:
SPIDER_MIDDLEWARES = {
'myproject.middlewares.CustomSpiderMiddleware': 543,
'scrapy.contrib.spidermiddleware.offsite.OffsiteMiddleware': None,
}
最后,請注意萌焰,有些中間件需要通過特定的設(shè)置來啟用哺眯。更多內(nèi)容請查看相關(guān)中間件文檔。
2扒俯,編寫自己的spider中間件
編寫spider中間件十分簡單奶卓。每個中間件組件是一個定義了以下一個或多個方法的Python類:
class scrapy.contrib.spidermiddleware.SpiderMiddleware
process_spider_input(response, spider)
當(dāng)response通過spider中間件時,該方法被調(diào)用撼玄,處理該response夺姑。
process_spider_input() 應(yīng)該返回 None 或者拋出一個異常(exception)。
如果其返回 None 互纯,Scrapy將會繼續(xù)處理該response瑟幕,調(diào)用所有其他的中間件直到spider處理該response磕蒲。
如果其拋出一個異常(exception)留潦,Scrapy將不會調(diào)用任何其他中間件的 process_spider_input() 方法,并調(diào)用request的errback辣往。 errback的輸出將會以另一個方向被重新輸入到中間件鏈中兔院,使用 process_spider_output() 方法來處理,當(dāng)其拋出異常時則帶調(diào)用process_spider_exception() 站削。
參數(shù):
response (Response 對象) – 被處理的response
spider (Spider 對象) – 該response對應(yīng)的spider
process_spider_output(response, result, spider)
當(dāng)Spider處理response返回result時坊萝,該方法被調(diào)用。
process_spider_output() 必須返回包含 Request 或 Item 對象的可迭代對象(iterable)。
參數(shù):
response (Response 對象) – 生成該輸出的response
result (包含 Request 或 Item 對象的可迭代對象(iterable)) – spider返回的result
spider (Spider 對象) – 其結(jié)果被處理的spider
process_spider_exception(response, exception, spider)
當(dāng)spider或(其他spider中間件的) process_spider_input() 拋出異常時十偶, 該方法被調(diào)用菩鲜。
process_spider_exception() 必須要么返回 None , 要么返回一個包含 Response 或 Item 對象的可迭代對象(iterable)惦积。
如果其返回 None 接校,Scrapy將繼續(xù)處理該異常,調(diào)用中間件鏈中的其他中間件的 process_spider_exception() 方法狮崩,直到所有中間件都被調(diào)用蛛勉,該異常到達(dá)引擎(異常將被記錄并被忽略)。
如果其返回一個可迭代對象睦柴,則中間件鏈的 process_spider_output() 方法被調(diào)用诽凌, 其他的 process_spider_exception() 將不會被調(diào)用。
參數(shù):
response (Response 對象) – 異常被拋出時被處理的response
exception (Exception 對象) – 被跑出的異常
spider (Spider 對象) – 拋出該異常的spider
process_start_requests(start_requests, spider)
0.15 新版功能.
該方法以spider 啟動的request為參數(shù)被調(diào)用坦敌,執(zhí)行的過程類似于 process_spider_output() 侣诵,只不過其沒有相關(guān)聯(lián)的response并且必須返回request(不是item)。
其接受一個可迭代的對象(start_requests 參數(shù))且必須返回另一個包含 Request 對象的可迭代對象恬试。
注解
當(dāng)在您的spider中間件實(shí)現(xiàn)該方法時窝趣, 您必須返回一個可迭代對象(類似于參數(shù)start_requests)且不要遍歷所有的 start_requests。 該迭代器會很大(甚至是無限)训柴,進(jìn)而導(dǎo)致內(nèi)存溢出哑舒。 Scrapy引擎在其具有能力處理start request時將會拉起request, 因此start request迭代器會變得無限幻馁,而由其他參數(shù)來停止spider( 例如時間限制或者item/page記數(shù))洗鸵。
參數(shù):
start_requests (包含 Request 的可迭代對象) – start requests
spider (Spider 對象) – start requests所屬的spider