Python 爬虫 Scrapy:分布式抓取框架

FreeGuideOnline 最新 2026-06-16

Scrapy 分布式抓取完全指南

本教程将带你从零开始,掌握基于 Scrapy 的分布式抓取技术。你将了解分布式爬虫的核心原理、使用 Scrapy-Redis 改造单机爬虫、并通过真实案例实现多节点协同抓取。


为什么要使用分布式抓取

单机 Scrapy 受限于带宽、CPU 和 IP 资源,面对海量数据时效率低下。分布式抓取能带来三大核心优势:

  • 高并发:多台机器同时发起请求,吞吐量成倍提升。
  • 易扩展:随时增加工作节点,无需修改代码。
  • 去重稳定:利用 Redis 集合全局过滤重复 URL,避免重复抓取。

环境准备

在开始之前,请确保所有节点均安装以下组件:

  • Python 3.7+
  • Scrapy 2.5+
  • Redis 6.0+
  • scrapy-redis 库
pip install scrapy scrapy-redis redis

建议在每台工作节点上使用相同的 Python 环境和项目代码,可通过 Git 或 NFS 同步项目。


分布式抓取原理

Scrapy 默认的引擎、调度器、去重器都运行在单进程内存中。要实现分布式,需要将请求队列去重指纹共享到所有节点都能访问的地方。Redis 因其原子操作和高性能,成为实现这一目标的最佳选择。

核心架构

  • 调度器:使用 Redis 的 List 或 Zset 存储待抓取请求,所有节点从中获取。
  • 去重器:使用 Redis 的 Set 保存已抓取 URL 的指纹。
  • 数据管道:可选地将 Item 统一存入 Redis 或数据库,避免结果分散。

所有爬虫节点都作为消费者,从同一个 Redis 队列中获取任务,实现协同工作。


使用 Scrapy-Redis 构建分布式爬虫

scrapy-redis 是一个封装好的组件,提供了分布式所需的调度器、去重器和可继承的 Spider。

创建项目与基础爬虫

首先创建一个普通的 Scrapy 项目:

scrapy startproject dist_crawler
cd dist_crawler
scrapy genspider example example.com

安装 scrapy-redis 并修改 settings.py

settings.py 中添加或修改以下配置:

# 开启 scrapy-redis 调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"

# 使用 scrapy-redis 去重类
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

# 允许暂停,Redis 请求记录不丢失
SCHEDULER_PERSIST = True

# 指定 Redis 连接信息(默认连接 localhost:6379)
REDIS_HOST = '你的Redis服务器IP'
REDIS_PORT = 6379
# REDIS_PARAMS = {'password': 'your_password'}  # 如有密码

改造 Spider 为分布式 Spider

打开 spiders/example.py,将 Spider 的继承类改为 RedisSpider,并指定 redis_key

import scrapy
from scrapy_redis.spiders import RedisSpider

class ExampleSpider(RedisSpider):
    name = 'example'
    redis_key = 'example:start_urls'  # Redis 中存放起始 URL 的键

    def parse(self, response):
        # 提取需要的数据,生成 Item
        for item in self.parse_item(response):
            yield item

        # 提取新的链接,生成请求
        for next_url in response.css('a::attr(href)').getall():
            yield scrapy.Request(url=response.urljoin(next_url), callback=self.parse)

RedisSpider 不再使用 start_urls,启动后它会监听 Redis 中的 example:start_urls 列表,等待任务推入。

启动种子 URL

在任意一台能连接 Redis 的机器上,向 example:start_urls 推入一个起始 URL:

redis-cli lpush example:start_urls "http://example.com"

运行爬虫

在所有工作节点上执行相同的命令:

scrapy crawl example

每个节点都会从 Redis 队列中获取请求并处理,实现分布式抓取。


进阶配置

使用 Redis 优先级队列

默认调度器使用先进先出(FIFO)队列。如果需要优先抓取某些页面,可将 SCHEDULER_QUEUE_CLASS 改为优先级队列:

SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderPriorityQueue'

此时 Redis 使用 Zset 存储请求,通过控制权重来调整抓取顺序。

分布式数据处理

Item 也可直接写入 Redis,供后续统一清洗入库。在 pipelines.py 中使用 RedisPipeline

ITEM_PIPELINES = {
    'scrapy_redis.pipelines.RedisPipeline': 300,
}

Item 会被存储到 Redis 的 项目名:items 列表中,再用独立脚本批量消费。

Scrapyd 集群部署

为了方便管理多节点上的爬虫任务,可以使用 Scrapyd。在每台机器上安装并启动 Scrapyd:

pip install scrapyd
scrapyd

然后通过 scrapyd-deploy 将项目部署到所有节点,最后通过 API 或 ScrapydWeb 等工具统一调度。

集中调度示例:

curl http://node1:6800/schedule.json -d project=dist_crawler -d spider=example
curl http://node2:6800/schedule.json -d project=dist_crawler -d spider=example

各节点仍共享同一个 Redis,协同抓取。


完整示例:分布式抓取书籍信息

下面以一个抓取在线图书信息的分布式爬虫为例,展示完整流程。

items.py

import scrapy

class BookItem(scrapy.Item):
    title = scrapy.Field()
    price = scrapy.Field()
    url = scrapy.Field()

spiders/books.py

from scrapy_redis.spiders import RedisSpider
from dist_crawler.items import BookItem

class BooksSpider(RedisSpider):
    name = 'books'
    redis_key = 'books:start_urls'

    def parse(self, response):
        for book in response.css('article.product_pod'):
            item = BookItem()
            item['title'] = book.css('h3 a::attr(title)').get()
            item['price'] = book.css('p.price_color::text').get()
            item['url'] = book.css('h3 a::attr(href)').get()
            yield item

        next_page = response.css('li.next a::attr(href)').get()
        if next_page:
            yield response.follow(next_page, self.parse)

推入种子

redis-cli lpush books:start_urls "http://books.toscrape.com/"

在多个终端分别运行 scrapy crawl books 即可看到分布式抓取效果。


常见问题与优化

1. 单节点空跑,CPU 占用高

Redis 队列为空时,爬虫会进入忙等状态。可通过修改爬虫的 custom_settings,或使用 SCHEDULER_IDLE_BEFORE_CLOSE 设置空闲等待时间后自动关闭。

SCHEDULER_IDLE_BEFORE_CLOSE = 10  # 空闲10秒后关闭爬虫

2. Redis 内存压力

请求队列和去重集合会不断增长。建议:

  • 使用 Redis 的 maxmemory 策略,如 volatile-lru
  • 定期清理已完成的去重集合(但需谨慎,避免重复抓取)。

3. 反爬应对

分布式爬虫更容易触发目标网站的反爬策略。应做好:

  • 为不同节点配置不同的 User-Agent 和 IP。
  • 使用下载中间件添加随机延迟。
  • 引入代理 IP 池,在中间件中动态更换。

4. 数据一致性

如果多个节点同时写入数据库,需考虑并发控制。建议先将数据写入 Redis 或 Kafka,再用单消费者写入最终数据库。


总结

Scrapy-Redis 让你能够快速将单机爬虫改造为强大的分布式系统。核心思路是共享 Redis 中的请求队列和去重集合,使多个爬虫实例协同工作。结合 Scrapyd 和良好的反爬策略,你可以构建出高可用、可扩展的数据采集平台。

现在,尝试用本教程的内容改造你的第一个分布式爬虫吧!