Python中scrapy使用什么方式管理任务队列,如何指定域名进行定时清除? [V 币感谢]

RT,我想知道基础 scrapy 是如何管理队列的,我大致猜测是根据自带的队列池,并不依赖任何中间件。

我的需求是:

一旦达到特定条件,清除指定域名的队列,不再爬含有该域名的 url。
比如达到某个访问频次,就根据域名去清除该域名的所有爬行请求,但不影响爬行队列里已经存在的含有其他域名的 url。

我这边现在的情况是,根据文本 txt,喂给 scrapy 一部分 url,其中包含多个域名。

由于一些特殊情况,不是很方便用 redis 挨个 push url,好像这个也不太好根据域名去清除 url 队列,不过实在要用也请大家给个方案。


Python中scrapy使用什么方式管理任务队列,如何指定域名进行定时清除? [V 币感谢]

5 回复

你可以写个 Downloader Middleware, 然后在处理 request 时根据你的条件判断, 如果不满足就抛弃


Scrapy默认用内存队列管理请求,但生产环境建议用scrapy-redis。它用Redis做分布式队列,还能持久化任务。

要按域名定时清理,可以在custom_settings里配DUPEFILTER_CLASS,自己写个带过期逻辑的过滤器。下面是个完整示例:

# settings.py
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
DUPEFILTER_CLASS = "myproject.dupefilter.DomainExpireRFPDupeFilter"
SCHEDULER_PERSIST = True

# dupefilter.py
from scrapy_redis.dupefilter import RFPDupeFilter
from datetime import datetime, timedelta

class DomainExpireRFPDupeFilter(RFPDupeFilter):
    def __init__(self, server, key, timeout=86400):
        self.domain_timeout = timeout  # 默认24小时
        super().__init__(server, key)

    def request_seen(self, request):
        # 生成域名级别的指纹
        domain = request.url.split('/')[2]
        domain_fp = hash(domain)
        
        # 检查是否已有该域名的记录
        if self.server.get(domain_fp):
            return True
        
        # 记录域名并设置过期时间
        self.server.setex(domain_fp, self.domain_timeout, '1')
        
        # 继续默认的请求去重逻辑
        return super().request_seen(request)

这样同一个域名在24小时内不会重复抓取,超时后自动清除记录。

总结:用scrapy-redis加自定义过滤器搞定。

Scrapy-Redis 有个功能是动态切换域名,不知道是不是你想要的。

中间件不满足抛弃的话,我那边也做了,但还是在爬触发了我条件的网站,不会停下对该域名的爬行的。

不知道您说的是不是这个:
<br>#动态域范围的获取<br>def __init__(self, *args, **kwargs):<br> # Dynamically define the allowed domains list.<br> domain = kwargs.pop('domain', '')<br> self.allowed_domains = filter(None, domain.split(','))<br> super(MySpider, self).__init__(*args, **kwargs)<br>
我这边需要是的是条件触发清除指定域名的队列,好像跟这个不太符合。

回到顶部