Scrapy 配置介紹及常見優化配置
今天我們來看看 Scrapy 框架的相關配置項以及常見的一些優化配置。涉及的文件主要是 scrapy 項目的 settings.py
文件和 Scrapy 源碼目錄下的 scrapy/settings/default_settings.py
文件。這些內容會在我們每個 Scrapy 爬蟲項目中都會用到,特別是在爬取海量數據時需要特別注意的地方。
1. Scrapy 的 settings.py
配置
從前面的學習中我們知道,settings.py
是 Scrapy 使用 startproject 命令生成的,這里的配置會默認覆蓋 Scrapy 內置的配置項,這些默認的配置項都位于 Scrapy 的 scrapy/settings/default_settings.py 中:
我們來看看 default_settings.py 中的一些默認配置項。
-
AJAXCRAWL_ENABLED
:通用爬取經常會抓取大量的 index 頁面;AjaxCrawlMiddleware 能幫助我們正確地爬取,AJAXCRAWL_ENABLED
配置正是開啟該中間件的開關。由于有些性能問題,且對于特定爬蟲沒有什么意義,該中間默認關閉; -
自動限速擴展 (AutoThrottle):這類配置主要是以 Scrapy 爬蟲以及正在抓取網站的負載來自動優化爬取速度。它能自動調整 Scrapy 達到最佳的爬取速度,使用者無需自己設置下載延遲,只要設置好最大并發請求數即可。來看看有關該擴展的配置項:
AUTOTHROTTLE_ENABLED = False # 默認關閉 AUTOTHROTTLE_DEBUG = False # 關閉調試 AUTOTHROTTLE_MAX_DELAY = 60.0 # 最高下載延遲 AUTOTHROTTLE_START_DELAY = 5.0 # 初始化下載延遲 AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 # Scrapy 同時請求目標網站的平均請求數
下面四個配置用于設置爬蟲自動關閉條件:
CLOSESPIDER_TIMEOUT
:一個整數值,單位為秒。如果一個 spider 在指定的秒數后仍在運行, 它將以closespider_timeout
的原因被自動關閉。 如果值設置為0 (或者沒有設置),spiders 不會因為超時而關閉;CLOSESPIDER_ITEMCOUNT
:一個整數值,指定條目的個數。如果 spider 爬取條目數超過了設置的值, 并且這些條目通過 item pipelines 傳遞,spider 將會以closespider_itemcount
的原因被自動關閉;CLOSESPIDER_PAGECOUNT
:一個整數值,指定最大的抓取響應 (reponses) 數。 如果 spider 抓取數超過指定的值,則會以closespider_pagecount
的原因自動關閉。 如果設置為0(或者未設置),spiders不會因為抓取的響應數而關閉;CLOSESPIDER_ERRORCOUNT
:一個整數值,指定spider可以接受的最大錯誤數。 如果spider生成多于該數目的錯誤,它將以closespider_errorcount
的原因關閉。 如果設置為0(或者未設置),spiders不會因為發生錯誤過多而關閉;
以上四個參數在 default_settings.py 中設置的默認值都是0
并發相關,的設置會較大影響 Scrapy 爬蟲的性能。下面是默認的配置值,其中都已經進行了詳細的注釋說明:
# pipelines中并發處理items數
CONCURRENT_ITEMS = 100
# scrapy中并發下載請求數
CONCURRENT_REQUESTS = 16
# 對任何單個域執行的并發請求的最大數量
CONCURRENT_REQUESTS_PER_DOMAIN = 8
# 將對任何單個IP執行的并發請求的最大數量。如果非零
CONCURRENT_REQUESTS_PER_IP = 0
Cookie相關配置:
# 是否啟用cookiesmiddleware。如果關閉,cookies將不會發送給web server
COOKIES_ENABLED = True
# 如果啟用,Scrapy將記錄所有在request(cookie 請求頭)發送的cookies及response接收到的cookies(set-cookie接收頭),這也會間接影響性能,因此默認關閉。
COOKIES_DEBUG = False
請求深度相關配置,比如 DEPTH_LIMIT
設置請求允許的最大深度。如果為 0 ,則表示不受限;DEPTH_STATS_VERBOSE
參數控制是否收集詳細的深度統計信息;如果啟用此選項,則在統計信息中收集每個深度的請求數。DEPTH_PRIORITY
參數用于根據深度調整請求優先級。來看看他們的默認設置:
DEPTH_LIMIT = 0
DEPTH_STATS_VERBOSE = False
DEPTH_PRIORITY = 0
DNS 相關配置。DNSCACHE_ENABLED
用于控制是否啟用 DNS 緩存,DNSCACHE_SIZE
參數設置緩存大小,DNS_TIMEOUT
處理 DNS 查詢超時時間;我們來具體看看 default_settings.py 中的默認配置:
DNSCACHE_ENABLED = True
DNSCACHE_SIZE = 10000
# 緩存解析器
DNS_RESOLVER = 'scrapy.resolver.CachingThreadedResolver'
DNS_TIMEOUT = 60
下載器相關。這部分的配置比較多,也是主要影響性能的地方。我們對一些關鍵的配置進行說明,具體如下:
DOWNLOAD_DELAY
:下載器在從同一網站下載連續頁面之前應等待的時間,通過該配置可以限制爬蟲的爬取速度。此外,該設置也受RANDOMIZE_DOWNLOAD_DELAY 設置(默認情況下啟用)的影響。DOWNLOAD_TIMEOUT
:下載超時時間;DOWNLOAD_MAXSIZE
:下載器將下載的最大響應大?。?/li>DOWNLOAD_HANDLERS_BASE
:處理不同類型下載的下載器;DOWNLOAD_FAIL_ON_DATALOSS
:數據丟失后是否繼續下載;DOWNLOADER_MIDDLEWARES
和DOWNLOADER_MIDDLEWARES_BASE
:分別表示自定義的下載中間件類和默認的下載中間件類;DOWNLOADER_STATS
:是否啟用下載器統計信息收集。
來看看 default_settings.py 中的默認配置,具體如下:
DOWNLOAD_DELAY = 0
DOWNLOAD_HANDLERS = {}
DOWNLOAD_HANDLERS_BASE = {
'data': 'scrapy.core.downloader.handlers.datauri.DataURIDownloadHandler',
'file': 'scrapy.core.downloader.handlers.file.FileDownloadHandler',
'http': 'scrapy.core.downloader.handlers.http.HTTPDownloadHandler',
'https': 'scrapy.core.downloader.handlers.http.HTTPDownloadHandler',
's3': 'scrapy.core.downloader.handlers.s3.S3DownloadHandler',
'ftp': 'scrapy.core.downloader.handlers.ftp.FTPDownloadHandler',
}
DOWNLOAD_TIMEOUT = 180 # 3mins
DOWNLOAD_MAXSIZE = 1024 * 1024 * 1024 # 1024m
DOWNLOAD_WARNSIZE = 32 * 1024 * 1024 # 32m
DOWNLOAD_FAIL_ON_DATALOSS = True
DOWNLOADER = 'scrapy.core.downloader.Downloader'
DOWNLOADER_HTTPCLIENTFACTORY = 'scrapy.core.downloader.webclient.ScrapyHTTPClientFactory'
DOWNLOADER_CLIENTCONTEXTFACTORY = 'scrapy.core.downloader.contextfactory.ScrapyClientContextFactory'
DOWNLOADER_CLIENT_TLS_CIPHERS = 'DEFAULT'
# Use highest TLS/SSL protocol version supported by the platform, also allowing negotiation:
DOWNLOADER_CLIENT_TLS_METHOD = 'TLS'
DOWNLOADER_CLIENT_TLS_VERBOSE_LOGGING = False
DOWNLOADER_MIDDLEWARES = {}
DOWNLOADER_MIDDLEWARES_BASE = {
# Engine side
'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 side
}
DOWNLOADER_STATS = True
DUPEFILTER_CLASS
:指定去重類;
DUPEFILTER_CLASS = 'scrapy.dupefilters.RFPDupeFilter'
自定義擴展和內置擴展配置:
EXTENSIONS = {}
EXTENSIONS_BASE = {
'scrapy.extensions.corestats.CoreStats': 0,
'scrapy.extensions.telnet.TelnetConsole': 0,
'scrapy.extensions.memusage.MemoryUsage': 0,
'scrapy.extensions.memdebug.MemoryDebugger': 0,
'scrapy.extensions.closespider.CloseSpider': 0,
'scrapy.extensions.feedexport.FeedExporter': 0,
'scrapy.extensions.logstats.LogStats': 0,
'scrapy.extensions.spiderstate.SpiderState': 0,
'scrapy.extensions.throttle.AutoThrottle': 0,
}
文件存儲相關:
FILES_STORE_S3_ACL = 'private'
FILES_STORE_GCS_ACL = ''
FTP 服務配置, Scrapy 框架內置 FTP 下載程序。我們可以指定 FTP 的相關參數:
FTP_USER = 'anonymous'
FTP_PASSWORD = 'guest'
FTP_PASSIVE_MODE = True
HTTP 緩存相關配置。Scrapy 的 HttpCacheMiddleware
組件(默認情況下沒有啟用)提供了一個底層的對HTTP請求和響應的緩存。如果啟用的話(把HTTPCACHE_ENABLED
設置為True
),它會緩存每個請求和對應的響應。來看看和其相關的配置和含義:
# 是否啟用http緩存
HTTPCACHE_ENABLED = False
# 緩存數據目錄
HTTPCACHE_DIR = 'httpcache'
HTTPCACHE_IGNORE_MISSING = False
# 緩存存儲的插件
HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'
# 緩存過期時間
HTTPCACHE_EXPIRATION_SECS = 0
HTTPCACHE_ALWAYS_STORE = False
# 緩存忽略的Http狀態碼
HTTPCACHE_IGNORE_HTTP_CODES = []
HTTPCACHE_IGNORE_SCHEMES = ['file']
HTTPCACHE_IGNORE_RESPONSE_CACHE_CONTROLS = []
HTTPCACHE_DBM_MODULE = 'dbm'
# 設置緩存策略,DummyPolicy是所有請求均緩存,下次在請求直接訪問原來的緩存即可
HTTPCACHE_POLICY = 'scrapy.extensions.httpcache.DummyPolicy'
# 是否啟用緩存數據壓縮
HTTPCACHE_GZIP = False
Item 和 Item pipelines相關配置:
# ITEM處理器
ITEM_PROCESSOR = 'scrapy.pipelines.ItemPipelineManager'
# 自定義的 item pipelines
ITEM_PIPELINES = {}
ITEM_PIPELINES_BASE = {}
日志相關的配置:
# 啟動日志功能
LOG_ENABLED = True
# 日志編碼
LOG_ENCODING = 'utf-8'
# 日志格式器
LOG_FORMATTER = 'scrapy.logformatter.LogFormatter'
# 日志格式
LOG_FORMAT = '%(asctime)s [%(name)s] %(levelname)s: %(message)s'
# 日志時間格式
LOG_DATEFORMAT = '%Y-%m-%d %H:%M:%S'
LOG_STDOUT = False
# 日志級別
LOG_LEVEL = 'DEBUG'
# 指定日志輸出文件
LOG_FILE = None
LOG_SHORT_NAMES = False
郵件配置:在 Scrapy 中提供了郵件功能,該功能使用十分簡便且采用了 Twisted 非阻塞模式,避免了對爬蟲的影響。我們只需要在 Scrapy 中進行簡單的設置,就能通過 API 發送郵件。郵件的默認配置項如下:
MAIL_HOST = 'localhost'
MAIL_PORT = 25
MAIL_FROM = 'scrapy@localhost'
MAIL_PASS = None
MAIL_USER = None
我們現在可以簡單的使用下 Scrapy 給我們提供的郵件類,來利用它給我們自己發送一封郵件。首先需要找下自己的 qq 郵箱或者其他郵箱,開啟 POP3/SMTP服務,然后我們可以得到一個授權碼。這個就是我們登陸這個郵箱服務的密碼。然后我們配置 settings.py 中的相應項:
MAIL_HOST = 'smtp.qq.com'
MAIL_PORT = 25
MAIL_FROM = '[email protected]'
MAIL_PASS = '你的授權碼'
MAIL_USER = '[email protected]'
接下來我們在 scrapy shell 中來調用相應的郵件接口,發送郵件:
(scrapy-test) [root@server china_pub]# scrapy shell --nolog
[s] Available Scrapy objects:
[s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s] crawler <scrapy.crawler.Crawler object at 0x7f1c3d4e9100>
[s] item {}
[s] settings <scrapy.settings.Settings object at 0x7f1c3d4e6dc0>
[s] Useful shortcuts:
[s] fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s] fetch(req) Fetch a scrapy.Request and update local objects
[s] shelp() Shell help (print this help)
[s] view(response) View response in a browser
>>> from scrapy.mail import MailSender
>>> mailer = MailSender().from_settings(settings)
>>> mailer.send(to=["[email protected]"], subject="這是一個測試", body="來自百度云主機發送的一封郵件", cc=["[email protected]"])
<Deferred at 0x7f1c3c4d1c40>
內存相關參數:
MEMDEBUG_ENABLED = False # enable memory debugging
MEMDEBUG_NOTIFY = [] # send memory debugging report by mail at engine shutdown
MEMUSAGE_CHECK_INTERVAL_SECONDS = 60.0
# 是否啟用內存使用擴展
MEMUSAGE_ENABLED = True
# 在關閉Scrapy之前允許的最大內存量,為0則不檢查
MEMUSAGE_LIMIT_MB = 0
# 要達到內存限制時通知的電子郵件列表
MEMUSAGE_NOTIFY_MAIL = []
# 在發送警告電子郵件通知之前,要允許的最大內存量(以兆字節為單位)。如果為零,則不會產生警告
MEMUSAGE_WARNING_MB = 0
調度器相關配置:
# 調度器類
SCHEDULER = 'scrapy.core.scheduler.Scheduler'
# 指定調度器的三種隊列類
SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleLifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.LifoMemoryQueue'
SCHEDULER_PRIORITY_QUEUE = 'scrapy.pqueues.ScrapyPriorityQueue'
# 正在處理響應數據的軟限制(以字節為單位),如果所有正在處理的響應的大小總和高于此值,Scrapy不會處理新的請求
SCRAPER_SLOT_MAX_ACTIVE_SIZE = 5000000
spider 中間件相關配置,有我們熟悉的 SPIDER_MIDDLEWARES
和 SPIDER_MIDDLEWARES_BASE
,表示自定義的 Spider 中間件和 Scrapy 內置的 Spider 中間件;
SPIDER_MIDDLEWARES = {}
SPIDER_MIDDLEWARES_BASE = {
# Engine side
'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 side
}
指定模板文件目錄,這個在使用 scrapy startproject 項目名
命令創建項目時,對應的模板文件所在的目錄:
TEMPLATES_DIR = abspath(join(dirname(__file__), '..', 'templates'))
USER_AGENT
:設置請求頭的 User-Agent
參數,用來模擬瀏覽器。我們通常都會添加一個瀏覽器的 User-Agent
值,防止爬蟲直接被屏蔽;
Scrapy 的大體配置就是這些,還有一些沒有介紹到的參數,課后可以仔細查看官方文檔進行了解。
2. 常見的優化配置參數
首先 scrapy 框架有一個命令 (bench) 來幫助我們測試本地環境的效率,它會在本地創建一個 HTTP 服務器,并以最大可能的速度進行爬取,這個模擬的 Spider 只會做跟進連接操作,而不做其他處理。我們來實際看看這個命令的執行效果:
(scrapy-test) [root@server qidian_yuepiao]# scrapy bench
# ...
2020-07-25 23:35:07 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 127918,
'downloader/request_count': 278,
'downloader/request_method_count/GET': 278,
'downloader/response_bytes': 666962,
'downloader/response_count': 278,
'downloader/response_status_count/200': 278,
'elapsed_time_seconds': 11.300798,
'finish_reason': 'closespider_timeout',
'finish_time': datetime.datetime(2020, 7, 25, 15, 35, 7, 370135),
'log_count/INFO': 21,
'memusage/max': 48553984,
'memusage/startup': 48553984,
'request_depth_max': 12,
'response_received_count': 278,
'robotstxt/request_count': 1,
'robotstxt/response_count': 1,
'robotstxt/response_status_count/200': 1,
'scheduler/dequeued': 277,
'scheduler/dequeued/memory': 277,
'scheduler/enqueued': 5540,
'scheduler/enqueued/memory': 5540,
'start_time': datetime.datetime(2020, 7, 25, 15, 34, 56, 69337)}
2020-07-25 23:35:07 [scrapy.core.engine] INFO: Spider closed (closespider_timeout)
在上面的執行日志中,我們可以很清楚的看到該命令會搜索 settings.py 中的配置并打印項目的基本信息以及啟用的擴展、下載中間件、Spider 中間件以及相應的 item pipelines。接下來是做的一些本地環境測試,測試顯示的是每分鐘平均能抓取1440個頁面,當然實際的爬蟲程序中需要有較多的處理,比如抽取頁面數據、過濾、去重以及保存到數據庫中,這些都是會消耗一定時間的。
現在來介紹一下 settings.py 中比較常見的一個優化配置:
-
并發控制:settings.py 中的
CONCURRENT_REQUESTS
參數用來確定請求的并發數,默認給的是16。而這個參數往往不適用于本地環境,我們需要進行調整。調整的方法是一開始設置一個比較大的值,比如100,然后進行測試,得到 Scrapy 的并發請求數與 CPU 使用率之間的關系,我們選擇大概使得 CPU 使用率在 80%~90% 對應的并發數,這樣能使得 Scrapy 爬蟲充分利用 CPU 進行網頁爬??; -
關閉 Cookie :這也是一個常見的優化策略。對于一些網站的請求,比如起點網、京東商城等, 不用登錄都可以任意訪問數據的,沒有必要使用 Cookie,使用 Cookie 而會增加 Scrapy 爬蟲的工作量。直接設置
COOKIES_ENABLED = False
即可關閉 Cookie; -
設置 Log 級別:將默認的 DEBUG 級別調整至 INFO 級別,減少不必要的日志打?。?/p>
-
關閉重試:默認情況下 Scrapy 會對失敗的請求進行重試,這種操作會減慢數據的爬取效率,因為對于海量的請求而言,丟失的數個甚至數百個請求都無關緊要;反而不必要的嘗試會影響爬蟲爬取效率;生產環境的做法最好是直接關閉,即
RETRY_ENABLED = False
; -
減少下載超時時間:對于響應很慢的網站,在超時時間結束前,Scrapy 會持續等到響應返回,這樣容易造成資源浪費。因此一個常見的優化策略是,減少超時時間,盡量讓響應慢的請求釋放資源。相應的參數設置示例如下:
DOWNLOAD_TIMEOUT = 3
-
關閉重定向:除非對重定向內容感興趣,否則可以考慮關閉重定向。關閉操作
REDIRECT_ENABLED = False
; -
自動調整爬蟲負載:我們啟用這個可以自動調節服務器負載的擴展程序,設置相關的參數,可以一定程度上優化爬蟲的性能;
AUTOTHROTTLE_ENABLED = False # 默認不啟用,可以設置為True并調整下面相關參數 AUTOTHROTTLE_DEBUG = False AUTOTHROTTLE_MAX_DELAY = 60.0 AUTOTHROTTLE_START_DELAY = 5.0 AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0
3. 小結
本小節中我們首先介紹了 settings.py 中的相關配置參數,先了解這些基礎的配置的含義,然后才知道如何選擇較合適的參數,這些對于 Scrapy 爬蟲性能有著較大的影響。當然這些性能變化可能在我們編寫的實驗性爬蟲中無法體現,但是對于真正的爬蟲公司而言,這些參數的調優對他們而言至關重要,甚至能決定公司的核心競爭力。為此,我們需要積極儲備相關知識,說不定會在未來有一天用的上。