前言单机 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:requestsList分布式待爬任务队列lpop 出队消费spider_name:dupefilterSet/BloomFilterURL 指纹库全局去重spider_name:itemsList爬虫产出数据队列可对接管道入库spider_name:crawl_statsHash爬虫运行统计抓取量、失败量spider_name:cookie_poolZSet复用前文分布式 Cookie 池二、环境依赖安装bash运行pip install scrapy2.11.2 scrapy-redis0.7.3 redis5.0.8三、步骤 1settings.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, }四、步骤 2Spider 爬虫改造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[classdetail]/href).getall() for link in detail_links: yield scrapy.Request(urllink,callbackself.parse_detail) # 分页逻辑 next_page response.xpath(//a[text()下一页]/href).get() if next_page: yield scrapy.Request(next_page,callbackself.parse) def parse_detail(self,response): item { title:response.xpath(//h1/text()).get(), price:response.xpath(//span[classprice]/text()).get() } yield item任务下发命令redis-cliredisLPUSH goods_dist:start_urls https://demo-goods.com/list?page1五、步骤 3中间件对接代理池 UA 池分布式全局资源middlewares.pypython运行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] fhttp://{proxy} # 代理失效回调 def process_exception(self,request,exception,spider): fail_proxy request.meta[proxy].replace(http://,) requests.get(fhttp://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批量入库 MySQLpython运行import pymysql class MysqlPipeline: def open_spider(self,spider): self.conn pymysql.connect(host127.0.0.1,userroot,passwdxxx,dbcrawl_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 容器化一键部署爬虫集群。
Python 分布式爬虫实战:Scrapy-Redis 集群爬虫搭建 + 去重 + 断点续爬
前言单机 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:requestsList分布式待爬任务队列lpop 出队消费spider_name:dupefilterSet/BloomFilterURL 指纹库全局去重spider_name:itemsList爬虫产出数据队列可对接管道入库spider_name:crawl_statsHash爬虫运行统计抓取量、失败量spider_name:cookie_poolZSet复用前文分布式 Cookie 池二、环境依赖安装bash运行pip install scrapy2.11.2 scrapy-redis0.7.3 redis5.0.8三、步骤 1settings.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, }四、步骤 2Spider 爬虫改造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[classdetail]/href).getall() for link in detail_links: yield scrapy.Request(urllink,callbackself.parse_detail) # 分页逻辑 next_page response.xpath(//a[text()下一页]/href).get() if next_page: yield scrapy.Request(next_page,callbackself.parse) def parse_detail(self,response): item { title:response.xpath(//h1/text()).get(), price:response.xpath(//span[classprice]/text()).get() } yield item任务下发命令redis-cliredisLPUSH goods_dist:start_urls https://demo-goods.com/list?page1五、步骤 3中间件对接代理池 UA 池分布式全局资源middlewares.pypython运行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] fhttp://{proxy} # 代理失效回调 def process_exception(self,request,exception,spider): fail_proxy request.meta[proxy].replace(http://,) requests.get(fhttp://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批量入库 MySQLpython运行import pymysql class MysqlPipeline: def open_spider(self,spider): self.conn pymysql.connect(host127.0.0.1,userroot,passwdxxx,dbcrawl_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 容器化一键部署爬虫集群。