Lzh on GitHub

Broad Crawls (广度爬取)

Scrapy 的默认设置针对抓取特定网站进行了优化。这些网站通常由单个 Scrapy 爬虫处理,尽管这并非必要或强制(例如,有一些通用爬虫可以处理任何给定的网站)。

除了这种“聚焦爬取”之外,还有另一种常见的爬取类型,它涵盖了大量(可能无限)的域,并且仅受时间或其他任意约束的限制,而不是在域被完全抓取或没有更多请求可执行时停止。这些被称为“广度爬取”,是搜索引擎采用的典型爬虫。

广度爬取通常具有以下一些共同特性:

  • 它们抓取许多域(通常是无限制的),而不是特定的一组网站。
  • 它们不一定抓取域直到完成,因为这样做不切实际(或不可能),而是通过时间或抓取页面数量来限制爬取。
  • 它们的逻辑更简单(与具有许多提取规则的非常复杂的爬虫相反),因为数据通常在单独的阶段进行后处理。
  • 它们同时抓取许多域,这使得它们能够通过不受任何特定站点约束的限制来实现更快的爬取速度(每个站点都被缓慢抓取以尊重礼貌,但许多站点并行抓取)。

如上所述,Scrapy 的默认设置针对聚焦爬取进行了优化,而不是广度爬取。然而,由于其异步架构,Scrapy 非常适合执行快速广度爬取。本页总结了使用 Scrapy 进行广度爬取时需要记住的一些事项,以及为了实现高效广度爬取而调整 Scrapy 设置的具体建议。

Use the right SCHEDULER_PRIORITY_QUEUE (使用正确的 SCHEDULER_PRIORITY_QUEUE)

Scrapy 的默认调度器优先级队列是 'scrapy.pqueues.ScrapyPriorityQueue'。它在单域爬取期间效果最佳。它不适用于并行爬取许多不同的域。

要应用推荐的优先级队列,请使用:

SCHEDULER_PRIORITY_QUEUE = "scrapy.pqueues.DownloaderAwarePriorityQueue"

Increase concurrency (增加并发性)

并发性是并行处理的请求数量。有一个全局限制(CONCURRENT_REQUESTS)和一个可以按域(CONCURRENT_REQUESTS_PER_DOMAIN)或按 IP(CONCURRENT_REQUESTS_PER_IP)设置的额外限制。

注意

推荐用于广度爬取的调度器优先级队列不支持 CONCURRENT_REQUESTS_PER_IP

Scrapy 的默认全局并发限制不适用于并行爬取许多不同的域,因此您需要增加它。增加多少将取决于您的爬虫将有多少可用的 CPU 和内存。

一个好的起点是 100

CONCURRENT_REQUESTS = 100

但找出最佳值的方法是进行一些试验,并确定您的 Scrapy 进程在何种并发程度下会受到 CPU 限制。为了获得最佳性能,您应该选择 CPU 使用率在 80-90% 的并发程度。

增加并发性也会增加内存使用。如果内存使用是一个问题,您可能需要相应地降低全局并发限制。

Increase Twisted IO thread pool maximum size (增加 Twisted IO 线程池最大大小)

目前 Scrapy 使用线程池以阻塞方式进行 DNS 解析。在更高的并发级别下,爬取可能会变慢甚至因为达到 DNS 解析器超时而失败。可能的解决方案是增加处理 DNS 查询的线程数。DNS 队列将更快地处理,从而加快连接建立和整体爬取速度。

要增加最大线程池大小,请使用:

REACTOR_THREADPOOL_MAXSIZE = 20

Setup your own DNS (设置您自己的 DNS)

如果您有多个爬取进程和单个中央 DNS,它可能会对 DNS 服务器造成 DoS 攻击,从而导致整个网络变慢甚至阻止您的机器。为避免这种情况,请设置您自己的带有本地缓存的 DNS 服务器,并向上游连接到 OpenDNS 或 Verizon 等大型 DNS。

Reduce log level (降低日志级别)

在进行广度爬取时,您通常只对获得的爬取率和发现的任何错误感兴趣。Scrapy 在使用 INFO 日志级别时会报告这些统计数据。为了节省 CPU(和日志存储需求),在生产环境中执行大型广度爬取时,不应使用 DEBUG 日志级别。但在开发您的(广度)爬虫时,使用 DEBUG 级别可能没问题。

要设置日志级别,请使用:

LOG_LEVEL = "INFO"

除非您真的需要,否则请禁用 cookie。在进行广度爬取时通常不需要 cookie(搜索引擎爬虫会忽略它们),并且它们通过节省一些 CPU 周期和减少 Scrapy 爬虫的内存占用来提高性能。

要禁用 cookie,请使用:

COOKIES_ENABLED = False

Disable retries (禁用重试)

重试失败的 HTTP 请求会大大减慢爬取速度,特别是当站点响应非常慢(或失败)时,从而导致超时错误并被多次不必要地重试,阻止爬虫容量被其他域重复使用。

要禁用重试,请使用:

RETRY_ENABLED = False

Reduce download timeout (缩短下载超时)

除非您正在从非常慢的连接进行爬取(广度爬取不应该出现这种情况),否则请缩短下载超时,以便快速丢弃卡住的请求并释放容量以处理下一个请求。

要缩短下载超时,请使用:

DOWNLOAD_TIMEOUT = 15

Disable redirects (禁用重定向)

考虑禁用重定向,除非您有兴趣跟踪它们。在进行广度爬取时,通常会保存重定向并在稍后的爬取中重新访问站点时解析它们。这也有助于保持每个爬取批次的请求数量恒定,否则重定向循环可能会导致爬虫在任何特定域上占用过多资源。

要禁用重定向,请使用:

REDIRECT_ENABLED = False

Crawl in BFO order (按 BFO 顺序爬取)

Scrapy 默认按 DFO(深度优先)顺序爬取。

然而,在广度爬取中,页面爬取往往比页面处理更快。因此,未处理的早期请求会保留在内存中,直到达到最终深度,这会显著增加内存使用量。

相反,按 BFO(广度优先)顺序爬取以节省内存

Be mindful of memory leaks (注意内存泄漏)

如果您的广度爬取显示内存使用量很高,除了按 BFO 顺序爬取降低并发性之外,您还应该调试内存泄漏

Install a specific Twisted reactor (安装特定的 Twisted reactor)

如果爬取超出系统的能力,您可能需要尝试通过 TWISTED_REACTOR 设置安装特定的 Twisted reactor。