Scrapy入門到放棄03:理解settings配置,監控Scrapy引擎

前言

程式碼未動,配置先行。本篇文章主要講述一下Scrapy中的配置文件settings.py的參數含義,以及如何去獲取一個爬蟲程式的運行性能指標。

這篇文章無聊的一匹,沒有程式碼,都是配置化的東西,但是呢不學還不行,屬於Scrapy的樞紐,很關鍵。所以還請各位看官老爺耐得住這一章的寂寞。

settings.py

在我們創建一個Scrapy項目的時候,就會在項目下生成四個py文件,其中就有一個settings.py。其中大大小小配置也是有大幾十個,這裡只講一些比較常見的,其他的還請移步官方文檔。

官文配置參數說明url:
//docs.scrapy.org/en/latest/topics/settings.html

常見參數

下面也羅列了小几十個配置,大部分都其實使用默認值即可,最值得我們關注的,就是下面幾個:

  1. DOWNLOAD_DELAY
  2. CONCURRENT_REQUESTS
  3. CONCURRENT_REQUESTS_PER_DOMAIN
  4. CONCURRENT_REQUESTS_PER_IP
  5. SPIDER_MIDDLEWARES
  6. DOWNLOADER_MIDDLEWARES
  7. ITEM_PIPELINES

那麼,為什麼說Settings是Scrapy的樞紐?

Scrapy架構

還記得我上篇文章畫的架構圖嗎?還記得之前說過Scrapy的四大模組嗎?每個模組在項目初始化時都是獨立的,各個模組只有在Settings配置之後,請求、響應、數據才會在模組間流轉。這一部分對應上面提到的配置5、6、7。

配置具體說明,詳看下文:

# Scrapy settings for ScrapyDemo project

# 自動生成的配置,無需關注,不用修改
BOT_NAME = 'ScrapyDemo'
SPIDER_MODULES = ['ScrapyDemo.spiders']
NEWSPIDER_MODULE = 'ScrapyDemo.spiders'

# 設置UA,但不常用,一般都是在MiddleWare中添加
USER_AGENT = 'ScrapyDemo (+//www.yourdomain.com)'

# 遵循robots.txt中的爬蟲規則,很多人喜歡False,當然我也喜歡....
ROBOTSTXT_OBEY = True

# 對網站並發請求總數,默認16
CONCURRENT_REQUESTS = 32

# 相同網站兩個請求之間的間隔時間,默認是0s。相當於time.sleep()
DOWNLOAD_DELAY = 3
# 下面兩個配置二選一,但其值不能大於CONCURRENT_REQUESTS,默認啟用PER_DOMAIN
# 對網站每個域名的最大並發請求,默認8
CONCURRENT_REQUESTS_PER_DOMAIN = 16
# 默認0,對網站每個IP的最大並發請求,會覆蓋上面PER_DOMAIN配置,
# 同時DOWNLOAD_DELAY也成了相同IP兩個請求間的間隔了
CONCURRENT_REQUESTS_PER_IP = 16

# 禁用cookie,默認是True,啟用
COOKIES_ENABLED = False

# 請求頭設置,這裡基本上不用
DEFAULT_REQUEST_HEADERS = {
#   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
#   'Accept-Language': 'en',
#}

# 配置啟用Spider MiddleWares,Key是class,Value是優先順序
SPIDER_MIDDLEWARES = {
    'ScrapyDemo.middlewares.ScrapydemoSpiderMiddleware': 543,
}

# 配置啟用Downloader MiddleWares

DOWNLOADER_MIDDLEWARES = {
    'ScrapyDemo.middlewares.ScrapydemoDownloaderMiddleware': 543,
}

# 配置並啟用擴展,主要是一些狀態監控
EXTENSIONS = {
    'scrapy.extensions.telnet.TelnetConsole': None,
}

# 配置啟用Pipeline用來持久化數據
ITEM_PIPELINES = {
   'ScrapyDemo.pipelines.ScrapydemoPipeline': 300,
}

# 禁止控制台使用telnet連接scrapy獲取狀態,默認是啟用。我們使用默認值即可
TELNETCONSOLE_ENABLED = False
# Telnet終端使用的埠範圍。默認: [6023, 6073],如果設置為 None 或 0 , 則使用動態分配的埠
# TELNETCONSOLE_PORT

# telnet帳號,默認:scrapy
TELNETCONSOLE_USERNAME = None

# telnet密碼:默認會自動生成一個密碼
TELNETCONSOLE_PASSWORD

# Telnet終端監聽的介面(interface)。默認: '127.0.0.1'
TELNETCONSOLE_HOST = '127.0.0.1'


# AutoThrottle是限速節流演算法
# 讓爬蟲程式自適應download_delay和concurrent並發
AUTOTHROTTLE_ENABLED = True
# 爬蟲程式啟動時,開始對網站發起請求的延遲
AUTOTHROTTLE_START_DELAY = 5
# 請求到響應的最大允許的延遲時間,必須大於download_delay
AUTOTHROTTLE_MAX_DELAY = 60
# 並行發送到每個遠程伺服器的平均請求數,小於CONCURRENT_REQUESTS_PER_DOMAIN和CONCURRENT_REQUESTS_PER_IP
AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
# 為每個響應啟用顯示限制統計資訊
AUTOTHROTTLE_DEBUG = False

# HttpCache主要是將每次的請求和響應快取到本地,可以離線進行處理
# 配置啟用HTTP Cache,默認不啟用
HTTPCACHE_ENABLED = True
# 快取的過期時間,0為永不過期
HTTPCACHE_EXPIRATION_SECS = 0
# 快取目錄名稱
HTTPCACHE_DIR = 'httpcache'
# 設置不需要快取的狀態碼請求
HTTPCACHE_IGNORE_HTTP_CODES = []
# 此類將快取保存到本地文件系統,還可以使用其他類保存到資料庫
HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'

像上面的Telnet配置使用默認即可,一般AutoThrottle限速演算法和Http Cache用的也少,當然還有一些log日誌、retry請求重試功能,這裡就不一一列舉了。

局部配置定義

settings.py中的配置,屬於全局配置,是項目中所有爬蟲共享的。改了一個,其他的爬蟲也會受影響。

所以很多時候我們都會在爬蟲程式內,定義字典類型的custom_settings成員變數,來實現局部配置。

    custom_settings = {
        'DOWNLOAD_DELAY': 10
    }

這樣DOWNLOAD_DELAY為10這個配置,只在當前程式中生效。

那這局部配置在什麼時候用的多?

我用的最多的地方,就是使用Scrapy-Splash插件的時候,因為要發起的是SplashRequest,而不是之前的Request,所以要進行單獨的配置。為了不改變全局配置、影響其他爬蟲,通常在程式內定義這些配置。

這個後面Scrapy-Splash插件會講。

啟動時配置

我們在啟動爬蟲時,可以使用-s來指定配置。

scrapy crawl [spiderName] -s DOWNLOAD_DELAY=10

程式中獲取配置

我們通常也將資料庫的用戶、密碼、ip等資訊配置在settings中,然後通過crawler對象來獲取。該對象提供對所有Scrapy核心組件的訪問,可以debug看一下。

如圖,可以通過crawler訪問到settings配置、engine引擎、訊號量signals、狀態stat等。這裡我們先只關注settings。

這裡寫一段程式碼,驗證局部配置、啟動時配置、以及配置三個功能。

import scrapy

class DouLuoDaLuSpider(scrapy.Spider):
    name = 'DouLuoDaLu'
    allowed_domains = ['v.qq.com']
    start_urls = ['//v.qq.com/detail/m/m441e3rjq9kwpsc.html']
    # 自定義配置
    custom_settings = {
        'DOWNLOAD_DELAY': 10
    }

    def parse(self, response):
        # 獲取配置
        delay = self.crawler.settings.get('DOWNLOAD_DELAY')
        print(delay)

DOWNLOAD_DELAY在全局配置中我修改為3,如果沒有在程式中定義custom_settings,則輸出為3。

當我們定義custom_settings之後,啟動程式,輸出如下:

這裡輸出的就是10,是程式內的配置,覆蓋了全局配置。當我們使用以下命令在啟動爬蟲時指定延遲為11。

scrapy crawl DouLuoDaLu -s DOWNLOAD_DELAY=11


則輸出為11,覆蓋了程式內變數。所以,我們也得出一個結論,同一配置的優先順序為:

啟動時配置 > 程式內配置 > 全局配置

引擎狀態監控

關於引擎的定義:

Scrapy engine which controls the Scheduler, Downloader and Spiders

引擎狀態是指現在調度器中有多少請求排隊、下載器中有多少個請求正在下載、有多少響應在被處理等等,而監控是通過telnet來實現。

我的Scrapy中全局配置都是默認的,為了直觀,我這裡都使用局部配置。這裡我發起100 * 10次請求,模擬一個一直運行的爬蟲,程式碼如下:

import scrapy
from scrapy import Request

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

    custom_settings = {
        'DOWNLOAD_DELAY': 6,
        'CONCURRENT_REQUESTS': 32,
        'CONCURRENT_REQUESTS_PER_DOMAIN': 8,
        # 帳號默認就是scrapy
        # 'TELNETCONSOLE_USERNAME' = 'scrapy'
        'TELNETCONSOLE_PASSWORD': 'scrapy'
    }

    def start_requests(self):
        for i in range(0, 100):
            yield Request(url=self.start_urls[0], callback=self.parse, dont_filter=True)

    def parse(self, response):
        for i in range(0, 10):
            yield Request(url=self.start_urls[0], callback=self.parse, dont_filter=True)

啟動爬蟲之後,使用以下命令進入telnet。

# telnet終端監聽埠配置為*TELNETCONSOLE_PORT*,默認為6023。
telnet localhost 6023

輸入帳號和密碼:
telnet

進入交互頁面,輸入est(),輸出引擎狀態指標。

主要監控一下五個指標:

  1. engine.downloader.active:下載器中等待下載的請求,對應最大並發數。設置中為32,這裡也是32,說明下載器已經滿了,其他請求進不來了。
  2. engine.slot.scheduler.mqs:記憶體調度隊列。進不去下載器的請求就只能在調度器中等待了,這裡有28個請求在等待。
  3. engine.slot.scheduler.dqs:磁碟調度隊列,可以設置,將請求放於磁碟之中。
  4. engine.scraper.slot.active:正在被處理的響應數量
  5. engine.scraper.slot.itemproc_size:pipeline處理的Item數量

同時也可以在交互命令中暫停、恢復、停止引擎。

engine.pause()
engine.unpause()
engine.stop()

當引擎被暫停或停止,下載器處理完隊列中的請求之後,便處於空閑狀態。

結語

本篇文章主要講了一些基本的配置和Telnet引擎監控,主要目的還是為了將Scrapy架構掰扯清楚,後面用的時候才能瞭然於胸。

後面的文章接著寫其他模組,下一篇講MiddleWare中間件,下下篇就是Pipeline,下下下篇打算寫一個完整的樣例,將各個模組整合起來。期待下一次相遇。


95後小程式設計師,寫的都是日常工作中的親身實踐,置身於初學者的角度從0寫到1,詳細且認真。文章會在公眾號 [入門到放棄之路] 首發,期待你的關注。

感謝每一份關注