news 2026/5/4 13:50:28

Python 爬虫实战:Scrapy 框架快速搭建分布式爬虫

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python 爬虫实战:Scrapy 框架快速搭建分布式爬虫

前言

在大数据时代,单节点爬虫面对海量数据采集需求时,往往受限于单机的网络带宽、CPU 算力和 IP 资源,采集效率难以满足业务要求。Scrapy 作为一款成熟的 Python 爬虫框架,本身具备轻量级、高扩展性的特点,结合分布式架构可将爬虫任务拆分至多个节点并行执行,大幅提升数据采集效率。本文将从分布式爬虫的核心原理出发,手把手教你基于 Scrapy + Redis 快速搭建分布式爬虫系统,覆盖环境配置、核心组件改造、任务调度及实战验证全流程,帮助开发者解决大规模数据采集的效率瓶颈。

摘要

本文聚焦 Scrapy 分布式爬虫的搭建与实战,首先剖析分布式爬虫的核心原理,对比单节点与分布式架构的差异;其次详细讲解环境搭建(Redis 部署、Scrapy 依赖安装),并基于 Scrapy 内置的RedisSpider改造爬虫项目,实现任务的分布式调度;最后通过实战案例(目标站点:豆瓣电影 Top250)验证分布式爬虫的可用性,同时分析关键参数调优与常见问题解决方案。通过本文,读者可掌握分布式爬虫的核心开发思路,实现从单节点到多节点的爬虫能力升级。

一、分布式爬虫核心原理

1.1 单节点 Scrapy 局限

单节点 Scrapy 爬虫的任务调度、请求队列、数据存储均在本地完成,存在以下问题:

  • 请求队列存储在本地内存 / 磁盘,节点故障会导致任务丢失;
  • 单机 IP 易被目标网站封禁,采集速度受限于单节点带宽;
  • 无法利用多机算力,海量 URL 处理耗时过长。

1.2 分布式爬虫架构设计

Scrapy 分布式爬虫核心依赖Redis 分布式队列实现任务共享,整体架构如下:

组件作用
Redis 服务器存储待爬取的 URL 队列(去重)、已爬取 URL 集合、节点共享配置
爬虫节点(Slave)多个节点同时连接 Redis,获取待爬取 URL,执行爬取任务并解析数据
调度器(Scheduler)替换 Scrapy 本地调度器,从 Redis 读取 / 写入 URL,实现任务分布式调度
去重组件基于 Redis 的集合(Set)实现 URL 全局去重,避免多节点重复爬取

核心流程:

  1. 主节点(或任意节点)将初始 URL 推入 Redis 的待爬队列;
  2. 所有爬虫节点监听 Redis 队列,获取 URL 并执行爬取;
  3. 爬取过程中产生的新 URL 经去重后再次推入 Redis 队列;
  4. 各节点解析的数据通过 Pipeline 统一存储(如 MySQL、MongoDB)。

二、环境搭建

2.1 基础环境要求

软件 / 库版本要求作用
Python≥3.8基础开发环境
Scrapy≥2.6爬虫框架
redis-py≥4.3Python 操作 Redis 客户端
scrapy-redis≥0.7.3Scrapy 分布式扩展
Redis 服务器≥6.0分布式队列存储

2.2 环境安装

(1)安装 Python 依赖

bash

运行

pip install scrapy==2.6.2 redis==4.5.1 scrapy-redis==0.7.3
(2)部署 Redis 服务器
  • Linux 系统

    bash

    运行

    # 安装 Redis sudo apt update && sudo apt install redis-server -y # 启动 Redis 并设置开机自启 sudo systemctl start redis-server sudo systemctl enable redis-server # 验证 Redis 运行状态 redis-cli ping # 输出 PONG 表示正常
  • Windows 系统:从 Redis 官网 下载 Windows 版本,解压后双击redis-server.exe启动服务。

三、分布式爬虫实战开发

3.1 创建 Scrapy 项目

bash

运行

# 创建项目 scrapy startproject douban_distributed # 进入项目目录 cd douban_distributed # 创建爬虫文件 scrapy genspider douban_top250 movie.douban.com

3.2 核心配置修改(settings.py)

打开douban_distributed/settings.py,修改以下配置,替换 Scrapy 原生组件为 scrapy-redis 分布式组件:

python

运行

# 1. 启用 Redis 调度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 2. 启用 Redis 去重 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 3. 爬取完成后不清除 Redis 队列(便于重复运行) SCHEDULER_PERSIST = True # 4. Redis 服务器地址(默认本地 6379,多节点需填写 Redis 服务器公网 IP) REDIS_URL = "redis://127.0.0.1:6379/0" # 5. 关闭默认的 UserAgent,自定义请求头 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" # 6. 遵守 robots.txt 协议 ROBOTSTXT_OBEY = False # 7. 并发数(分布式节点可适当调高) CONCURRENT_REQUESTS = 32 # 8. 下载延迟 DOWNLOAD_DELAY = 1 # 9. 启用管道(后续数据持久化可扩展) ITEM_PIPELINES = { "douban_distributed.pipelines.DoubanDistributedPipeline": 300, # 可选:将 Item 存入 Redis # "scrapy_redis.pipelines.RedisPipeline": 400, }

3.3 改造爬虫文件(douban_top250.py)

将原生Spider替换为RedisSpider,实现从 Redis 读取待爬 URL:

python

运行

import scrapy from scrapy_redis.spiders import RedisSpider from douban_distributed.items import DoubanDistributedItem class DoubanTop250Spider(RedisSpider): name = 'douban_top250' # 替换 allowed_domains 和 start_urls,改为 Redis 队列名称 allowed_domains = ['movie.douban.com'] # Redis 队列名称(启动爬虫时需手动推入初始 URL) redis_key = 'douban:start_urls' def parse(self, response): """解析豆瓣 Top250 页面,提取电影信息""" # 提取当前页电影列表 movie_list = response.xpath('//ol[@class="grid_view"]/li') for movie in movie_list: item = DoubanDistributedItem() # 电影标题 item['title'] = movie.xpath('.//span[@class="title"][1]/text()').extract_first() # 评分 item['score'] = movie.xpath('.//span[@class="rating_num"]/text()').extract_first() # 简介 item['quote'] = movie.xpath('.//span[@class="inq"]/text()').extract_first() yield item # 提取下一页 URL next_page = response.xpath('//span[@class="next"]/a/@href').extract_first() if next_page: # 拼接完整 URL next_url = f"https://movie.douban.com/top250{next_page}" # 将下一页 URL 推入 Redis 队列 yield scrapy.Request(url=next_url, callback=self.parse)

3.4 定义 Item 结构(items.py)

python

运行

import scrapy class DoubanDistributedItem(scrapy.Item): # 电影标题 title = scrapy.Field() # 评分 score = scrapy.Field() # 简介 quote = scrapy.Field()

3.5 管道数据持久化(pipelines.py)

此处实现将爬取的数据保存至本地 JSON 文件,可扩展为存储至 MySQL/MongoDB:

python

运行

import json class DoubanDistributedPipeline: def open_spider(self, spider): """爬虫启动时创建文件""" self.file = open('douban_top250.json', 'w', encoding='utf-8') self.file.write('[') self.first_item = True def process_item(self, item, spider): """处理每个 Item""" # 转换为字典并序列化 item_dict = dict(item) if not self.first_item: self.file.write(',') else: self.first_item = False self.file.write(json.dumps(item_dict, ensure_ascii=False, indent=2)) return item def close_spider(self, spider): """爬虫关闭时关闭文件""" self.file.write(']') self.file.close()

四、启动分布式爬虫

4.1 推送初始 URL 至 Redis

bash

运行

# 进入 Redis 客户端 redis-cli # 推送初始 URL 至指定队列 LPUSH douban:start_urls https://movie.douban.com/top250 # 验证队列是否有数据 LLEN douban:start_urls # 输出 1 表示成功

4.2 启动多个爬虫节点

节点 1(本地):

bash

运行

cd douban_distributed scrapy crawl douban_top250
节点 2(另一台服务器 / 本地新开终端):

bash

运行

# 确保该节点已安装相同依赖,且能访问 Redis 服务器 cd douban_distributed scrapy crawl douban_top250

4.3 输出结果示例

(1)Redis 队列状态(Redis 客户端执行)

bash

运行

# 查看待爬 URL 队列 LRANGE douban:start_urls 0 -1 # 输出示例: 1) "https://movie.douban.com/top250?start=25&filter=" 2) "https://movie.douban.com/top250?start=50&filter=" # 查看已去重的 URL 集合 SMEMBERS scrapy:dupefilter:douban_top250 # 输出示例:包含所有已爬取的 URL 哈希值
(2)本地 JSON 文件(douban_top250.json)

json

[ { "title": "肖申克的救赎", "score": "9.7", "quote": "希望让人自由。" }, { "title": "霸王别姬", "score": "9.6", "quote": "风华绝代。" }, { "title": "阿甘正传", "score": "9.5", "quote": "人生就像一盒巧克力,你永远不知道下一块会是什么味道。" } ]

4.4 核心原理解析

  1. 任务调度:每个爬虫节点启动后,会连接 Redis 并从douban:start_urls队列中弹出 URL 执行爬取,爬取产生的新 URL 会再次推入该队列,实现多节点共享任务;
  2. URL 去重:scrapy-redis 将每个 URL 进行哈希计算后存入 Redis 的 Set 集合,确保所有节点不会爬取相同 URL;
  3. 队列持久化SCHEDULER_PERSIST = True保证爬虫停止后 Redis 中的待爬队列不会被清空,重启节点可继续爬取。

五、关键调优与问题排查

5.1 性能调优

参数调优建议
CONCURRENT_REQUESTS分布式节点总数 × 单节点并发数 ≤ 目标网站承受阈值(建议单节点 20-50)
DOWNLOAD_DELAY根据目标网站反爬策略调整(豆瓣建议 1-2 秒)
REDIS_URL多节点部署时,Redis 服务器需配置公网访问,且设置密码(避免未授权访问)

5.2 常见问题及解决方案

问题现象原因分析解决方案
节点无法连接 RedisRedis 未开放公网端口 / 防火墙拦截配置 Redisbind 0.0.0.0,开放 6379 端口,关闭防火墙
多节点爬取重复数据去重组件未生效检查DUPEFILTER_CLASS配置是否正确,重启 Redis 服务
Redis 队列数据积压爬取速度慢于 URL 生成速度增加爬虫节点数量,或降低新 URL 生成频率
爬虫被目标网站封禁 IP单 IP 访问频率过高结合 Scrapy 代理中间件,为每个节点配置不同代理 IP

六、总结

本文基于 Scrapy + Redis 实现了分布式爬虫的快速搭建,核心是通过 Redis 实现任务队列的分布式共享和 URL 全局去重,解决了单节点爬虫效率低、易被封禁的问题。实战中以豆瓣电影 Top250 为例,完整覆盖了项目创建、配置修改、爬虫开发、多节点启动全流程,并给出了性能调优和问题排查方案。

分布式爬虫的核心价值在于利用多节点的算力和 IP 资源提升采集效率,后续可进一步扩展:结合代理池实现 IP 自动切换、基于 Kafka 实现数据实时传输、通过监控平台可视化爬虫运行状态等。掌握本文的核心思路后,可快速适配各类大规模数据采集场景,满足企业级爬虫开发需求。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/4 16:36:16

Python 爬虫实战:爬虫代理 IP 池搭建与自动切换

摘要 本文聚焦爬虫代理 IP 池的核心搭建与自动切换技术,针对反爬机制中 IP 封禁的核心痛点,系统讲解代理 IP 池的架构设计、数据源对接、有效性检测、自动切换及动态维护全流程。实战验证基于IP 检测测试页(可直接点击验证 IP 有效性&#x…

作者头像 李华
网站建设 2026/5/5 0:54:50

JAVA面相对象编程—抽象类、接口

#JAVA笔记#抽象类定义抽象类与普通类基本类似,唯一的区别在于使用abstract关键字修饰,且类中有未实现(没有方法体)的抽象方法(abstract修饰)。抽象方法必须位于抽象类中,抽象方法只能访问抽象成…

作者头像 李华
网站建设 2026/5/4 13:36:54

2026最新网络安全小白自学之路,别到处拜师了!!

较为完整的学习路线: 这个路线是我和一些已入职大佬来规划整理,也加上了小提示,我也希望你们能看看上面我的心得,都会有所帮助。 第一阶段,初入门学网络基础tip:这部分没有什么逻辑可以说的,半个…

作者头像 李华
网站建设 2026/5/1 11:57:33

加入2025护网,日薪最低1500,能力越强薪资越高!

加入2025护网,日薪最低1500,能力越强薪资越高! 什么是护网行动 ** ** 1.护网行动 护网,也称网络保护,是指网络安全人员对企业或组织的网络进行检查、维护和保护,以防止网络受到黑客攻击、病毒、木马或其…

作者头像 李华
网站建设 2026/5/1 7:51:52

Selenium切换窗口、框架和弹出框window、ifame、alert

🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 一、切换窗口#获取打开的多个窗口句柄 windows driver.window_handles #切换到当前最新打开的窗口 driver.switch_to.window(windows[-1]) #最大化浏览器 driv…

作者头像 李华
网站建设 2026/5/1 13:05:54

一个人,一家独角兽公司:代码的终结与创造者的崛起

刚看完 Silicon Valley Girl 采访 Replit CEO Amjad Masad 的视频,后劲很大。Amjad 在视频里抛出了一个非常炸裂的预测:“我们很快就会看到第一家由单人创办并运营的 10 亿美元估值(Unicorn)公司。”注意,是一人公司&a…

作者头像 李华