Python中如何主动关闭Scrapy爬虫框架?

背景:

  1. 有一个视频网站,需要登录,由于有 recaptcha 和 fingerprint 存在,模拟登录不太会,所以手动写入 cookie 到代码中去实现登录
  2. 固定的位置的 json 文件,会存储视频的相关信息,格式是{"url":"视频名称"}
  3. 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爬虫框架?

7 回复

求教求教


在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

还有几个别的招儿:

  1. 在Spider里直接抛 CloseSpider 异常:
from scrapy.exceptions import CloseSpider

def parse(self, response):
    if some_condition:
        raise CloseSpider('reason_here')
  1. 用扩展(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

回到顶部