Python中如何主动关闭Scrapy爬虫框架?
背景:
- 有一个视频网站,需要登录,由于有 recaptcha 和 fingerprint 存在,模拟登录不太会,所以手动写入 cookie 到代码中去实现登录
- 固定的位置的 json 文件,会存储视频的相关信息,格式是{"url":"视频名称"}
- json 文件中存储的 url 是视频播放页面,这个页面不需要登录,可以直接解析出来真实的视频地址
我的逻辑是这样的:
如果代码中设置的 Cookie 失效或者没设置,就直接从指定的位置读 json 文件。然后请求文件中的 url,解析出来真实的视频地址,放到 pipeline 中下载
如果代码中设置的 cookie 有效,那么就分析视频列表页面,将结果写入 json 文件,然后读取文件下载
所以,我在第一段逻辑中需要设置一个关闭 scrapy,这部分代码如下
if 'login.php' in response.url:
self.logger.warn('cookie 失效,直接用 follow.json 下载')
with open('myfollowinfo/follow.json') as f:
movie_info = json.loads(f.read())
self.logger.warn('文件中保存了{0}个视频'.format(len(movie_info)))
for link, title in movie_info.items():
yield scrapy.Request(url=link, callback=self.parse_my_follow_real_link)
raise CloseSpider(self.crawler)
由于我不知道下载视频需要多久,所以我是不能设置 CLOSESPIDER_TIMEOUT 的值的,所以根据 scrapy 的代码逻辑,会抛出 NotConfigured 异常
请问我目前这种需求应该怎么做呢?
Python中如何主动关闭Scrapy爬虫框架?
在Scrapy里主动关爬虫,最直接的就是在Spider里调用 self.crawler.engine.close_spider()。
比如你想抓够100条数据就停,可以这么写:
import scrapy
class MySpider(scrapy.Spider):
name = 'my_spider'
item_count = 0
max_items = 100
def start_requests(self):
# 你的起始请求
yield scrapy.Request('http://example.com', callback=self.parse)
def parse(self, response):
# 解析逻辑,生成item
item = {'data': 'some data'}
self.item_count += 1
if self.item_count >= self.max_items:
self.crawler.engine.close_spider(self, 'item_limit_reached')
yield item
或者你想在Pipeline里根据条件关,比如数据存数据库失败了:
class MyPipeline:
def process_item(self, item, spider):
try:
# 存数据库
pass
except SomeCriticalError:
spider.crawler.engine.close_spider(spider, 'db_error')
return item
还有几个别的招儿:
- 在Spider里直接抛
CloseSpider异常:
from scrapy.exceptions import CloseSpider
def parse(self, response):
if some_condition:
raise CloseSpider('reason_here')
- 用扩展(Extension)的
spider_idle信号:
from scrapy import signals
from scrapy.exceptions import NotConfigured
class CloseSpiderExtension:
def __init__(self, crawler):
self.crawler = crawler
crawler.signals.connect(self.spider_idle, signal=signals.spider_idle)
@classmethod
def from_crawler(cls, crawler):
return cls(crawler)
def spider_idle(self, spider):
if should_close(spider):
self.crawler.engine.close_spider(spider, 'idle_condition_met')
简单说就是:在需要的地方调 close_spider() 或者抛 CloseSpider 异常。
不是很懂你的两个逻辑,不过你试试获取登陆过后的 cookie,然后带这个 cookie 请求,不会那么容易失效的
简单说就是 我想在代码中的 if 条件真的时候,只执行 if 内的语句,剩下的这些都不执行,也就是说能不能有什么方法,让 if 里边的 yield scrapy.Request()这个都跑完然后关闭爬虫
设置 timeout
Request()跑完不是会自动关闭吗
去看官方文档,Extensions 这部分。https://scrapy-chs.readthedocs.io/zh_CN/0.24/topics/extensions.html
简单来说,setting 设置接收数据的信号收发标记,一段时间数据为空,自动关闭 scrapy


