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
 - 降级策略:跳过问题页面继续爬取
 - 熔断策略:对问题域名暂时停止爬取
 
人工处理流程
- 异常聚合分析
 - 根本原因调查
 - 规则/代码调整
 - 回归验证
 
最佳实践建议
- 建立异常知识库:
- 记录历史异常及解决方案
 - 形成异常处理手册
 
 - 定期异常复盘:
- 周度异常分析报告
 - 重大异常事后分析
 
 - 监控系统自监控:
- 确保监控系统自身可靠
 - 监控数据采集完整性
 
 - 异常演练:
- 定期模拟异常场景
 - 测试告警和处理流程
 
 

