Spider
主流爬虫系统
实现
graph TD
A[调度中心] --> B[URL管理器]
A --> C[下载器集群]
C --> D[解析器集群]
D --> E[数据存储]
F[监控中心] --> A & B & C & D & E
G[代理/IP池] --> C
H[缓存系统] --> C & D
调度中心
- 分布式任务调度:采用主从架构(如Celery+Redis/Kafka)
- 动态负载均衡:基于节点CPU/网络实时分配任务
- 优先级队列:支持VIP站点优先抓取(加权轮询算法)
URL管理器
去重系统:
短期去重:Bloom Filter(错误率<0.01%
)
长期去重:RocksDB存储指纹(SHA256)
下载器集群
多协议支持:HTTP/2, WebSocket, gRPC
连接池优化:
Keep-Alive连接复用(单机维持500+连接)
智能超时设置:
connect_timeout: 5s
read_timeout: 15s
total_timeout: 30s
自适应限流:令牌桶算法控制请求频率
解析器集群
多模式解析引擎
graph LR
HTML --> XPath解析
JSON --> JMESPath
JavaScript --> Headless Chrome
PDF --> Tika OCR
容错机制:Sandbox隔离环境防止解析崩溃
数据存储
- 原始页面:HDFS + Parquet 冷热分层(S3归档)
- 结构化数据:Elasticsearch + PG 主存储(TTL 3年)
- URL状态:Redis Cluster 持久化RDB+AOF
数据类型 | 存储 | 生命周期 | 压缩 | 备份 |
---|---|---|---|---|
原始页面 | HDFS Parquet + S3 Glacier | 7天热→冷→30天归档 | LZ4→ZSTD | 跨区3副本 |
结构化数据 | ClickHouse (主) + ES (搜索) | TTL 3年 | ZSTD(6) | 双活 |
URL状态 | Redis Cluster (RDB+AOF) | 永久 | — | RDB 每6h+AOF实时 |
监控指标 | VictoriaMetrics | 15天 | ZSTD | 冷存 |
关键技术
反爬对抗体系
维度 | v1 | v2 升级 |
---|---|---|
IP轮换 | 代理池 | ISP+住宅IP双池 + 实时质量评分 (丢包率>5% → 拉黑) |
TLS指纹 | ja3随机 | ja3n+ja4+http2 fingerprint 全链路随机 |
浏览器指纹 | 500 模板 | 指纹工厂(每次启动随机 Canvas/WebGL/Audio) |
行为模拟 | 鼠标轨迹 | 完整交互链:鼠标→滚轮→键盘→悬停→延迟泊松分布 |
验证码 | 打码平台 | 混合策略:2Captcha + 自训练 CNN(YOLOv8) |
IP轮换系统:
- 代理池维护(数据中心IP+住宅IP混合)
- 智能切换策略
行为指纹混淆
- 鼠标轨迹模拟(贝塞尔曲线)
- TLS指纹随机化(ja3算法)
- 浏览器指纹库轮换(500+指纹模板)
运维保障体系
监控矩阵
指标 | SLI | SLO | 采集 | 报警 |
---|---|---|---|---|
抓取成功率 | 2xx/(2xx+5xx) | ≥99.5 % | Prometheus 10s | Alertmanager |
解析延迟 | P95 | <2 s | OpenTelemetry 5s | PagerDuty |
代理健康 | success_rate | ≥90 % | 自研 exporter 30s | Webhook |
数据丢失 | 未落盘消息数 | 0 | Kafka lag | DeadManSnitch |
自动扩缩容
# Kubernetes HPA示例
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
minReplicas: 10
maxReplicas: 500
核心监控指标
基础运行指标
- 爬虫存活状态:进程/服务是否正常运行
- 运行时间:持续运行时长
- 内存使用:防止内存泄漏
- CPU占用率:避免资源耗尽
- 网络带宽:监控网络使用情况
爬取性能指标
- 请求速率:请求数/秒
- 成功率:HTTP 200响应比例
- 失败率:4xx/5xx错误比例
- 重试率:请求重试比例
- 响应时间:平均/最大/最小响应时间
数据质量指标
- 有效数据比例:解析成功的数据比例
- 重复数据比例:去重后的数据比例
- 数据完整性:必填字段完整比例
监控系统架构
[爬虫节点] → [日志收集] → [监控数据处理] → [存储] → [可视化/告警]
↘________[API上报] ↗
- 数据采集层
- 日志收集:Filebeat/Fluentd收集日志
- API上报:爬虫节点直接上报关键指标
- 中间件监控:代理池、数据库等组件的监控
- 数据处理层
- 流处理:Kafka+Flink实时处理
- 批处理:定时ETL作业
- 聚合计算:按时间窗口聚合指标
- 存储层
- 时序数据库:Prometheus/InfluxDB存储指标数据
- 日志存储:ELK存储详细日志
- 关系数据库:MySQL存储结构化监控数据
- 展示与告警层
- 可视化:Grafana/Kibana展示仪表盘
- 告警系统:Prometheus Alertmanager/PagerDuty
- 自定义报表:定期生成性能报告
关键监控点设计
- 反爬监控
- 封禁检测:验证码出现频率、403/429状态码
- 请求特征:User-Agent、Cookie使用情况
- 代理质量:代理IP可用率、响应时间
- 调度监控
- 队列深度:待抓取URL队列长度
- 调度延迟:URL从入队到被抓取的延迟
- 优先级分布:不同优先级URL的处理情况
- 存储监控
- 写入速率:数据存储速度
- 存储延迟:从抓取到存储的延迟
- 存储异常:写入失败次数
告警策略设计
- 分级告警
- P0紧急:爬虫宕机、持续高频失败
- P1重要:成功率下降、响应时间突增
- P2警告:资源使用率偏高、数据质量下降
- 告警方式
- 即时通知:短信/电话(P0)
- 及时通知:企业微信/钉钉/Slack(P1)
- 延迟通知:邮件/站内信(P2)
- 智能告警
- 基线告警:与历史基线对比
- 同比告警:与上周同期对比
- 预测告警:基于趋势预测问题
实现建议
- 使用现成组件
- Prometheus + Grafana 用于指标监控
- ELK 用于日志监控
- Sentry 用于错误追踪
- 自定义开发
- 爬虫健康检查API
- 数据质量验证模块
- 反爬策略检测模块
- 部署建议
- 监控系统与爬虫系统隔离部署
- 监控数据采样避免过高开销
- 设置监控系统的容灾备份
高级监控功能
- 分布式追踪:跟踪一个请求在整个系统中的流转
- 异常检测:自动发现异常模式
- 容量规划:基于历史数据预测资源需求
- 自动化修复:简单问题自动恢复(如重启进程)
通过以上设计,可以建立一个全面的爬虫监控系统,及时发现并解决问题,保障爬虫系统的稳定运行。
分布式追踪
Jaeger/OpenTelemetry 可以把「一次抓取任务」在分布式爬虫中的完整链路(调度 → 下载 → 解析 → 存储 → 回调)以 Trace 的形式展现出来,帮助你在秒级定位慢请求、失败原因、依赖拓扑。
- 可视化调用链:追踪一个URL从发现到存储的完整生命周期
- 性能分析:精确测量各环节耗时(下载、解析、存储)
- 错误定位:快速定位失败请求的问题环节
- 依赖分析:识别系统瓶颈(如代理池或数据库延迟)
场景:
- 单进程爬虫:把每个 URL 的抓取全过程当做一个 Trace,内部再拆成 DNS、TCP、TLS、首包、解析、入库等 Span。
- 分布式爬虫:调度器、下载器、解析器、存储层都是独立服务/容器,通过 Trace-Context 把 Span 串起来。
- 分布式爬虫集群
- 多阶段处理流水线(下载→解析→存储)
- 复杂爬取逻辑(递归抓取、AJAX请求等)
- 需要分析反爬策略影响的场景
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.jaeger.thrift import JaegerExporter
# 初始化Jaeger
trace.set_tracer_provider(TracerProvider())
jaeger_exporter = JaegerExporter(
agent_host_name="jaeger-agent",
agent_port=6831,
)
trace.get_tracer_provider().add_span_processor(
BatchSpanProcessor(jaeger_exporter)
)
tracer = trace.get_tracer(__name__)
def fetch_url(url):
with tracer.start_as_current_span("fetch_url") as span:
span.set_attribute("http.url", url)
try:
# 实际请求逻辑
response = requests.get(url)
span.set_attribute("http.status_code", response.status_code)
return response
except Exception as e:
span.record_exception(e)
span.set_status(trace.Status(trace.StatusCode.ERROR))
raise
def parse_content(html):
with tracer.start_as_current_span("parse_content") as span:
# 解析逻辑
return data
常见坑 & 建议
问题 | 做法 |
---|---|
Trace 爆炸 | 使用“尾部采样”或“按错误采样”策略,避免每条 URL 都落盘。 |
网络耗时失真 | 把 DNS 解析、TCP 握手、TLS 握手、首字节拆成独立 Span。 |
标签基数过大 | URL 不要直接放到 tag,可哈希或用 <scheme>://<host> 。 |
跨语言 | 统一走 OpenTelemetry 协议,Jaeger/Zipkin/SkyWalking 都能接。 |
[爬虫节点] → [OpenTelemetry SDK] → [Jaeger Agent] → [Jaeger Collector] → [Storage]
↓
[监控UI] ← [Jaeger Query] ← [Spark分析作业]
Sentry主动上报
核心优势
- 实时错误警报:第一时间发现爬虫异常
- 完整上下文:捕获错误发生时的变量状态、调用栈和请求信息
- 智能聚合:自动归类相似错误,避免告警风暴
- 丰富集成:与主流爬虫框架(Pyppeteer/Scrapy/Requests等)无缝对接
- 爬虫追踪环节与属性记录规范
适合的爬虫错误类型
- 网络请求异常(连接超时、SSL错误等)
- 反爬机制触发(验证码、封禁等)
- 数据解析失败(XPath/CSS选择器失效)
- 存储写入异常(数据库约束冲突等)
- 内存泄漏和系统级错误
实例
基础配置
import sentry_sdk
from sentry_sdk.integrations.httpx import HttpxIntegration
from sentry_sdk.integrations.redis import RedisIntegration
def init_sentry():
sentry_sdk.init(
dsn="https://your-key@sentry.io/your-project",
integrations=[
HttpxIntegration(),
RedisIntegration(),
],
traces_sample_rate=0.2, # 性能追踪采样率
environment="production",
release="crawler-v1.2.3",
attach_stacktrace=True,
send_default_pii=False, # 根据隐私要求配置
# 爬虫特定配置
max_breadcrumbs=50,
debug=False,
)
爬虫专用集成配置
# Scrapy集成示例
class SentryMiddleware:
@classmethod
def from_crawler(cls, crawler):
init_sentry()
return cls()
def process_spider_exception(self, response, exception, spider):
sentry_sdk.capture_exception(exception)
return None
# Playwright/Puppeteer集成
async def intercept_console(msg):
if msg.type == 'error':
sentry_sdk.capture_message(
f"Browser console error: {msg.text}",
level="error"
)
page.on('console', intercept_console)
典型看板配置
- 错误分类看板
- 按错误类型(网络/解析/存储)分组
- 按目标站点统计错误率
- 随时间变化的错误趋势
- 反爬监控看板
- 封禁类型分布(IP/User-Agent/Cookie)
- 验证码触发频率
- 反爬规则演变趋势
- 数据质量看板
- 字段缺失率TOP10
- 数据格式错误统计
- 解析失败页面类型分布
维度 | Sentry 主动上报 | 日志采集再转指标 |
---|---|---|
实时性 | 进程内即刻发,秒级可见 | 取决于采集/解析批处理,分钟级 |
精度 | 精确 Counter/Histogram | 日志采样或截断,易失真 |
资源占用 | 小(UDP/TCP 轻量) | 大(磁盘 IO + 日志解析 CPU) |
查询/报警 | Sentry Alerts、Prometheus Rule | ES/Loki → Grafana/Alertmanager |
成本 | Sentry 额度或自建 StatsD | 日志存储贵、索引膨胀 |
适用场景 | 高频业务指标、RED 三件套 | 低频或事后分析型指标、审计 |
追踪环节 | 应记录的属性 | 特殊处理 |
---|---|---|
URL调度 | ||
• 队列类型 | • 记录入队/出队时间戳 | |
• 优先级 | • 标记紧急任务标识 | |
• 调度延迟 | ||
网络请求 | ||
• URL | • 记录请求头(脱敏) | |
• HTTP方法 | • 记录响应前1KB内容 | |
• 状态码 | • 标记重定向链 | |
• 重试次数 | ||
代理使用 | ||
• 代理IP(哈希处理) | • 标记代理切换事件 | |
• 代理响应时间 | • 关联代理池健康状态 | |
• 代理可用状态 | ||
反爬处理 | ||
• 验证码类型(滑动/点选/计算等) | • 关联原始请求的TraceID | |
• 处理耗时 | • 记录验证码识别中间结果 | |
• 处理结果(成功/失败) | ||
数据解析 | ||
• 解析器版本 | • 记录解析前后数据样本 | |
• 选择器路径 | • 保留失败字段的HTML片段 | |
• 字段缺失情况 | ||
数据存储 | ||
• 存储后端(MySQL/ES/Kafka等) | • 标记重试次数 | |
• 写入耗时 | • 记录异常时的数据快照 | |
• 写入结果(成功/部分成功/失败) |
异常
异常分类监控
- 网络层异常
- 连接异常:
- 连接超时(TCP连接失败)
- SSL握手失败
- DNS解析失败
- 请求异常:
- 4xx错误(特别是403/404/429)
- 5xx错误(特别是502/503/504)
- 非标准状态码(如200但返回错误页)
- 连接异常:
- 反爬异常
- 验证码触发:
- 验证码出现频率
- 验证码识别失败率
- 封禁特征:
- IP封禁(特定状态码或跳转)
- User-Agent封禁
- Cookie失效
- 请求频率限制触发
- 验证码触发:
- 数据解析异常
- 结构异常:
- HTML结构变更(XPath/CSS选择器失效)
- JSON结构变更(字段缺失或类型变化)
- 数据编码异常(乱码)
- 内容异常:
- 数据为空或占位符(如"暂无数据")
- 数据格式错误(日期/数字格式不符)
- 数据逻辑矛盾(如结束时间早于开始时间)
- 结构异常:
- 系统级异常
- 资源异常:
- 内存泄漏(内存持续增长)
- 线程/协程泄漏
- 文件描述符耗尽
- 依赖异常:
- 数据库连接失败
- 代理池枯竭
- 中间件(Redis/Kafka)不可用
- 资源异常:
关键仪表盘
- 异常总览看板:
- 异常趋势图(按类型/严重程度)
- TOP异常来源(域名/页面类型)
- 异常影响面(受影响数据比例)
- 反爬监控看板:
- 封禁IP数量
- 验证码触发频率
- 成功绕过比例
- 解析异常看板:
- 选择器失效统计
- 数据字段缺失率
- 数据格式错误分布
采集指标
- 异常时间戳
- 异常类型(分类编码)
- 异常描述
- 相关URL
- 请求头信息(脱敏后)
- 响应片段(前1KB)
- 当前爬虫状态(内存、并发数等)
- 环境信息(IP、代理、User-Agent)
高级检测方法
- 模式识别:检测异常响应内容模式(如封禁页面特征)
- 行为分析:检测爬虫行为异常(如突然大量重定向)
- 机器学习:无监督学习检测异常集群
自动处理策略
- 重试策略:临时错误自动重试(带退避算法)
- 切换策略:自动切换代理/User-Agent
- 降级策略:跳过问题页面继续爬取
- 熔断策略:对问题域名暂时停止爬取
人工处理流程
- 异常聚合分析
- 根本原因调查
- 规则/代码调整
- 回归验证
最佳实践建议
- 建立异常知识库:
- 记录历史异常及解决方案
- 形成异常处理手册
- 定期异常复盘:
- 周度异常分析报告
- 重大异常事后分析
- 监控系统自监控:
- 确保监控系统自身可靠
- 监控数据采集完整性
- 异常演练:
- 定期模拟异常场景
- 测试告警和处理流程