简易异步爬虫引擎的设计,主要分为核心功能模块和架构设计两个部分:
一、 核心功能模块设计
引擎包含以下七个核心组件:
1. 调度器 (Scheduler)
需要一个容器(优先级队列)来管理待抓取的 URL。
需要支持 URL 去重功能,避免重复抓取浪费资源。
需要能判断优先级,比如详情页优先级高于列表页。
支持按域名分组调度,避免同一域名请求过于集中。
支持断点续爬,爬取进度持久化存储。
2. 异步下载器 (Downloader)
引擎的"手脚"。基于
httpx封装(或者aiohttp)。并发控制,限制同时请求的数量,防止把目标服务器搞崩或者被封IP。
需要设计重试机制,遇到网络波动自动重试。
速率限制,支持单域名请求间隔控制。
随机延迟,模拟人类行为,降低被封风险。
3. 解析器 (Parser)
引擎的"眼睛"。负责从 HTML/XML/JSON/TEXT 中提取数据。
设计成可插拔的形式,不同的网站配置不同的解析规则(XPath 或 CSS Selector)。
支持自动编码检测与转换。
4. 数据管道 (Pipeline)
设计一个出口接口,支持保存为 JSON、CSV 或者存入数据库,把存储逻辑和爬取逻辑解耦。
支持异步写入,不阻塞爬取流程。
数据去重机制,避免重复存储。
5. 异常与日志监控 (Monitor)
引擎需要有"黑匣子"日志记录,记录请求耗时、成功失败率、错误详情。
实时统计面板,展示爬取进度、成功率、剩余任务数等。
错误告警机制,异常率超过阈值时发出警告。
6. 中间件系统 (Middleware) —— 新增
请求中间件: 请求发出前进行处理。
自动添加/轮换 User-Agent
Cookies 管理
Referer 自动填充
请求签名(应对反爬)
响应中间件: 响应返回后进行处理。
自动解码
异常状态码处理
异常中间件: 统一异常处理入口。
7. 代理管理器 (ProxyManager)
代理池管理,支持从文件/API/数据库加载代理。
代理轮换策略(随机/顺序/权重)。
失效代理检测与自动剔除。
支持认证代理。
二、 架构设计思路
采用 生产者-消费者模型 来设计整体的数据流向:
┌─────────────────────────────────────────────────────────────────┐
│ 配置管理层 │
│ settings.py / YAML / 环境变量 │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 引擎核心 (Engine) │
├────────────┬────────────┬────────────┬────────────┬─────────────┤
│ 调度器 │ 下载器 │ 解析器 │ 管道 │ 监控 │
│ Scheduler │ Downloader │ Parser │ Pipeline │ Monitor │
└─────┬──────┴─────┬──────┴─────┬──────┴─────┬──────┴──────┬──────┘
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ 中间件层 (Middleware) │
│ 请求中间件 │ 响应中间件 │ 异常中间件 │ Spider中间件 │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 代理管理器 (ProxyManager) │
└─────────────────────────────────────────────────────────────────┘数据流转流程
1. 入口:
你将起始 URL 放入调度器队列。
2. 循环引擎:
这是异步的核心。引擎不断从调度器取出 URL,分发给空闲的下载器协程。下载完成后,将结果传给解析器。
3. 中间件处理:
请求发出前,经过请求中间件处理(添加 UA、Cookies 等)。
响应返回后,经过响应中间件处理(解码、状态检查)。
4. 数据流转:
解析器提取数据后,做两件事:
将新的 URL 推回调度器队列(生产者)。
将有效数据推送到数据管道进行保存。
5. 异步处理:
利用 Python 的 httpx 库,让下载器在等待网络 I/O 时挂起,转而去处理其他请求,这样能极大提高并发效率。
三、 异常处理策略
重试机制详解
第1次重试:等待 1 秒
第2次重试:等待 2 秒
第3次重试:等待 4 秒
超过3次:标记为失败,记录日志四、 配置管理
建议使用 dataclass 或 YAML 文件管理配置:
@dataclass
class Settings:
CONCURRENCY: int = 10 # 并发数
REQUEST_DELAY: float = 0.5 # 请求间隔(秒)
RANDOM_DELAY: tuple = (0.1, 0.5) # 随机延迟范围
TIMEOUT: int = 30 # 超时时间
MAX_RETRIES: int = 3 # 最大重试次数
USER_AGENT: str = "..." # 默认 UA
PROXY_ENABLED: bool = False # 是否启用代理
LOG_LEVEL: str = "INFO" # 日志级别五、 目录结构建议
spider_engine/
├── init.py
├── engine.py # 引擎核心
├── scheduler.py # 调度器
├── downloader.py # 下载器
├── parser.py # 解析器基类
├── pipeline.py # 数据管道
├── monitor.py # 监控模块
├── middleware/ # 中间件
│ ├── init.py
│ ├── base.py # 中间件基类
│ ├── request.py # 请求中间件
│ └── response.py # 响应中间件
├── proxy/ # 代理管理
│ ├── init.py
│ └── manager.py
├── utils/ # 工具函数
│ ├── init.py
│ └── helpers.py
└── settings.py # 配置文件