Scrapy-4.Middleware

本文地址:http://www.reibang.com/p/2f80c0fb818e

眾所周知Scrapy有一個非常強大的優(yōu)點累提,就是其結(jié)構(gòu)非常模塊化,想要自定義的擴展功能非常方便署恍。而其模塊化的思想很大一部分體現(xiàn)在其Middleware組件上。

Middleware其實是一個輕量級、較底層的鉤子框架,用來全局的去處理相對應(yīng)的內(nèi)容扣囊。得益于其模塊化的結(jié)構(gòu),編寫和添加一個Middleware是非常輕松方便的绒疗。

Scrapy中主要有兩種Middleware侵歇,一種是Downloader Middleware,一種是Spider Middleware吓蘑。


下載中間件(Downloader Middleware)

如簡介中的流程圖所示惕虑,Downloader Middleware處于Downloader和引擎之間,所以它可以處理進出Downloader的Request和Response磨镶。

啟用下載中間件(Downloader Middleware)

首先溃蔫,我們要啟用一個Downloader Middleware,需要在settings中進行相應(yīng)的設(shè)置琳猫,如下是一個簡單例子:

DOWNLOADER_MIDDLEWARES = {
    'myproject.middlewares.CustomDownloaderMiddleware': 543,
}

這個字典的鍵名是Downloader Middleware類的路徑伟叛,值是其優(yōu)先級。

DOWNLOADER_MIDDLEWARES設(shè)置將會與默認的DOWNLOADER_MIDDLEWARES_BASE混合脐嫂,然后按照對應(yīng)的優(yōu)先級進行排序统刮。優(yōu)先級數(shù)值越小,越靠近引擎這邊账千,數(shù)值越大侥蒙,越靠近Downloader一端。

換句話說匀奏,Downloader Middleware中的process_request()方法鞭衩,將按照優(yōu)先級逐漸增大的順序依次調(diào)用,而process_response()方法調(diào)用順序正好相反娃善。

DOWNLOADER_MIDDLEWARES_BASEScrapy中默認已經(jīng)啟用的一些默認的下載中間件:

{
    '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,
}

如果你想要將自定義的Downloader Middleware插入到指定的位置论衍,那么你需要將優(yōu)先級設(shè)置為相對應(yīng)的中間件優(yōu)先級之間。

如果想要關(guān)閉DOWNLOADER_MIDDLEWARES_BASE中某些中間件聚磺,那么你可以在DOWNLOADER_MIDDLEWARES中將其值設(shè)置為None坯台。如下所示:

DOWNLOADER_MIDDLEWARES = {
    'myproject.middlewares.CustomDownloaderMiddleware': 543,
    'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
}

自定義下載中間件(Downloader Middleware)

每個Middleware都是一個定義了以下一個或多個方法的Python類。

class scrapy.downloadermiddlewares.DownloaderMiddleware
  • process_request(request, spider)

    當request通過這個Downloader Middleware時咧最,將會調(diào)用這個函數(shù)來處理request捂人。

    參數(shù):

    • request(Request對象) - 被處理的request御雕。
    • spider(Spider對象) - 這個reuqest所對應(yīng)的spider。

    這個方法應(yīng)該返回以下四種結(jié)果之一:

    • None

      如果返回None滥搭,那么Scrapy會繼續(xù)往下處理這個request酸纲,執(zhí)行接下來的其他Middleware,最終下載這個request并獲得response瑟匆。

    • Response

      如果返回的是Response的話闽坡,那么Scrapy會中斷對這個Request的后續(xù)處理,不再調(diào)用后續(xù)的process_request()process_exception()愁溜。Scrapy會調(diào)用所有啟用的Middleware中的process_response()來處理這個Response疾嗅。

    • Request

      如果返回的是Request,那么Scrapy同樣會中斷這個Request的后續(xù)處理冕象,然后把返回的Request重新進行調(diào)度代承。

    • IgnoreRequest

      如果在這個方法中拋出了一個IgnoreRequest異常,那么啟用的Middleware中的process_exception()將會被調(diào)用渐扮。如果沒有一個方法處理這個異常论悴,那么Request自帶的異常處理函數(shù)(Request.errback)會被調(diào)用。如果沒有任何代碼處理這個異常墓律,那么這個Request將被忽略并且不會被記錄膀估。

  • process_response(request, response, spider)

    Downloader生成的Response在通過Downloader時,用來處理Response的方法耻讽。

    參數(shù):

    • request(Request對象) - response所對應(yīng)的request察纯。
    • response(Response對象) - 要處理的response。
    • spider(Spider對象) - 這個response所對應(yīng)的spider针肥。

    這個方法應(yīng)該返回以下三種結(jié)果之一:

    • Response

      如果返回的是Response饼记,那么Scrapy將會繼續(xù)調(diào)用下一個Middleware中的process_response()方法進行處理。

    • Request

      如果返回的是Request祖驱,那么Scrapy將會中斷對Response的處理握恳,并將返回的Request重新進行調(diào)度瞒窒。與process_request()中返回Request的處理方式是一樣的捺僻。

    • IgnoreRequest

      如果在方法中拋出了一個IgnoreRequest異常,那么Request自帶的異常處理函數(shù)(Request.errback)會被調(diào)用崇裁。如果沒有任何代碼處理這個異常匕坯,那么這個Request將被忽略并且不會被記錄。

  • process_exception(request, exception, spider)

    如果在Download或者process_request()過程中拋出一個異常拔稳,那么將會調(diào)用此方法來處理異常葛峻。

    參數(shù):

    • request(Request對象) - 產(chǎn)生異常的request。
    • exception(Exception對象) - 拋出的異常巴比。
    • spider(Spider對象) - request對應(yīng)的Spider术奖。

    這個方法應(yīng)該返回以下三種結(jié)果之一:

    • None

      如果返回的是None礁遵,Scrapy將會繼續(xù)調(diào)用啟用的Middleware中的process_exception()來處理異常。當所有剩下的process_exception()都調(diào)用完畢后采记,會使用默認的異常處理佣耐。

    • Response

      如果返回的是一個Response對象,那么Scrapy將會中斷異常的處理唧龄,重新調(diào)用所有啟用的Middleware中的process_response()來處理返回的這個Response兼砖。

    • Request

      如果返回的是一個Request對象,那么Scrapy將會中斷異常的處理既棺,重新調(diào)用所有啟用的Middleware中的process_request()來處理返回的這個Request讽挟。


爬蟲中間件(Spider Middleware)

爬蟲中間件與下載中間件的作用都是對經(jīng)過的數(shù)據(jù)進行處理,只不過爬蟲中間件的位置處于Spider與引擎之間丸冕,主要處理Spider的輸入和輸出耽梅。相對于下載中間件來說,爬蟲中間件使用的較少胖烛。

爬蟲中間件(Spider Middleware)與下載中間件(Downloader Middleware)最主要的區(qū)別是褐墅,下載中間件處理的是進出Downloader的Request和Response,爬蟲中間件處理的洪己,主要是從Downloader返回的Response和Spider生成的Request和Item妥凳。

可以看到,在處理Response這里答捕,下載中間件和爬蟲中間件是有一定的功能重疊的逝钥。但是在處理Request的時候,兩者之間其實還間隔著一個調(diào)度器(Scheduler)拱镐,所以這里處理的Request還有著未經(jīng)調(diào)度器處理艘款,和已經(jīng)經(jīng)過調(diào)度器處理的區(qū)別。并且沃琅,爬蟲中間件還能處理Spider生成的Item哗咆。

爬蟲中間件同樣有一部分已經(jīng)默認啟用的基礎(chǔ)中間件SPIDER_MIDDLEWARES_BASE

{
    'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware': 50,
    'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': 500,
    'scrapy.spidermiddlewares.referer.RefererMiddleware': 700,
    'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware': 800,
    'scrapy.spidermiddlewares.depth.DepthMiddleware': 900,
}

啟用爬蟲中間件的方式也和下載中間件基本一致。

SPIDER_MIDDLEWARES = {
    'myproject.middlewares.CustomSpiderMiddleware': 543,
    'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': None,
}

自定義爬蟲中間件(Spider Middleware)

每個爬蟲中間件都是一個類:

class scrapy.spidermiddlewares.SpiderMiddleware

其中定義了以下一個或多個方法:

  • process_spider_input(response, spider)

    這個方法將會在Response傳入Spider之前調(diào)用益眉,來處理這個Response晌柬。

    參數(shù):

    • response(Response對象) - 處理的response。
    • spider(Spider對象) - response對應(yīng)的spider郭脂。

    process_spider_input()需要返回一個None或者拋出一個異常年碘。

    • None

      如果返回的是None的話,Scrapy將會調(diào)用接下來的Middleware繼續(xù)處理Response展鸡。

    • 拋出異常

      如果這個方法拋出的是一個異常的話屿衅,Scrapy將會停止處理這個Response。并調(diào)用Request對應(yīng)的異常處理函數(shù)莹弊。

  • process_spider_output(response, result, spider)

    這個方法會在Spider返回結(jié)果時調(diào)用涤久,用來處理Spider返回的Request涡尘,dict或者Item。

    參數(shù):

    • response(Response對象) - Spider用來生成返回結(jié)果的Response响迂。
    • result(Request, dict或者Item對象) - Spider生成的返回結(jié)果悟衩。
    • spider(Spider對象) - 處理結(jié)果的Spider
  • process_spider_exception(response, exception, spider)

    Spider或者process_spider_input()中拋出異常時栓拜,將會調(diào)用此方法來處理異常座泳。

    參數(shù):

    • response(Response對象) - 異常拋出時被處理的Response。
    • exception(Exception對象) - 拋出的異常幕与。
    • spider(Spider對象) - 拋出異常的Spider挑势。

    這個方法返回的結(jié)果有兩種選擇:

    • None

      如果返回的是None,那么Scrapy將會繼續(xù)調(diào)用接下來的Midleware中的process_spider_exception()方法來處理異常啦鸣。

    • 包含Request潮饱,dict或者Item的可迭代對象

      如果返回的是一個包含Request,dict或者Item的可迭代對象诫给,那么異常處理將會被中斷香拉。轉(zhuǎn)而開始調(diào)用process_spider_output()方法。

  • process_start_requests(start_requests, spider)

    Spider訪問的是最初始的start_requests時中狂,將會調(diào)用這個方法來進行處理Spider的輸出凫碌,這個方法的使用與process_spider_output()大致相同,區(qū)別只是處理的目標不同胃榕。

    而且這個方法只能返回一個包含Request的可迭代對象盛险。


系列文章:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市勋又,隨后出現(xiàn)的幾起案子苦掘,更是在濱河造成了極大的恐慌,老刑警劉巖楔壤,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鹤啡,死亡現(xiàn)場離奇詭異,居然都是意外死亡蹲嚣,警方通過查閱死者的電腦和手機递瑰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來端铛,“玉大人泣矛,你說我怎么就攤上這事疲眷『滩希” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵狂丝,是天一觀的道長换淆。 經(jīng)常有香客問我哗总,道長,這世上最難降的妖魔是什么倍试? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任讯屈,我火速辦了婚禮,結(jié)果婚禮上县习,老公的妹妹穿的比我還像新娘涮母。我一直安慰自己,他們只是感情好躁愿,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布叛本。 她就那樣靜靜地躺著,像睡著了一般彤钟。 火紅的嫁衣襯著肌膚如雪来候。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天逸雹,我揣著相機與錄音营搅,去河邊找鬼。 笑死梆砸,一個胖子當著我的面吹牛转质,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播帖世,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼峭拘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了狮暑?” 一聲冷哼從身側(cè)響起鸡挠,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎搬男,沒想到半個月后拣展,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡缔逛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年备埃,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片褐奴。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡按脚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出敦冬,到底是詐尸還是另有隱情辅搬,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布脖旱,位于F島的核電站堪遂,受9級特大地震影響介蛉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜溶褪,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一供炎、第九天 我趴在偏房一處隱蔽的房頂上張望晶姊。 院中可真熱鬧馏谨,春花似錦故河、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贰剥,卻和暖如春倾剿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蚌成。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工前痘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人担忧。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓芹缔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瓶盛。 傳聞我的和親對象是個殘疾皇子最欠,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354