豆瓣Top250分布式爬虫实战|从单机到多机,Scrapy-Redis核心用法全拆解
豆瓣Top250分布式爬虫实战|从单机到多机,Scrapy-Redis核心用法全拆解
今天带大家从零落地豆瓣电影Top250分布式爬虫,全程对比普通单机爬虫与Scrapy-Redis分布式爬虫的差异,嵌入完整对比代码、实操步骤,拆解每一步推进逻辑,避开实操坑点,让大家既能看懂原理,也能直接上手运行。
本次实战核心目标:用Scrapy-Redis将普通单机爬虫改造为分布式爬虫,验证多机协同、自动去重、断点续爬的优势;对比两者在代码、效率、容错性上的差异;完成豆瓣Top250电影数据(标题、导演、剧情简介)的爬取与存储。
实战环境:2台Windows主机(爬虫节点)、1台Linux服务器(部署Redis,作为中央调度中心),Python 3.9、Scrapy 2.8.0、Scrapy-Redis 0.7.2、Redis 6.2.6。
一、前期准备:单机vs分布式,环境配置差异拆解
在动手写代码前,先明确两者的环境配置差异——普通单机爬虫无需依赖Redis,而分布式爬虫的核心是“Redis中央调度”,必须先完成Redis部署与多节点连通,这是分布式爬虫能正常运行的前提。
1.1 普通单机爬虫环境(极简配置)
仅需在本地安装基础依赖,无需配置Redis,一行命令即可完成:
pipinstallscrapy配置完成后,直接编写爬虫代码即可启动,无需额外配置调度相关环境,适合小规模爬取。
1.2 分布式爬虫环境(核心配置)
分布式爬虫需要“多节点+Redis中央调度”,分两步配置,缺一不可:
第一步:所有爬虫节点(2台Windows主机)安装依赖:
pipinstallscrapy scrapy-redis第二步:Linux服务器部署Redis(核心,中央调度中心):
安装Redis后,修改配置文件(redis.conf):关闭保护模式(protected-mode no)、允许远程连接(bind 0.0.0.0)、设置密码(requirepass 你的密码),避免未授权访问。
开启Redis持久化(RDB+AOF),确保断点续爬时进度不丢失:配置save 60 100(60秒内有100次修改则持久化),开启appendonly yes。
启动Redis服务,开放对应端口(默认6379),确保两台爬虫节点能ping通Redis服务器,且能正常连接Redis。
关键差异:普通单机爬虫“单节点无依赖”,分布式爬虫“多节点+Redis依赖”,Redis的作用是统一管理任务队列、实现去重与断点续爬。
二、代码编写:从单机到分布式,3处修改搞定改造(附完整对比代码)
这是本次实战的核心的环节——分布式爬虫无需改动解析逻辑,仅需修改3处调度相关代码,就能将普通单机爬虫改造为分布式爬虫。下面直接上完整对比代码,每一处差异都标红说明。
2.1 普通单机爬虫完整代码(douban_spider_single.py)
importscrapyfromDouban.itemsimportDoubanItem# 普通单机爬虫:继承scrapy.SpiderclassMoviesSpider(scrapy.Spider):name="movies_single"# 爬虫名称,单机可随意命名allowed_domains=["movie.douban.com"]# 单机爬虫:固定写死起始URL,仅单台机器从该URL开始爬取start_urls=["https://movie.douban.com/top250"]# 列表页解析逻辑(分布式无需修改)defparse(self,response):lis=response.xpath("//ol[@class='grid_view']/li")forliinlis:href=li.xpath(".//div[@class='hd']/a/@href").get()title=li.xpath(".//div[@class='hd']/a/span[1]/text()").get()yieldscrapy.Request(href,callback=self.parse_detail,meta={"title":title})# 详情页解析逻辑(分布式无需修改)defparse_detail(self,response):# 解析导演(处理可能的空值,避免报错)director=response.xpath('//*[@id="info"]/span[1]/span[2]/a/text()').get()or"未知"# 解析剧情简介(去除空格、换行)summary=response.xpath('//div[@id="link-report-intra"]/span[@property="v:summary"]/text()').get()or"无简介"summary=summary.strip().replace("\n","").replace(" ","")# 输出数据yieldDoubanItem(title=response.meta["title"],director=director,summary=summary)2.2 分布式爬虫完整代码(douban_spider_distributed.py)
importscrapyfromDouban.itemsimportDoubanItem# 分布式爬虫:导入RedisSpider(核心修改1)fromscrapy_redis.spidersimportRedisSpider# 分布式爬虫:继承RedisSpider(核心修改1)classMoviesSpider(RedisSpider):name="movies_distributed"allowed_domains=["movie.douban.com"]# 分布式爬虫:删除start_urls(核心修改2),避免多节点重复爬取# start_urls = ["https://movie.douban.com/top250"] # 注释掉,禁止写死# 分布式爬虫:添加redis_key(核心修改3),作为任务队列名称redis_key="afei"# 所有节点都监听这个队列,领取任务# 列表页解析逻辑:与单机完全一致,无需修改defparse(self,response):lis=response.xpath("//ol[@class='grid_view']/li")forliinlis:href=li.xpath(".//div[@class='hd']/a/@href").get()title=li.xpath(".//div[@class='hd']/a/span[1]/text()").get()yieldscrapy.Request(href,callback=self.parse_detail,meta={"title":title})# 补充:下一页URL解析(单机可加可不加,分布式必须加,确保任务持续推进)next_url=response.xpath('//span[@class="next"]/a/@href').get()ifnext_url:next_url="https://movie.douban.com/top250"+next_urlyieldscrapy.Request(next_url,callback=self.parse)# 详情页解析逻辑:与单机完全一致,无需修改defparse_detail(self,response):director=response.xpath('//*[@id="info"]/span[1]/span[2]/a/text()').get()or"未知"summary=response.xpath('//div[@id="link-report-intra"]/span[@property="v:summary"]/text()').get()or"无简介"summary=summary.strip().replace("\n","").replace(" ","")yieldDoubanItem(title=response.meta["title"],director=director,summary=summary)2.3 核心修改点总结(3处,必记)
| 修改位置 | 普通单机爬虫 | 分布式爬虫 | 修改原因 |
|---|---|---|---|
| 继承类 | scrapy.Spider | scrapy_redis.spiders.RedisSpider | 让爬虫具备分布式调度能力,能够监听Redis任务队列 |
| 起始URL | start_urls = [“xxx”](写死) | 删除start_urls | 避免多节点同时从起始URL爬取,导致数据重复 |
| 任务队列 | 无 | redis_key = “afei” | 所有节点监听该队列,统一领取任务,实现中央调度 |
| 关键提醒:解析逻辑(parse、parse_detail)完全不变!分布式只改“调度方式”,不改“爬取逻辑”,这也是Scrapy-Redis的便捷之处。 |
三、配置优化:settings.py配置对比(单机vs分布式)
除了爬虫代码,settings.py的配置也有差异,主要集中在Redis相关配置与去重、管道配置,直接上对比配置,复制即可使用。
3.1 普通单机爬虫settings.py核心配置
# 基础配置BOT_NAME='Douban'SPIDER_MODULES=['Douban.spiders']NEWSPIDER_MODULE='Douban.spiders'# 反爬配置(单机、分布式通用)USER_AGENT='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'ROBOTSTXT_OBEY=False# 不遵守robots协议(豆瓣robots禁止爬取,需关闭)DOWNLOAD_DELAY=1# 请求间隔1秒,避免触发反爬# item管道配置(单机可存入本地文件)ITEM_PIPELINES={'Douban.pipelines.DoubanPipeline':300,}# 单机爬虫:无需Redis相关配置3.2 分布式爬虫settings.py核心配置
# 基础配置(与单机一致)BOT_NAME='Douban'SPIDER_MODULES=['Douban.spiders']NEWSPIDER_MODULE='Douban.spiders'# 反爬配置(与单机一致,需严格配置,避免多节点触发反爬)USER_AGENT='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'ROBOTSTXT_OBEY=FalseDOWNLOAD_DELAY=1# 多节点需保持一致,避免请求过于密集# 分布式核心配置:Redis相关(新增)REDIS_URL='redis://:你的密码@Redis服务器IP:6379/0'# 连接RedisREDIS_PARAMS={'password':'你的密码'}# 额外密码配置,双重保障# 分布式核心配置:自动去重(新增)DUPEFILTER_CLASS="scrapy_redis.dupefilter.RFPDupeFilter"# Redis自动去重SCHEDULER="scrapy_redis.scheduler.Scheduler"# 使用Redis调度器SCHEDULER_PERSIST=True# 调度器持久化,实现断点续爬# item管道配置(分布式建议存入Redis/MySQL,统一管理数据)ITEM_PIPELINES={# 存入Redis管道(Scrapy-Redis自带)'scrapy_redis.pipelines.RedisPipeline':300,# 如需存入MySQL,可添加自定义管道,优先级低于Redis管道# 'Douban.pipelines.DoubanMysqlPipeline': 400,}四、实战启动:单机vs分布式,启动流程对比(附命令)
配置与代码都完成后,分别启动单机与分布式爬虫,对比启动流程与运行效果,直观感受两者的差异。
4.1 普通单机爬虫启动(单节点)
启动流程极简,无需启动Redis,直接在项目根目录执行命令:
scrapy crawl movies_single运行效果:单台机器从start_urls开始,串行爬取列表页→详情页,爬取过程中若中断,只能重新启动,进度丢失,且无法多机协同,爬取速度慢。
4.2 分布式爬虫启动(多节点+Redis)
分布式启动分3步,必须按顺序执行,否则无法正常运行:
启动Redis服务(Linux服务器):
推入起始URL(Redis客户端,任意节点执行均可):
启动所有爬虫节点(2台Windows主机,分别执行):
运行效果:两台节点同时监听Redis的“afei”队列,领取任务(起始URL、详情页URL、下一页URL),一台节点爬取列表页,另一台爬取详情页,互不干扰,任务完成后自动领取新任务,实现多机协同。
五、实战验证:核心优势对比
启动后,分别运行单机与分布式爬虫,爬取豆瓣Top250全部数据,对比两者的核心指标,验证分布式爬虫的优势,结果如下表所示:
| 对比指标 | 普通单机爬虫 | Scrapy-Redis分布式爬虫(2节点) | 优势体现 |
|---|---|---|---|
| 爬取耗时 | 约40分钟 | 约15分钟 | 多机协同,速度提升60%+ |
| 数据重复率 | 若多开进程,重复率100% | 0%(Redis自动去重) | 避免重复爬取,节省资源 |
| 断点续爬 | 无,中断后需重新爬取 | 有,重启后继续未完成任务 | 容错性强,避免进度丢失 |
| 任务管理 | 无,只能本地查看进度 | Redis实时查看任务队列、已完成任务 | 便于监控,适合大规模爬取 |
| 扩展性 | 无法扩展,只能单台运行 | 可新增节点,速度随节点数量提升 | 适配大规模数据爬取场景 |
六、实操坑点拆解(避坑必看)
结合本次实战,整理了4个分布式爬虫高频坑点,单机爬虫基本不会遇到,大家实操时重点注意:
坑点1:Redis连接失败 → 排查3点:Redis服务器防火墙是否开放6379端口、配置文件是否允许远程连接、密码是否正确,建议用redis-cli测试连接(telnet RedisIP 6379)。
坑点2:多节点重复爬取 → 大概率是忘记删除start_urls,或redis_key不一致,确保所有节点的redis_key相同,且未写死start_urls。
坑点3:IP被豆瓣封禁 → 分布式多节点请求密集,更容易触发反爬,除了设置DOWNLOAD_DELAY,建议配置IP代理池、User-Agent池,避免单一IP/UA过度请求。
坑点4:断点续爬失效 → 未开启SCHEDULER_PERSIST = True,或Redis未配置持久化,导致任务队列丢失,需同时开启调度器持久化与Redis持久化。
七、实战总结与拓展
本次实战通过对比普通单机爬虫与Scrapy-Redis分布式爬虫,清晰掌握了分布式爬虫的核心原理与实操技巧,总结核心要点:
核心差异:单机爬虫“单节点、无调度、无容错”,适合小规模爬取;分布式爬虫“多节点、Redis中央调度、自动去重、断点续爬”,适合大规模爬取。
改造关键:仅需3处代码修改(继承类、删除start_urls、添加redis_key),解析逻辑不变,开发成本低。
核心原理:Scrapy-Redis将Scrapy的任务队列、去重、调度功能迁移至Redis,实现多节点共享任务,协同工作。
拓展方向:
性能优化:新增更多爬虫节点,配置动态IP代理池,进一步提升爬取速度。
数据存储:将Redis中的数据导入MySQL、MongoDB,便于后续数据查询与分析。
监控优化:搭建Redis监控面板,实时查看任务进度、节点运行状态,及时排查问题。
本次实战代码为scrapy中的主python文件,需要完整项目模板(含items.py、pipelines.py)的同学,评论区留言“豆瓣分布式”,我会统一回复。关注我,后续持续分享爬虫实战、数据采集相关技巧,避开更多坑点~
