当前位置: 首页 > news >正文

Scrapy-Redis 分布式爬虫实战——从单机到集群

上一篇用 Scrapy 实现了单机爬虫,能爬几千页没问题。但当数据量达到几十万、上百万页时,单机就有瓶颈了——爬取速度不够、IP 容易被封、爬了一半挂了还要重新来。

用 Scrapy-Redis 做分布式,几台机器一起爬,速度翻倍,还自带断点续爬。

一、分布式爬虫的原理

单机 Scrapy 的请求队列在内存里,A 机器爬过的 B 机器不知道。分布式就是把请求队列放到Redis中,所有机器共享。

单机模式: 爬虫A → 内存队列 → 下载 → 解析 爬虫B → 内存队列 → 下载 → 解析 (各爬各的,互不通信) 分布式模式: Redis 请求队列(所有爬虫共享) ↑↓ ↑↓ ↑↓ 爬虫A 爬虫B 爬虫C (请求被分配,不会重复爬)

核心优势:

  • 爬取速度 = 机器数 × 单机速度(近似)
  • 天然去重:Redis 集合保证同一个 URL 不会被爬两次
  • 断点续爬:Redis 里的队列不会丢失,重启爬虫接着爬

二、安装与配置

1. 安装

pipinstallscrapy-redis

确保 Redis 已经安装并启动。

2. 配置 settings.py

# 使用 Scrapy-Redis 的调度器(替代默认的内存调度器)SCHEDULER="scrapy_redis.scheduler.Scheduler"# 使用 Redis 去重组件(替代默认的内存去重)DUPEFILTER_CLASS="scrapy_redis.dupefilter.RFPDupeFilter"# Redis 连接配置REDIS_HOST="localhost"# Redis 服务器地址REDIS_PORT=6379REDIS_PARAMS={"password":"",# Redis 密码"db":0,}# 持久化请求队列(爬虫停了以后不清空)SCHEDULER_PERSIST=True# 爬虫停止后是否清空去重集合(建议 True,避免内存堆积)SCHEDULER_FLUSH_ON_START=False# 可选:从 Redis 中读取起始 URLREDIS_START_URLS_AS_SET=True

3. 修改爬虫代码

# spiders/quotes.pyfromscrapy_redis.spidersimportRedisSpider# 原来继承 scrapy.Spider,现在继承 RedisSpiderclassQuotesSpider(RedisSpider):name="quotes"# 不再写 start_urls,而是从 Redis 读取redis_key="quotes:start_urls"defparse(self,response):# 解析逻辑和单机时完全一样forquoteinresponse.css("div.quote"):yield{"text":quote.css("span.text::text").get(),"author":quote.css("small.author::text").get(),}# 翻页next_page=response.css("li.next a::attr(href)").get()ifnext_page:yieldresponse.follow(next_page,callback=self.parse)

关键区别:继承从scrapy.Spider改为scrapy_redis.spiders.RedisSpider,不再写start_urls,改为redis_key

三、启动分布式爬虫

第一步:启动爬虫(所有机器都执行)

# 两台机器上都执行,它们都会去连同一个 Redisscrapy crawl quotes

此时爬虫启动后会等待——因为 Redis 里还没有起始 URL。

第二步:向 Redis 推送起始 URL

在任意一台机器上执行:

# 向 Redis 的 quotes:start_urls 集合中插入起始 URLredis-cli lpush quotes:start_urls"https://quotes.toscrape.com"

推入后,所有等待中的爬虫会立刻开始爬取,自动分配请求,不会重复。

第三步:随时追加新任务

redis-cli lpush quotes:start_urls"https://quotes.toscrape.com/page/2/"

新 URL 会被所有爬虫共享,继续爬取。

四、Redis 中的数据查看

# 查看等待爬取的请求数量redis-cli llen quotes:requests# 查看已爬取的 URL 数量(去重集合)redis-cli scard quotes:dupefilter# 查看爬取结果(如果配置了 ITEM_PIPELINES)redis-cli llen quotes:items

核心 Redis key 说明:

Key类型说明
爬虫名:requestsList/ZSet待爬取的请求队列
爬虫名:dupefilterSet已爬取的 URL(去重用)
爬虫名:itemsList爬取到的数据(如果启用了 RedisPipeline)
爬虫名:start_urlsList/Set起始 URL 入口

五、数据存储——分布式写入

数据量大了以后,每台机器各自存一份 JSON 显然不行。统一存到 MongoDB 或 MySQL。

# pipelines.pyimportpymongoclassMongoPipeline:defopen_spider(self,spider):# 所有爬虫都连同一个 MongoDBself.client=pymongo.MongoClient("localhost",27017)self.db=self.client["spider_data"]defclose_spider(self,spider):self.client.close()defprocess_item(self,item,spider):# 插入到同一张表self.db["quotes"].insert_one(dict(item))returnitem
# settings.pyITEM_PIPELINES={# 注释掉默认的 JsonPipeline,换成 MongoPipeline"myspider.pipelines.MongoPipeline":300,}

关键:所有爬虫连接同一个数据库,数据自动汇总。

六、实战:分布式爬取豆瓣电影 Top250

fromscrapy_redis.spidersimportRedisSpiderclassDoubanSpider(RedisSpider):name="douban"redis_key="douban:start_urls"defparse(self,response):# 提取电影列表formovieinresponse.css("div.item"):yield{"title":movie.css("span.title::text").get(),"rating":movie.css("span.rating_num::text").get(),"quote":movie.css("span.inq::text").get(),"url":movie.css("a::attr(href)").get(),}# 翻页next_page=response.css("span.next a::attr(href)").get()ifnext_page:yieldresponse.follow(next_page,callback=self.parse)

启动:

# 机器Ascrapy crawl douban# 机器Bscrapy crawl douban# 推送起始 URLredis-cli lpush douban:start_urls"https://movie.douban.com/top250"

两台机器同时爬,一台爬第 1 页、第 3 页、第 5 页……另一台爬第 2 页、第 4 页、第 6 页……谁也抢不到谁的任务。

七、分布式爬虫注意事项

1. IP 被封问题

多台机器用同一个 IP 访问同一个网站,被封的概率也翻倍了。必须配代理:

# middlewares.pyclassProxyMiddleware:defprocess_request(self,request,spider):# 从代理池获取一个代理request.meta["proxy"]="http://代理IP:端口"

建议每台机器配不同的代理 IP 池。

2. 爬取速度控制

# settings.py# 每台机器各自限速,总的爬取速度会累加DOWNLOAD_DELAY=1.0# 单机间隔 1 秒CONCURRENT_REQUESTS=8# 单机并发 8# 3 台机器总速度 ≈ 3 × 8/1 = 24请求/秒

3. 去重机制

Scrapy-Redis 的去重是基于 URL 的,如果两个不同的 URL 返回相同的内容,不会被去重。如果要基于内容去重,需要自定义 DupeFilter。

4. 爬虫挂了怎么办

# settings.py# 调度器持久化 = 爬虫停了队列还在 Redis 中SCHEDULER_PERSIST=True# 重新启动爬虫scrapy crawl douban# 它会继续消费 Redis 中剩余的请求,不会从头开始

八、什么时候需要分布式?

数据量推荐方案原因
< 1万页单机 Scrapy几十分钟的事,没必要分布式
1万~10万页单机 Scrapy + 优化配置加大并发、减小延迟就能搞定
10万~100万页分布式 Scrapy-Redis单机需要跑几天,扛不住
> 100万页分布式 + 消息队列需要更健壮的架构

总结

Scrapy-Redis 只是把请求队列从内存搬到 Redis,代码改动很小——改继承、删 start_urls、加三行配置,单机就变分布式了。

单机爬虫 → 加 scrapy-redis 配置 → 多台机器启动 → push 起始 URL → 分布式跑起来

建议先在一台机器上把爬虫调好,再部署到多台机器上。不要还没调通就上分布式,排查问题会多一倍的复杂度。


💡 觉得有用的话,点赞 + 关注【张老师技术栈】吧!每周更新 Java/Python/爬虫 实战干货,不让你白来。

http://www.gsyq.cn/news/1596002.html

相关文章:

  • Apache Dubbo:企业级微服务框架的标杆
  • 360互联网安全大会聚焦智能体威胁,“中国版Mythos”能否破网络安全困局?
  • LinkSwift:九大网盘直链解析工具,开启高速下载新体验
  • Windows PDF处理终极方案:Poppler预编译包完整指南
  • 设计数据密集型应用第2版:2025-2026出版新书的《人月神话》引用(4)
  • 夏天总疲惫乏力、容易累、爱出汗的人,常喝这杯茶,养出元气满满好状态~
  • 终极无广告体验:SpotifyPremium桌面版完整配置指南
  • ts3380,G3000,ix6780,MG3640,ix6700,ix6800,G5080,TS8380,ts8220报错5B00,P07,E08,1700,5b02废墨垫清零,亲测可用
  • 鸿蒙语音识别的 Flutter ↔ ArkTS 完整调用链:权限申请、引擎生命周期与结果回传的时序问题
  • 进销存软件不一定贵,但要看这几点
  • 告别链接失效烦恼:百度网盘秒传脚本完全指南
  • 中医药现代化研究,国自然申请书怎么写才能中?
  • 一台高配置图形工作站带10人SolidWorks画图的实施方案是怎样的
  • 用你自己的签名,打你自己
  • 微信会话存档亿级数据处理:基于 RSA 混合解密与 Flink 的流式架构实战
  • C#工业相机开发从零到一:图像采集与显示的工程化实战
  • 从CTF实战解析SQL注入:绕过过滤与联合查询攻防
  • Python+Selenium自动化测试:Chrome Driver版本管理全流程实现
  • 天行健与优胜劣汰:两种文明范式的哲学比较及其现代启示
  • LSR包胶技术深度解析:金属包胶、塑料包胶到底怎么做?
  • OpenAI 9 个月自研芯片 Jalapeño,推理成本砍半,ChatGPT 体验将大升级!
  • 天河应用大讲堂 | 基于人工智能的天气预报技术发展趋势
  • 打通企微接口,构建适配 GEO 检索规则的结构化素材库
  • 从安装到调优,Strix Halo 本地大模型一周使用实录
  • C++跨平台(一):开发概述与策略选择
  • 合同系统智能化,让企业合同管理快人一步!
  • iOS网络安全实战:AFNetworking证书锁定防御中间人攻击
  • 《赣州市本级政府投资数字化项目费用编制指南》(赣市财审字〔2026〕2号)标准解读
  • 什么是企业号码认证?
  • Gogs高危漏洞实战:从原理到修复的完整安全加固指南