Scrapy作业:暂停与继续爬取

Scrapy作业:暂停与继续爬取

抓取大型网站时,有时希望暂停爬取,并在之后继续。

Scrapy通过以下内置机制支持这一功能:

  • 将已调度的请求持久化到磁盘的调度器。
  • 将已访问请求持久化到磁盘的去重过滤器。
  • 在批次之间持久保存部分爬虫状态(键值对)的扩展。

作业目录

要启用持久化支持,通过JOBDIR设置指定一个作业目录。

这个目录保存维持单个作业(即一次爬虫运行)状态所需的全部数据,因此只要正常停止,稍后就可以继续运行。

另见作业目录的内容。

如何使用

要启动启用持久化支持的爬虫,运行:

scrapy crawl somespider -s JOBDIR=crawls/somespider-1

此后可以随时安全停止爬虫(按Ctrl-C或发送信号),之后再次执行相同的命令即可继续:

scrapy crawl somespider -s JOBDIR=crawls/somespider-1

根据爬虫名称生成作业目录

将不同作业目录分开的方法之一,是在scrapy.Spider.update_settings()中构建路径,让一组爬虫使用除爬虫名称之外均相同的路径:

from pathlib import Path

from scrapy import Spider


class BaseSpider(Spider):
    @classmethod
    def update_settings(cls, settings):
        super().update_settings(settings)
        settings.set("JOBDIR", str(Path("crawls", cls.name)), priority="spider")

在暂停和继续运行的批次之间保存状态

有时需要在暂停与继续运行的批次之间持久保存爬虫状态。为此可使用spider.state属性,其值应为字典。Scrapy有一个内置扩展:在爬虫启动和停止时,负责将该属性序列化、存储到作业目录,以及从目录加载。

下面是使用爬虫状态的回调示例,其他爬虫代码为简洁起见省略:

def parse_item(self, response):
    # parse item here
    self.state["items_count"] = self.state.get("items_count", 0) + 1

持久化的注意事项

使用Scrapy的持久化支持时,需要注意以下事项。

暂停的限制

只有通过正常停止爬虫来暂停时,才支持暂停与继续。强制、突然或其他非正常关闭可能使作业目录中的数据损坏,导致爬虫无法正确继续运行。

Scrapy版本变化

作业目录的内容属于写入该目录的Scrapy版本的实现细节。继续作业时必须使用暂停作业时的同一个Scrapy版本;升级或降级Scrapy后,应使用新的作业目录启动新作业。

Cookie过期

Cookie可能过期,因此如果没有很快恢复爬虫,已调度的请求可能不再有效。如果爬虫不依赖Cookie,就不会有这个问题。

请求序列化

要实现持久化,scrapy.Request对象必须可以通过pickle序列化,但传入其__init__方法的callback与errback值除外:它们必须是正在运行的scrapy.Spider类的方法。

无法序列化的请求只保存在内存中:它们仍会被发送,但暂停爬取时会丢失。

如果希望记录无法序列化的请求,可以在项目设置中将SCHEDULER_DEBUG设为True,其默认值为False。

作业目录的内容

作业目录的内容取决于作业所使用的组件。已知会写入该目录的组件包括调度器和scrapy.extensions.spiderstate.SpiderState扩展。详细信息请参阅相应组件的参考文档。

例如在默认设置下,作业目录可能如下所示:

├── requests.queue
|   ├── active.json
|   └── {hostname}-{hash}
|       └── {priority}{s?}
|           ├── q{00000}
|           └── info.json
├── requests.seen
└── spider.state

其中:

  • scrapy.core.scheduler.Scheduler创建requests.queue/目录与active.json文件。后者保存上一次暂停作业时DownloaderAwarePriorityQueue.close()返回的状态数据。
  • scrapy.pqueues.DownloaderAwarePriorityQueue创建{hostname}-{hash}目录。
  • scrapy.pqueues.ScrapyPriorityQueue创建{priority}{s?}目录。
  • scrapy.squeues.PickleFifoDiskQueue是queuelib.FifoDiskQueue的子类,使用pickle序列化scrapy.Request对象的dict表示,并创建info.json与q{00000}文件。
  • scrapy.dupefilters.RFPDupeFilter创建requests.seen文件。
  • scrapy.extensions.spiderstate.SpiderState扩展创建spider.state文件。

来源与许可

来源:Scrapy官方文档:Jobs: pausing and resuming crawls,Scrapy开发者。本版为中文翻译。项目版权与BSD许可见官方LICENSE;完整版权、条件与免责声明随来源文件保留。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容