Vanson's Eternal Blog

Python爬虫系统架构设计

Python spider basic.png
Published on
/18 mins read/---

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 Glacier7天热→冷→30天归档LZ4→ZSTD跨区3副本
结构化数据ClickHouse (主) + ES (搜索)TTL 3年ZSTD(6)双活
URL状态Redis Cluster (RDB+AOF)永久RDB 每6h+AOF实时
监控指标VictoriaMetrics15天ZSTD冷存

关键技术

反爬对抗体系

维度v1v2 升级
IP轮换代理池ISP+住宅IP双池 + 实时质量评分 (丢包率>5% → 拉黑)
TLS指纹ja3随机ja3n+ja4+http2 fingerprint 全链路随机
浏览器指纹500 模板指纹工厂(每次启动随机 Canvas/WebGL/Audio)
行为模拟鼠标轨迹完整交互链:鼠标→滚轮→键盘→悬停→延迟泊松分布
验证码打码平台混合策略:2Captcha + 自训练 CNN(YOLOv8)

IP轮换系统:

  • 代理池维护(数据中心IP+住宅IP混合)
  • 智能切换策略

行为指纹混淆

  • 鼠标轨迹模拟(贝塞尔曲线)
  • TLS指纹随机化(ja3算法)
  • 浏览器指纹库轮换(500+指纹模板)

运维保障体系

监控矩阵

指标SLISLO采集报警
抓取成功率2xx/(2xx+5xx)≥99.5 %Prometheus 10sAlertmanager
解析延迟P95<2 sOpenTelemetry 5sPagerDuty
代理健康success_rate≥90 %自研 exporter 30sWebhook
数据丢失未落盘消息数0Kafka lagDeadManSnitch

自动扩缩容

# 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 RuleES/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
  • 降级策略:跳过问题页面继续爬取
  • 熔断策略:对问题域名暂时停止爬取

人工处理流程

  • 异常聚合分析
  • 根本原因调查
  • 规则/代码调整
  • 回归验证

最佳实践建议

  • 建立异常知识库:
    • 记录历史异常及解决方案
    • 形成异常处理手册
  • 定期异常复盘:
    • 周度异常分析报告
    • 重大异常事后分析
  • 监控系统自监控:
    • 确保监控系统自身可靠
    • 监控数据采集完整性
  • 异常演练:
    • 定期模拟异常场景
    • 测试告警和处理流程