1. 程式人生 > 遊戲 >生活模擬遊戲《花園小徑》將於2023年春季推出

生活模擬遊戲《花園小徑》將於2023年春季推出

前言

MiddleWare,顧名思義,中介軟體。主要處理請求(例如新增代理IP、新增請求頭等)和處理響應。

本篇文章主要講述下載器中介軟體的概念,以及如何使用中介軟體和自定義中介軟體。

MiddleWare分類

依舊是那張熟悉的架構圖。

從圖中看,中介軟體主要分為兩類:

  1. Downloader MiddleWare:下載器中介軟體
  2. Spider MiddleWare:Spider中介軟體

本篇文主要介紹下載器中介軟體,先看官方的定義:

下載器中介軟體是介於Scrapy的request/response處理的鉤子框架。 是用於全域性修改Scrapy request和response的一個輕量、底層的系統。

作用

如架構圖中所描述的一樣,下載器中介軟體位於engine和下載器之間。engine將未處理的請求傳送給下載器的時候,會經過下載器中介軟體,這時候在中介軟體裡可以包裝請求,例如修改請求頭資訊(設定UA、cookie等)和新增代理IP。

當下載器將網站的響應傳送給engine的時候,也會經過下載器中介軟體,這裡我們就可以對響應內容進行處理。

內建下載器中介軟體

Scrapy內建了很多下載器中介軟體供開發者使用。當我們啟動一個Scrapy爬蟲時,Scrapy會自動幫助我們啟用這些中介軟體。如圖:

圖中就是在啟動Scrapy程式時控制檯列印的日誌資訊,我們發現Scrapy幫我們啟用了很多下載器中介軟體和Spider中介軟體。

這裡,先看看這些內建的中介軟體是如何發揮作用的?

RetryMiddleware

其實,這些內建中介軟體是和settings中的配置配套使用的。這裡就拿RetryMiddleware為例。它的作用主要是:當請求失敗時,可以根據RETRY_ENABLEDRETRY_TIMES配置來啟用重試策略以及決定重試次數。就醬!!

那麼問題又來了,這麼多中介軟體,我去哪裡找這個settings配置和中介軟體的對應關係啊??

這裡我的方法有兩種:

  1. 去官方文件,上篇文章有連結
  2. 看原始碼註釋,在scrapy包下的都有中介軟體對應的py檔案

註釋裡面寫的明明白白,程式碼中獲取的引數也一覽無餘。

自定義中介軟體

有時候,內建的中介軟體滿足不了自己的需求,所以我們就要自力更生,自定義中介軟體。所有的中介軟體都在middlewares.py中進行定義。

我們開啟middlewares.py,發現裡面已經自動生成了一個下載器中介軟體和Spider中介軟體。

先看自生成的下載器中介軟體模板:

可以看到裡面主要有五個方法:

  1. from_crawler:類方法,用於初始化中介軟體
  2. process_request:每個request通過下載中介軟體時,都會呼叫該方法,對應架構圖步驟4
  3. process_response:處理下載器返回的響應內容,對應架構圖步驟7
  4. process_exception:當下載器或者處理請求異常時,呼叫此方法
  5. spider_opened:內建的訊號量回調方法,這裡先不關注,先不關注!

這裡主要關注3,順帶了解一下4、5。

process_request()

此方法有兩個引數:

  1. request:spider發起的需要處理的request
  2. spider:該request對應的spider,暫定訊號量細講這個物件
def process_request(self, request, spider):
        # Called for each request that goes through the downloader middleware.

        # Must either:
        # - return None: continue processing this request
        # - or return a Response object
        # - or return a Request object
        # - or raise IgnoreRequest: process_exception() methods of
        #   installed downloader middleware will be called
        return None

這裡主要是為了讓大家看註釋,看註釋的目的是為了告訴大家:此方法必須返回值

  1. None:基本上用的都是這個返回值。表示這個請求可以進去下一個中介軟體進行處理了。
  2. request:停止呼叫process_request方法,並重新將request放回佇列重新排程
  3. response:不會呼叫其他的 process_request,直接返回response,執行process_response。

還有一個是raise丟擲異常,其實基本上返回值都用None,其他的目前可以僅做了解,有興趣的可以自己探索一下。

process_response()

此方法有三個引數:

  1. request:response所對應的request
  2. response:被處理的response
  3. spider:response所對應的spider
def process_response(self, request, response, spider):
        # Called with the response returned from the downloader.

        # Must either;
        # - return a Response object
        # - return a Request object
        # - or raise IgnoreRequest
        return response

一樣是看註釋,返回值有兩個:

  1. response:下載器返回的響應內容,在各個中介軟體的process_response處理
  2. request:停止呼叫process_response方法,響應不會到達spider,並重新將request放回佇列重新排程

這裡記住,只要return response就行。

process_exception()

def process_exception(self, request, exception, spider):
        # Called when a download handler or a process_request()
        # (from other downloader middleware) raises an exception.

        # Must either:
        # - return None: continue processing this exception
        # - return a Response object: stops process_exception() chain
        # - return a Request object: stops process_exception() chain
        pass

此方法就是當上面兩個方法丟擲異常的時候就會進入此方法,返回值有三個,意思和上面的差不多,用None就行。

啟用和禁用中介軟體

自定義的中介軟體,有時候會和內建中介軟體功能重複,也擔心功能上互相覆蓋。所以這裡我們可以選擇,在配置中關掉內建中介軟體。

我個人比較喜歡自定義User-Agent中介軟體,但是Scrapy內建UserAgentMiddleware中介軟體,這就衝突了。如果內建中介軟體執行優先順序低,後執行的話,則內建的UA就會覆蓋自定義的UA。所以,我們需要關掉這個內建中UA中介軟體。

DOWNLOADER_MIDDLEWARES引數用來設定下載器中介軟體。其中,Key為中介軟體路徑,Value為中介軟體執行優先順序,數字越小,越先執行,當Value為None時,表示禁用。

# settings.py
DOWNLOADER_MIDDLEWARES = {
    # 禁用預設的useragent外掛
    'scrapy.downloadermiddleware.useragent.UserAgentMiddleware': None,
    # 啟用自定義的中介軟體
    'ScrapyDemo.middlewares.VideospiderDownloaderMiddleware': 543,
}

這樣,內建的UA中介軟體則被禁用。

呼叫優先順序

其次我們要明確的是:中介軟體是鏈式呼叫,一個請求會根據中介軟體的優先順序,先後經過每個中介軟體,響應也是

上面也說了,每個中介軟體都會設定一個執行優先順序,數字越小越先執行。例如中介軟體1的優先順序設定為200,中介軟體2的優先順序設定為300。

當spider發起一個請求時,request會先經過中介軟體1的process_request進行處理,然後到達中介軟體2的此方法進行處理,當經過所有的中介軟體的此方法處理之後,最後到達下載器進行網站請求,然後返回響應內容。

process_response就是逆序處理,先到達中介軟體2的此方法,再到達中介軟體1,最後響應返回spider中,由開發者處理。

實踐

這裡我們自定義一個下載器中介軟體,來新增User-Agent。

自定義中介軟體

在middlewares.py中定義一箇中間件:

class CustomUserAgentMiddleWare(object):

    def process_request(self, request, spider):
        request.headers['User-Agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36'
        return None

    def process_response(self, request, response, spider):
        print(request.headers['User-Agent'])
        return response

啟用中介軟體

為了直觀,我們不修改settings.py全域性配置,依舊使用程式碼內區域性配置。

import scrapy

class DouLuoDaLuSpider(scrapy.Spider):
    name = 'DouLuoDaLu'
    allowed_domains = ['v.qq.com']
    start_urls = ['https://v.qq.com/detail/m/m441e3rjq9kwpsc.html']

    custom_settings = {
        'DOWNLOADER_MIDDLEWARES': {
            # 禁用預設的useragent外掛
            'scrapy.downloadermiddleware.useragent.UserAgentMiddleware': None,
            # 啟用自定義的中介軟體
            'ScrapyDemo.middlewares.CustomUserAgentMiddleWare': 400
        }
    }


    def parse(self, response):
        pass

這裡首先禁用了預設的UA中介軟體,然後啟用了自定義的UA中介軟體。並且我在最後一行打上斷點,Debug看UA是否設定成功。

測試結果

Debug模式啟動程式,這裡先把自定義的UA中介軟體禁用。

如圖,request的UA是Scrapy。我們將註釋去掉,啟動UA中介軟體,再次啟動程式測試。

如圖,request的UA已經變成我在中介軟體中設定的UA了。

設定代理IP

依舊是在process_request方法中設定代理IP。

程式碼如下:

request.meta["proxy"] = 'http://ip:port'

結語

下載器中介軟體主要的功能還是包裝請求,我個人自定義下載器中介軟體都是用來動態設定UA和實時檢測更換代理IP。至於其他的場景需求,內建的下載器中介軟體基本上夠用。

當然,不去學習下載器中介軟體這一塊的知識同樣可以開發Scrapy爬蟲,但是下載器中介軟體會讓你的爬蟲更加完美。

本來想把下載器中介軟體和Spider中介軟體寫在一篇中,但是知識點太碎,不好排版,而且還容易混淆,所以Spider中介軟體就留在下一篇寫,期待下一次相遇。