參考資料
Scrapy官方文檔:下載器中間件
徹底搞懂Scrapy的中間件(一)
徹底搞懂Scrapy的中間件(二)
徹底搞懂Scrapy的中間件(三)
【反爬蟲】下載器中間件講解
scrapy框架圖
圖中的數字編號指的是scrapy工作流程中的各個步驟,其中4、5步驟所歷經的組件爲下載器中間件。
所謂下載器中間件就是連接在Scrapy引擎和下載器之間的組件,主要是處理Scrapy引擎與下載器之間的請求及響應。
下載器中間件在scrapy官方文檔中的定義爲:下載器中間件是介於Scrapy的request/response處理的鉤子框架。 是用於全局修改Scrapy request和response的一個輕量、底層的系統。
通俗點說中間件是Scrapy裏面的一個核心概念。使用中間件可以在爬蟲的請求發起之前或者請求返回之後對數據進行定製化修改,從而開發出適應不同情況的爬蟲。所謂定製化修改主要爲更換代理IP,更換Cookies,更換User-Agent,剔除無效返回,自動重試。
假如沒有下載器中間件,爬蟲流程如圖所示:
假如有了下載器中間件,爬蟲流程如圖所示
Scrapy有以下自帶的下載器中間件
{
'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100,
'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': 300,
'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': 350,
'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 400,
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 500,
'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550,
'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': 560,
'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware': 580,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 590,
'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': 600,
'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 700,
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
'scrapy.downloadermiddlewares.stats.DownloaderStats': 850,
'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': 900,
}
當然用戶也可以自定義自己的下載器中間件,使用自定義的下載器中間件時要在settings.py文件中激活這個中間件
DOWNLOADERMIDDLEWARES = {
'myproject.middlewares.Custom_A_DownloaderMiddleware': 543,
'myproject.middlewares.Custom_B_DownloaderMiddleware': 643,
'myproject.middlewares.Custom_B_DownloaderMiddleware': None,
}
關於中間件順序,簡單畫個圖說明
其中數字越小越靠近引擎,數字越大越靠近下載器,process_request()優先處理;數字越大的,process_response()優先處理;若需要關閉某個中間件直接設爲None即可
假如要自定義下載器中間件,主要編寫下面幾個方法
class scrapy.downloadermiddlewares.DownloaderMiddleware
process_request(request, spider)
當每個request通過下載中間件時,該方法被調用。
通常它會返回 None
返回一個 Response 對象
返回一個 Request 對象
或raise IgnoreRequest
如果其返回 None ,Scrapy將繼續處理該request,執行其他的中間件的相應方法,直到合適的下載器處理函數(download handler)被調用, 該request被執行(其response被下載)。
如果其返回 Response 對象,Scrapy將直接返回該response,而不會再執行其他的中間件。
如果其返回 Request 對象,Scrapy則不再使用之前的request對象去下載數據,而是根據現在返回的request對象去下載數據。
如果其raise一個IgnoreRequest 異常,則安裝的下載中間件的 process_exception() 方法會被調用。 如果沒有代碼處理拋出的異常,則該異常被忽略且不記錄(不同於其他異常那樣)
process_response(request, response, spider)
當每個response通過下載中間件時,該方法被調用
通常它會返回 None
返回一個 Response 對象
返回一個 Request 對象
或raise IgnoreRequest 。
如果其返回一個 Response (可以與傳入的response相同,也可以是全新的對象), 該response會被在鏈中的其他中間件的 process_response() 方法處理。
如果其返回一個 Request 對象,則下載器中間件鏈被切斷, 返回的request會被重新調度下載。
如果其拋出一個 IgnoreRequest 異常,則調用request的errback方法(自行設置)。 如果沒有代碼處理拋出的異常,則該異常被忽略且不記錄(不同於其他異常那樣)
process_exception(request, exception, spider)
當下載處理器(download handler)或 process_request() 拋出異常(包括 IgnoreRequest 異常)時, Scrapy調用 process_exception()。(對此方法還不太瞭解)