news 2026/2/20 17:55:03

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/2/17 20:35:46

快速提取Oracle AWR报告指南

1. 当前连接实例的AWR报告提取 注意:中间没有任何空格,需要在数据库服务器上Oracle用户登陆 ?/rdbms/admin/awrrpt2. 输入格式 Enter value for report_type: htmlType Specified: html注意:这里直接回…

作者头像 李华
网站建设 2026/2/15 7:14:28

SGMICRO圣邦微 SGM2019-1.8YC5G/TR SC70-5 线性稳压器(LDO)

特性工作输入电压范围:2.5V至5.5V固定输出电压:1.2V、1.5V、1.8V、2.5V、2.6V、2.8V、2.85V、3.0V、3.3V可调输出电压范围:1.2V至5.0V输出电压精度:25C时为2.5%低输出噪声:30μV_RMS(典型值)低压…

作者头像 李华
网站建设 2026/2/7 10:08:00

Python 爬虫实战:Scrapy 中间件自定义开发

前言 Scrapy 框架的高扩展性核心体现在其模块化的组件设计,而中间件(Middleware)是连接引擎(Engine)与其他核心组件(下载器、爬虫、响应处理)的关键桥梁。无论是应对反爬机制(如 UA…

作者头像 李华
网站建设 2026/2/16 12:46:27

39. UVM Factory Override

UVM Factory:验证平台的"智能生产线" 我们要学习UVM中最强大、最核心的特性之一:Factory机制。这就像是一个智能的生产线,可以根据需求动态更换生产的产品类型,而不需要修改生产线本身。 🎯 一句话理解UVM F…

作者头像 李华