大规模爬取
Scrapy 的默认设置针对抓取特定网站进行了优化。这些网站通常由单个 Scrapy 爬虫处理,尽管这不是必需或强制的(例如,存在可以处理任何给定网站的通用爬虫)。
除了这种“聚焦爬取”之外,还有另一种常见的爬取类型,它涵盖了大量(可能无限)的域,并且仅受时间或其他任意限制,而不是在域爬取完成或没有更多请求可执行时停止。这些被称为“大规模爬取”,是搜索引擎常用的爬虫。
大规模爬取通常具有以下常见特性:
它们爬取许多域(通常是无限制的),而不是特定的网站集
它们不一定会将域爬取至完成,因为这样做不切实际(或不可能),而是通过时间或爬取页面数量来限制爬取
它们的逻辑更简单(与具有许多提取规则的复杂爬虫相反),因为数据通常在单独的阶段进行后处理
它们并发爬取许多域,这使得它们能够通过不受任何特定网站限制来提高爬取速度(每个网站都缓慢爬取以尊重礼貌,但许多网站并行爬取)
如上所述,Scrapy 的默认设置针对聚焦爬取进行了优化,而非大规模爬取。然而,由于其异步架构,Scrapy 非常适合执行快速大规模爬取。本页总结了使用 Scrapy 进行大规模爬取时需要记住的一些事项,并提供了调整 Scrapy 设置以实现高效大规模爬取的具体建议。
提高并发量
并发量是并行处理的请求数量。有一个全局限制(CONCURRENT_REQUESTS)以及一个可以按域设置的额外限制(CONCURRENT_REQUESTS_PER_DOMAIN)。
Scrapy 的默认全局并发限制不适合并行抓取许多不同的域,因此您会想要增加它。增加多少将取决于您的爬虫有多少可用的 CPU 和内存。
一个好的起点是 100
CONCURRENT_REQUESTS = 100
但最好的方法是通过进行一些试验并确定您的 Scrapy 进程在哪个并发量下受限于 CPU。为了获得最佳性能,您应该选择一个 CPU 使用率在 80-90% 的并发量。
增加并发量也会增加内存使用。如果内存使用是一个问题,您可能需要相应地降低您的全局并发限制。
增加 Twisted IO 线程池最大尺寸
目前 Scrapy 使用线程池以阻塞方式进行 DNS 解析。在更高的并发级别下,爬取可能会变慢,甚至可能因达到 DNS 解析器超时而失败。一个可能的解决方案是增加处理 DNS 查询的线程数。DNS 队列将处理得更快,从而加快连接的建立和整体爬取速度。
要增加线程池的最大大小,请使用
REACTOR_THREADPOOL_MAXSIZE = 20
设置自己的 DNS
如果您有多个爬取进程和单个中央 DNS,这可能会对 DNS 服务器造成类似 DoS 攻击的影响,导致整个网络变慢甚至阻止您的机器。为避免这种情况,请设置您自己的 DNS 服务器,带有本地缓存并上游到一些大型 DNS,如 OpenDNS 或 Verizon。
降低日志级别
进行大规模爬取时,您通常只对获得的爬取速率和发现的任何错误感兴趣。当使用 INFO 日志级别时,Scrapy 会报告这些统计数据。为了节省 CPU(和日志存储要求),在生产环境中执行大规模爬取时不应使用 DEBUG 日志级别。但在开发您的(大规模)爬虫时使用 DEBUG 级别可能是可以的。
要设置日志级别,请使用
LOG_LEVEL = "INFO"
禁用重试
重试失败的 HTTP 请求会大大减慢爬取速度,尤其是当网站响应非常慢(或失败)时,从而导致超时错误被不必要地重试多次,阻止爬虫容量被用于其他域。
要禁用重试,请使用
RETRY_ENABLED = False
缩短下载超时
除非您是从非常慢的连接进行爬取(对于大规模爬取不应该出现这种情况),否则请缩短下载超时,以便快速丢弃卡住的请求,并释放容量来处理下一个请求。
要缩短下载超时,请使用
DOWNLOAD_TIMEOUT = 15
禁用重定向
考虑禁用重定向,除非您有兴趣跟踪它们。在进行大规模爬取时,通常会保存重定向并在稍后的爬取中重新访问网站时解决它们。这也有助于保持每个爬取批次的请求数量恒定,否则重定向循环可能会导致爬虫将过多资源投入到任何特定域上。
要禁用重定向,请使用
REDIRECT_ENABLED = False
以 BFO 顺序爬取
然而,在大规模爬取中,页面爬取往往比页面处理更快。结果,未处理的早期请求会保留在内存中,直到达到最终深度,这会显著增加内存使用量。
改为以 BFO 顺序爬取以节省内存。
注意内存泄漏
如果您的广域爬取显示出高内存使用量,除了以 BFO 顺序爬取和降低并发量之外,您还应该调试内存泄漏。
安装特定的 Twisted reactor
如果爬取超出了系统的能力,您可能需要尝试通过 TWISTED_REACTOR 设置安装特定的 Twisted reactor。