作业:暂停并恢复爬行¶
有时,对于一些大型网站,需要中途暂停并在某个时间继续爬取。
使用以下工具,Scrapy可以实现这种开箱即用的这种功能,
- 将请求列表保存到磁盘的一种调度程序
- 在磁盘上保存已经请求过的一种过滤器
- 一个能持续保持爬虫状态(键/值对)的扩展
Job 路径¶
要启动持久化功能你只需通过 JOBDIR
设置一个 job directory 选项。这个路径会存储
所有的请求数据来保持一个单独任务的状态(如:一次爬虫)。需要注意的是,这个路径不能被
不同的爬虫之共享,或者一个爬虫中的不同的 jobs/runs。这意味着它只能保存一个 单独 任务的
状态。
如何使用¶
启用持久功能来开始一个爬虫, 按照以下方式运行:
scrapy crawl somespider -s JOBDIR=crawls/somespider-1
然后,你可以在任何时间使用安全方式停止爬虫 (使用 Ctrl-C 或者发送一个 信号), 并可以使用相同的命令来继续爬虫:
scrapy crawl somespider -s JOBDIR=crawls/somespider-1
保持状态¶
有时你想保持一些爬虫的状态。你可以使用 spider.state
属性来实现,这个属性必需是
一个字典。Scrapy提供了一个内置扩展负责在爬虫开始和停止的时候从 job路径 序列化、存储并加载这个属性。
这里有一个例子使用了爬虫状态来进行回调(简洁起见省略了其它爬虫代码):
def parse_item(self, response):
# parse item here
self.state['items_count'] = self.state.get('items_count', 0) + 1
持久化的一些事项¶
如果你想启用Scrapy持久化,以下几条你需要注意:
Cookies 有效期¶
Cookies 会过期。 因此,如果你没有尽快恢复爬虫,请求请求调度器可能不再工作。 如果你的爬虫不依赖cookies这也不是问题。
请求序列化¶
请求需要被 pickle
模块序列化,你需要确保你的请求可以被序列化以确保可以
持续运行。
最常见的问题是在requests回调函数中使用 lambda
函数,导致无法被序列化。
以下操作将无法工作:
def some_callback(self, response):
somearg = 'test'
return scrapy.Request('http://www.example.com', callback=lambda r: self.other_callback(r, somearg))
def other_callback(self, response, somearg):
print("the argument passed is: %s" % somearg)
但是可以这样:
def some_callback(self, response):
somearg = 'test'
return scrapy.Request('http://www.example.com', callback=self.other_callback, meta={'somearg': somearg})
def other_callback(self, response):
somearg = response.meta['somearg']
print("the argument passed is: %s" % somearg)
如果你想记录这些没有被序列化的请求, 你可以在项目中设置 SCHEDULER_DEBUG
选项为 True
。
它默认是 False
。