Python中scrapy使用什么方式管理任务队列,如何指定域名进行定时清除? [V 币感谢]
RT,我想知道基础 scrapy 是如何管理队列的,我大致猜测是根据自带的队列池,并不依赖任何中间件。
我的需求是:
一旦达到特定条件,清除指定域名的队列,不再爬含有该域名的 url。
比如达到某个访问频次,就根据域名去清除该域名的所有爬行请求,但不影响爬行队列里已经存在的含有其他域名的 url。
我这边现在的情况是,根据文本 txt,喂给 scrapy 一部分 url,其中包含多个域名。
由于一些特殊情况,不是很方便用 redis 挨个 push url,好像这个也不太好根据域名去清除 url 队列,不过实在要用也请大家给个方案。
Python中scrapy使用什么方式管理任务队列,如何指定域名进行定时清除? [V 币感谢]
你可以写个 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加自定义过滤器搞定。
中间件不满足抛弃的话,我那边也做了,但还是在爬触发了我条件的网站,不会停下对该域名的爬行的。
不知道您说的是不是这个:<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>
我这边需要是的是条件触发清除指定域名的队列,好像跟这个不太符合。


