Scrapy-Redis的dupefilter失效根本原因是未禁用Scrapy默认内存去重中间件,必须显式配置DUPEFILTER_CLASS为scrapy_redis.dupefilter.RFPDupeFilter并确保REDIS_URL连通,否则会静默退化为内存去重。

Scrapy-Redis 的 dupefilter 为什么总失效?
根本原因不是配置错,而是你没关掉 Scrapy 自带的去重中间件。Scrapy 默认启用 RFPDupeFilter,它只在单机内存里去重,和 Redis 无关;而 scrapy_redis.dupefilter.RFPDupeFilter 才是真正写进 Redis 的版本。
实操上必须做两件事:
- 在
settings.py中把DUPEFILTER_CLASS明确设为scrapy_redis.dupefilter.RFPDupeFilter - 注释或删掉
DUPEFILTER_CLASS = 'scrapy.dupefilters.RFPDupeFilter'这类残留配置(哪怕被覆盖也容易引发混淆) - 确保
REDIS_URL可连通,否则去重会静默退化回内存模式——你看到重复请求,其实是 Redis 写失败了,但日志不报错
多个爬虫共用一个 start_urls 队列时,怎么避免任务争抢?
Scrapy-Redis 默认用的是 spiders 模式:所有爬虫实例监听同一个 Redis list(如 myproject:start_urls),靠 Redis 的 BRPOP 原子操作实现天然并发安全——这不是“避免争抢”,而是“靠 Redis 保证不会争抢”。
但要注意三个实际坑点:
- 别手动生成 URL 后直接
rpush到队列,要用scrapy_redis.spiders.RedisSpider提供的redis_key属性,否则可能推到错误 key - 如果不同爬虫逻辑需要不同解析方式,不要共用一个 spider 类,而应继承
RedisSpider分别定义各自的parse方法,并设置各自独立的redis_key - 启动多个 worker 时,确保它们加载的是同一份
settings.py,尤其REDIS_URL和SCHEDULER_QUEUE_KEY必须一致,否则看似在跑分布式,实则各干各的
scrapy_redis.scheduler.Scheduler 的持久化开关怎么选?
关键参数是 SCHEDULER_PERSIST,它控制 Redis 里的请求队列是否在爬虫退出后保留。设为 True 适合断点续爬,False(默认)适合一次性任务。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
但很多人忽略副作用:
- 设为
True后,每次重启爬虫前得手动清空 Redis 队列(DEL myproject:requests),否则旧任务会反复执行 - 如果同时跑多个不同项目的爬虫,且都用了默认
redis_key格式,容易互相污染——建议显式配置SCHEDULER_QUEUE_KEY = 'myproject:requests' -
SCHEDULER_FLUSH_ON_START = True可以替代手动清空,但它只在 spider 初始化时触发,如果进程异常退出未走完生命周期,该 flush 不会执行
为什么加了 Redis 后反而比单机还慢?
常见于小规模任务或低配 Redis 实例。根本矛盾在于:Scrapy-Redis 把每个请求的入队、出队、去重都变成一次网络 IO,而单机模式下这些都在内存完成。
优化方向很具体:
- 检查 Redis 是否和爬虫部署在同一局域网,跨公网调用 Redis 延迟常超 50ms,直接拖垮吞吐
- 关闭
LOG_LEVEL = 'DEBUG',DEBUG 日志会高频打 Redis info 命令,形成额外负载 - 对简单页面,考虑用
scrapy_redis.pipelines.RedisPipeline直接存原始 HTML,而不是先 parse 再存结构化数据——减少 CPU 解析时间,让瓶颈留在网络而非本地 - 如果只是想提升并发数,不一定要上 Redis:先调大
CONCURRENT_REQUESTS和DOWNLOAD_DELAY,配合合理AUTO_THROTTLE,往往比加 Redis 更快
分布式不是银弹。当你的目标网站 QPS 不超过 20,或者 Redis 响应 P99 > 15ms,那所谓“分布式”大概率是在给架构添堵。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










