前言
单机 Scrapy 爬虫受限于队列、内存无法实现多机器协同抓取,Scrapy-Redis 依托 Redis 实现全局任务队列、分布式去重、断点续爬,多台服务器共享待爬 URL 池与已爬指纹库,是中大型爬虫项目集群标配。本章实现 Redis 键结构配置、爬虫改造、布隆过滤器去重、增量抓取、对接前文代理池 / UA 池 / Cookie 池,落地可直接上线的分布式爬虫工程。
本文所需依赖官方文档超链接:
- Scrapy 官方文档
- Scrapy-Redis 文档
- Redis-Py 官方文档
一、分布式爬虫核心原理
1.1 单机与分布式区别
- 原生 Scrapy:爬虫队列存储在内存,单机独立运行,多机任务重复抓取、无法共享任务;
- Scrapy-Redis:请求队列存入 Redis List,去重指纹存入 Redis Set / 布隆过滤器,所有爬虫节点统一从 Redis 取任务,新增机器自动分担抓取压力。
1.2 Redis 存储五大核心 Key
表格
| Redis Key | 数据结构 | 作用 |
|---|---|---|
| spider_name:requests | List | 分布式待爬任务队列,lpop 出队消费 |
| spider_name:dupefilter | Set/BloomFilter | URL 指纹库,全局去重 |
| spider_name:items | List | 爬虫产出数据队列,可对接管道入库 |
| spider_name:crawl_stats | Hash | 爬虫运行统计:抓取量、失败量 |
| spider_name:cookie_pool | ZSet | 复用前文分布式 Cookie 池 |
二、环境依赖安装
bash
运行
pip install scrapy==2.11.2 scrapy-redis==0.7.3 redis==5.0.8三、步骤 1:settings.py 全局分布式配置
python
运行
# 开启Redis调度器与去重过滤器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 断点续爬:保留Redis队列,爬虫重启不丢失任务 SCHEDULER_PERSIST = True # 爬虫空闲等待时长,空闲超时自动关闭爬虫 SCHEDULER_IDLE_BEFORE_CLOSE = 10 # Redis连接配置 REDIS_HOST = "127.0.0.1" REDIS_PORT = 6379 REDIS_DB = 0 # 远程集群填写REDIS_PASSWORD = "xxx" # 开启Redis Item管道 ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 300, } # 对接自定义UA中间件、代理中间件(复用前面资源池) DOWNLOADER_MIDDLEWARES = { 'spider.middlewares.RandomUAMiddle': 543, 'spider.middlewares.ProxyMiddleware': 550, }四、步骤 2:Spider 爬虫改造(RedisSpider 继承分布式基类)
python
运行
from scrapy_redis.spiders import RedisSpider import scrapy class GoodsDistSpider(RedisSpider): name = "goods_dist" # 从Redis读取起始任务键,手动lpush起始url redis_key = "goods_dist:start_urls" # 域名限制 allowed_domains = ["demo-goods.com"] def parse(self, response): # 列表页解析商品详情链接 detail_links = response.xpath("//a[@class='detail']/@href").getall() for link in detail_links: yield scrapy.Request(url=link,callback=self.parse_detail) # 分页逻辑 next_page = response.xpath("//a[text()='下一页']/@href").get() if next_page: yield scrapy.Request(next_page,callback=self.parse) def parse_detail(self,response): item = { "title":response.xpath("//h1/text()").get(), "price":response.xpath("//span[@class='price']/text()").get() } yield item任务下发命令(redis-cli)
redis
LPUSH goods_dist:start_urls https://demo-goods.com/list?page=1五、步骤 3:中间件对接代理池 + UA 池(分布式全局资源)
middlewares.py
python
运行
import requests import random PROXY_API = "http://127.0.0.1:5010/get_proxy" UA_API = "http://127.0.0.1:5011/get_ua" class RandomUAMiddle: def process_request(self,request,spider): ua = requests.get(UA_API).json()["ua"] request.headers["User-Agent"] = ua class ProxyMiddleware: def process_request(self,request,spider): proxy_json = requests.get(PROXY_API).json() if proxy_json["code"] ==200: proxy = proxy_json["proxy"] request.meta["proxy"] = f"http://{proxy}" # 代理失效回调 def process_exception(self,request,exception,spider): fail_proxy = request.meta["proxy"].replace("http://","") requests.get(f"http://127.0.0.1:5010/proxy_fail/{fail_proxy}") return request六、进阶:布隆过滤器优化海量 URL 去重(解决 Set 内存溢出)
原生 Set 存储千万级 URL 占用 Redis 内存过高,替换布隆过滤器:
bash
运行
pip install scrapy-redis-bloomfilter修改 settings 去重配置:
python
运行
DUPEFILTER_CLASS = "scrapy_redis_bloomfilter.BloomFilter" # 布隆过滤器参数 BLOOMFILTER_HASH_NUMBER = 6 BLOOMFILTER_BIT = 30七、多机集群部署方案
- 一台 Redis 服务作为中心存储,所有机器 Redis 配置指向同一台 RedisIP;
- 所有服务器部署同一份爬虫代码,统一执行
scrapy crawl goods_dist; - 任意机器 redis-cli 下发起始 URL,全集群自动分摊抓取任务。
八、增量爬虫实现(只抓取当日新增数据)
- 每日定时脚本 LPUSH 当日列表页 URL 至 redis 起始队列;
- 布隆过滤器自动过滤已爬历史 URL,仅新增 URL 进入抓取队列;
- 搭配 APScheduler 定时任务,实现全自动每日增量采集。
九、数据落地拓展:Redis Item 转存 MySQL
自定义 Pipeline 替代原生 RedisPipeline,批量入库 MySQL:
python
运行
import pymysql class MysqlPipeline: def open_spider(self,spider): self.conn = pymysql.connect(host="127.0.0.1",user="root",passwd="xxx",db="crawl_db") self.cur = self.conn.cursor() def process_item(self,item,spider): sql = "insert into goods(title,price) values(%s,%s)" self.cur.execute(sql,(item["title"],item["price"])) self.conn.commit() return item十、故障排查优化表
表格
| 异常 | 处理方案 |
|---|---|
| 多节点重复抓取 | 确认 DUPEFILTER_CLASS 配置生效,Redis 指纹正常写入 |
| 代理频繁失效 | 扩充代理池 IP 基数,调高代理可用性校验频次 |
| Redis 队列堆积过载 | 横向新增爬虫节点,拆分任务分批下发 |
| 内存持续上涨 | 布隆过滤器替代 Set,关闭无用爬虫统计日志 |
十一、本章总结
Scrapy-Redis 分布式核心:Redis 全局任务队列 + 分布式去重 + 多机集群消费,工程标准组合:Scrapy-Redis + Redis布隆去重 + 全局代理UA Cookie资源池 + MySQL持久化;单机调试直接本地 Redis,生产集群部署独立 Redis 服务。后续拓展:Scrapy-Redis 分布式爬虫监控面板、Kafka 替代 Redis 做任务队列、Docker 容器化一键部署爬虫集群。