Scrapy本身不支持分布式,因调度、去重、队列均依赖单机内存;Scrapy-Redis通过将Scheduler和DupeFilter状态外移至Redis共享存储,实现多机协同,用Redis列表/有序集合替代队列、集合结构实现全局去重,并支持断点续爬与负载均衡。

Scrapy 本身不支持分布式,所有调度、去重、队列都锁死在单机内存里;要让多台机器“看起来像一个爬虫”,必须把 Scheduler 和 DupeFilter 的状态外移到共享存储——Redis 就是那个被验证过最稳、最快、最轻量的选择。
Scrapy 单机队列为什么不能直接跨机器用
原生 Scrapy 的 scrapy.core.scheduler.Scheduler 依赖 Python 的 deque,所有请求排队、去重指纹都存在本机内存。这意味着:
- 两台机器各自跑一个 Scrapy 进程,它们的待抓 URL 队列完全隔离,毫无交集
- 同一 URL 可能在 A 机刚入队、B 机又推一遍,造成重复请求甚至被封 IP
- 任意一台机器宕机,它内存里的未完成请求就永久丢失,无法断点续爬
- 没有中心协调机制,根本谈不上“负载均衡”或“动态扩缩容”
Redis 如何替代内存队列和去重集合
Scrapy-Redis 不是简单地“用 Redis 存一下 URL”,而是按语义精准映射 Scrapy 内部组件:
-
SCHEDULER_QUEUE_CLASS="scrapy_redis.queue.PriorityQueue":用 Redis 有序集合(ZSET)实现带优先级的请求队列,分数对应Request.priority -
DUPEFILTER_CLASS="scrapy_redis.dupefilter.RFPDupeFilter":用 RedisSET存 URL 指纹(request_fingerprint()结果),所有节点查同一个 key -
REDIS_URL="redis://127.0.0.1:6379/0"必须显式配置,否则连接默认 localhost:6379 但可能连错 DB 或超时 - 队列操作实际走的是
LPUSH/BRPOP(FIFO)或ZADD/ZREVRANGE(优先级),不是直传字符串
常见踩坑点:配置对了,但还是不同步
现象:两台机器都启动了爬虫,但只有其中一台在干活,另一台一直空转;或者反复抓同一页面。
立即学习“Python免费学习笔记(深入)”;
- 没设
SCHEDULER_PERSIST = True:爬虫一停,Redis 里队列就被清空,新启进程从空队列开始,旧任务彻底消失 - Redis 密码或认证没配进
REDIS_URL,比如写成redis://:pwd@host:6379/0,漏了冒号或斜杠,连接静默失败 - 多个爬虫共用同一个
SPIDER_NAME,导致它们往 Redis 里写同一个队列 key(如myproject:requests),但实际应靠REDIS_PARAMS或命名空间隔离 - 本地开发时用了
SpiderQueue,但生产环境需要深度优先,却忘了改SCHEDULER_QUEUE_CLASS,结果广度遍历打爆目标站
真正难的不是把代码改成 Redis 版,而是理解哪些状态必须全局唯一(URL 队列、指纹集合)、哪些可以分片(items 存储、日志)、以及 Redis 的原子性边界在哪——比如 ZREM + ZRANGE 不是事务,高并发下仍需靠业务层兜底。


















