Scrapy-Redis的核心机制是通过Redis实现分布式任务共享与去重:所有爬虫节点共用同一Redis实例,将Request存入共享队列(如myspider:start_urls),并用Redis Set存储URL指纹实现全局去重,从而替代Scrapy原生内存调度器和去重器。

Scrapy-Redis 的核心机制是什么?
Scrapy 本身不支持分布式,Scrapy-Redis 是通过把 Request 和 dupefilter(去重指纹)存到 Redis 实现任务共享。所有爬虫实例都从同一个 redis_key(如 myproject:start_urls)里取 Request,用 RedisDupeFilter 判断是否已抓过,从而避免重复。
- 不是靠 Scrapy 自带的
Scheduler分发,而是靠 Redis 的LPUSH/BRPOP队列行为 - 所有节点必须共用同一套
REDIS_URL,且网络互通、权限开放 -
start_urls必须显式推入 Redis,不能只靠start_requests()返回——否则只在单机生效
如何正确配置 Scrapy-Redis 的 settings.py?
关键不是加几行代码,而是替换掉 Scrapy 原生调度与去重逻辑:
- 把
SCHEDULER换成"scrapy_redis.scheduler.Scheduler" - 把
DUPEFILTER_CLASS换成"scrapy_redis.dupefilter.RFPDupeFilter" - 必须设置
REDIS_URL = "redis://:password@192.168.1.100:6379/0"(含密码和 IP) - 加上
SCHEDULER_PERSIST = True,否则爬虫退出时队列清空 -
ROBOTSTXT_OBEY = False建议关掉,否则不同机器可能因 robots.txt 解析差异漏任务
注意:ITEM_PIPELINES 里的 scrapy_redis.pipelines.RedisPipeline 只是可选——它会把 item 写进 Redis,但多数场景你更倾向直接存数据库或文件。
启动多个爬虫实例时常见失败原因
分布式跑不起来,90% 出在环境一致性上:
立即学习“Python免费学习笔记(深入)”;
- 各机器的
scrapy、scrapy-redis、redis-py版本不一致,尤其是scrapy-redis==0.7.2以上才稳定支持 Scrapy 2.0+ - Redis 未开启远程访问:
bind 127.0.0.1要改成bind 0.0.0.0,并确认protected-mode no - 爬虫名(
name = "myspider")必须完全相同,否则各实例监听的 redis key 默认为myspider:requests,名字不一致就互相看不见 - 没手动 push URL:执行
redis-cli -h 192.168.1.100 lpush myspider:start_urls "<a href="https://www.php.cn/link/b05edd78c294dcf6d960190bf5bde635">https://www.php.cn/link/b05edd78c294dcf6d960190bf5bde635</a>",而不是靠scrapy crawl myspider自动加载 - 日志里出现
ConnectionRefusedError或redis.exceptions.AuthenticationError,说明连接参数写错,优先检查REDIS_URL中的 host/port/password/db
如何安全地扩缩容爬虫节点?
加机器很简单,但删机器容易丢任务:
- 新节点只需部署代码 + 相同配置 + 运行
scrapy crawl myspider,自动接入队列 - 下线节点前,先确认其正在处理的
Request已完成或超时(RETRY_TIMES起作用),否则该请求会卡在in_progress状态 - 不要直接 kill -9,建议用
scrapy stop或发 SIGTERM,让Scheduler有机会把未完成 request 回写回队列(依赖SCHEDULER_FLUSH_ON_START = False) - 如果某节点异常宕机,它的
in_progress集合里残留的 request ID 会一直占位——需要定期用脚本清理过期项,或启用SCHEDULER_IDLE_BEFORE_CLOSE = 10配合心跳检测
Redis 里没事务、没 TTL 自动清理,所有“状态”都靠业务逻辑维护。这点最容易被忽略。


















