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

📅 2026/6/26 22:23:30
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 的调度器替代默认的内存调度器SCHEDULERscrapy_redis.scheduler.Scheduler# 使用 Redis 去重组件替代默认的内存去重DUPEFILTER_CLASSscrapy_redis.dupefilter.RFPDupeFilter# Redis 连接配置REDIS_HOSTlocalhost# Redis 服务器地址REDIS_PORT6379REDIS_PARAMS{password:,# Redis 密码db:0,}# 持久化请求队列爬虫停了以后不清空SCHEDULER_PERSISTTrue# 爬虫停止后是否清空去重集合建议 True避免内存堆积SCHEDULER_FLUSH_ON_STARTFalse# 可选从 Redis 中读取起始 URLREDIS_START_URLS_AS_SETTrue3. 修改爬虫代码# spiders/quotes.pyfromscrapy_redis.spidersimportRedisSpider# 原来继承 scrapy.Spider现在继承 RedisSpiderclassQuotesSpider(RedisSpider):namequotes# 不再写 start_urls而是从 Redis 读取redis_keyquotes:start_urlsdefparse(self,response):# 解析逻辑和单机时完全一样forquoteinresponse.css(div.quote):yield{text:quote.css(span.text::text).get(),author:quote.css(small.author::text).get(),}# 翻页next_pageresponse.css(li.next a::attr(href)).get()ifnext_page:yieldresponse.follow(next_page,callbackself.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_urlshttps://quotes.toscrape.com推入后所有等待中的爬虫会立刻开始爬取自动分配请求不会重复。第三步随时追加新任务redis-cli lpush quotes:start_urlshttps://quotes.toscrape.com/page/2/新 URL 会被所有爬虫共享继续爬取。四、Redis 中的数据查看# 查看等待爬取的请求数量redis-cli llen quotes:requests# 查看已爬取的 URL 数量去重集合redis-cli scard quotes:dupefilter# 查看爬取结果如果配置了 ITEM_PIPELINESredis-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.clientpymongo.MongoClient(localhost,27017)self.dbself.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换成 MongoPipelinemyspider.pipelines.MongoPipeline:300,}关键所有爬虫连接同一个数据库数据自动汇总。六、实战分布式爬取豆瓣电影 Top250fromscrapy_redis.spidersimportRedisSpiderclassDoubanSpider(RedisSpider):namedoubanredis_keydouban:start_urlsdefparse(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_pageresponse.css(span.next a::attr(href)).get()ifnext_page:yieldresponse.follow(next_page,callbackself.parse)启动# 机器Ascrapy crawl douban# 机器Bscrapy crawl douban# 推送起始 URLredis-cli lpush douban:start_urlshttps://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_DELAY1.0# 单机间隔 1 秒CONCURRENT_REQUESTS8# 单机并发 8# 3 台机器总速度 ≈ 3 × 8/1 24请求/秒3. 去重机制Scrapy-Redis 的去重是基于 URL 的如果两个不同的 URL 返回相同的内容不会被去重。如果要基于内容去重需要自定义 DupeFilter。4. 爬虫挂了怎么办# settings.py# 调度器持久化 爬虫停了队列还在 Redis 中SCHEDULER_PERSISTTrue# 重新启动爬虫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/爬虫 实战干货不让你白来。