人人都会AI编程

21.3 爬虫框架 Scrapy:架构、中间件、管道、分布式爬虫

更新时间:2026-07-12

当你需要采集的网站不止一两个,而是成百上千,且对数据质量、爬取速度、异常处理有工程化要求时,自己用 requests + BeautifulSoup 从头搭建爬虫就会变得吃力。Scrapy 正是为此而生——一个成熟、高性能、可扩展的企业级爬虫框架。

Scrapy 的核心架构

Scrapy 基于 Twisted 异步网络引擎,天生支持高并发请求。它的核心组件及数据流大致如下:

  1. 引擎(Engine):控制所有组件之间的数据流,触发事件。
  2. 调度器(Scheduler):接收引擎发来的请求,排入队列,并在引擎请求时返回下一个要抓取的请求。支持去重(默认根据 URL 指纹)。
  3. 下载器(Downloader):负责获取网页内容并返回给引擎,再由引擎交给 Spider。
  4. 爬虫(Spider):用户自定义的解析逻辑。从响应中提取数据和新的请求链接(跟进爬取)。
  5. 项目管道(Item Pipeline):处理由 Spider 提取的数据(Item),进行清洗、验证、去重、存储等。
  6. 下载器中间件(Downloader Middleware):在引擎与下载器之间,可以全局修改请求和响应。
  7. 爬虫中间件(Spider Middleware):在引擎与 Spider 之间,可以处理 Spider 的输入(响应)和输出(Item、请求)。

整个流程是:Spider → Engine → Scheduler → Engine → Downloader → Engine → Spider,形成一个闭环,直到队列中没有新的请求。

Spider:聚焦解析逻辑

你开发的 Spider 类只需要定义两个核心部分:

  • start_requests / start_urls:生成初始请求。
  • parse 方法:接收下载器返回的 Response 对象,用 CSS 选择器或 XPath 提取数据,构造成 Item 对象(或字典)yield 给管道;同时可以 yield scrapy.Request(url, callback=self.parse) 继续抓取后续页面。

Scrapy 内建的 scrapy shell 是调试选择器的利器,你可以加载一个 URL 后直接在命令行里测试 CSS / XPath。

中间件:扩展与控制

中间件可以理解为“全局钩子”,让你通过最小代价实现爬虫的通用功能。

  • 下载器中间件:主要用于处理请求/响应。典型应用:
  • 设置随机 User-Agent、代理 IP
  • 处理 Cookie、重定向
  • 集成 Selenium 或 Playwright 处理动态渲染页面(如 scrapy-playwright
  • 爬虫中间件:较少直接使用,主要处理异常、调整 Spider 的输出。

自定义中间件只需实现对应方法(如 process_request(self, request, spider)),在 settings.py 中配置激活即可。

Item Pipeline:数据清洗与存储

当 Spider 产出一个 Item(或字典)后,它会被依次传到所有开启的 Pipeline 类中。每个 Pipeline 必须实现 process_item(self, item, spider) 方法,在其中可以做:

  • 数据清洗:去除空值、格式化日期、转换数字类型
  • 去重验证:检查数据库中是否已存在,决定是否丢弃
  • 存储入库:保存到 MySQL、MongoDB、CSV 文件等
  • 触发后续动作:比如写入 Kafka、发送通知

示例:一个简单的 JSON 存储 Pipeline。

import json

class JsonWriterPipeline:
    def open_spider(self, spider):
        self.file = open('items.json', 'w')

    def close_spider(self, spider):
        self.file.close()

    def process_item(self, item, spider):
        line = json.dumps(dict(item), ensure_ascii=False) + "\n"
        self.file.write(line)
        return item

settings.py 中通过 ITEM_PIPELINES 字典注册并设置优先级(数字越小优先级越高)。

分布式爬虫:突破单机瓶颈

面对海量 URL,单机 Scrapy 会触及性能上限。分布式爬虫的思路是:共享请求队列和去重集合

  • 核心组件 Scrapy‑Redis:用 Redis 数据库替代 Scrapy 默认的调度器和去重器。所有爬虫节点都从同一个 Redis 队列中取请求,并将新请求推入同一个队列。
  • 改造极简:只需让你的 Spider 继承 RedisSpider(或 RedisCrawlSpider),并使用 redis_key 而不是 start_urls。然后启动多个爬虫进程(甚至在不同机器上),它们会自动协调。
  • 常见部署:结合 Scrapyd(Scrapy 守护进程管理)或者 Docker + Kubernetes 管理节点,形成一套可水平扩展的抓取集群。

生产实践要点

  • 遵守 robots.txt:默认 Scrapy 会遵守,但在合法合规范围内可调整。
  • 设置下载延迟DOWNLOAD_DELAYAUTOTHROTTLE 自动限速,既保护目标站点,也降低被封风险。
  • 日志与监控:Scrapy 内置详细日志,搭配 scrapy‑logstash 或其他扩展,可实时监控爬虫运行状态。
  • 异常处理:利用 RetryMiddleware 自动重试失败请求,配合代理池确保高可用。

Scrapy 的学习曲线略高于简单脚本,但一旦掌握,它便成为你手中处理大规模数据采集的利器,让爬虫工程从“能跑”进化到“稳定、可维护、可扩展”。