网络爬虫系统设计

网络爬虫系统设计

设计一个网络爬虫系统,用于抓取互联网上的网页内容。重点包括给定种子 URL,爬取网页及其链接、支持可配置的爬取深度和频率、遵守 robots.txt 协议、避免重复爬取。

场景

设计一个网络爬虫系统,用于抓取互联网上的网页内容。

需求点:

  1. 给定种子 URL,爬取网页及其链接
  2. 支持可配置的爬取深度和频率
  3. 遵守 robots.txt 协议
  4. 避免重复爬取
  5. 每月爬取 10 亿个网页

估算

  • 月爬取量:10 亿页
  • 日爬取量:10 亿 / 30 ≈ 3300 万页/天
  • QPS:33,000,000 / 86400 ≈ 382 页/秒
  • 峰值 QPS:约 800 页/秒

存储估算:

  • 平均每页 500KB(HTML + 元数据)
  • 月存储量:10 亿 × 500KB = 500TB
  • 需要压缩存储和增量更新

设计

整体架构

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  Seed URLs  │────▶│   URL       │────▶│   URL       │
│             │     │  Frontier   │     │  Fetcher    │
└─────────────┘     └─────────────┘     └─────────────┘
                          ▲                    │
                          │                    ▼
                    ┌─────────────┐     ┌─────────────┐
                    │   URL       │◀────│   Content   │
                    │  Extractor  │     │   Parser    │
                    └─────────────┘     └─────────────┘
                                               │
                                               ▼
                                        ┌─────────────┐
                                        │   Storage   │
                                        │   (S3/HDFS) │
                                        └─────────────┘

核心组件

URL Frontier(待爬取队列)

管理待爬取的 URL 队列,负责:

  • 优先级调度:重要页面优先爬取
  • 礼貌性控制:同一域名间隔爬取
  • 去重:避免重复添加

数据结构:

┌─────────────────────────────────────────┐
│              URL Frontier               │
├─────────────────────────────────────────┤
│  优先级队列 (Priority Queue)             │
│    ├── P1: news.com, tech.com           │
│    ├── P2: blog.com, forum.com          │
│    └── P3: other sites                  │
├─────────────────────────────────────────┤
│  域名队列 (Per-host Queue)               │
│    ├── news.com: [url1, url2, ...]      │
│    └── tech.com: [url3, url4, ...]      │
└─────────────────────────────────────────┘

URL Fetcher(下载器)

  • 多线程并发下载
  • 支持 HTTP/HTTPS
  • 设置合理的超时和重试
  • 遵守 robots.txt

Content Parser(内容解析器)

  • 解析 HTML,提取文本内容
  • 提取页面中的链接
  • 处理不同字符编码

URL Extractor(链接提取器)

  • 从页面中提取新链接
  • URL 规范化(去除锚点、统一格式)
  • 过滤无效链接

遍历策略

BFS(广度优先)

从种子页面开始,逐层向外扩展。

优点:适合发现热门页面 适用:搜索引擎爬虫

DFS(深度优先)

沿着链接深入爬取,再回溯。

优点:内存占用小 适用:特定网站深度爬取

URL 去重

方案一:HashSet

Set<String> visited = new HashSet<>();

缺点:内存占用大,10 亿 URL 约需 100GB

方案二:Bloom Filter

BloomFilter<String> filter = BloomFilter.create(
    Funnels.stringFunnel(Charset.defaultCharset()),
    1_000_000_000,  // 预期元素数
    0.01            // 误判率
);

优点:内存占用小(约 1.2GB),查询 O(1) 缺点:有小概率误判(会漏爬)

方案三:分布式去重

使用 Redis 存储已访问 URL 的哈希值。

礼貌性爬取

  1. 遵守 robots.txt:检查是否允许爬取
  2. 限制频率:同一域名间隔 1-2 秒
  3. 设置 User-Agent:标识爬虫身份
  4. 限制并发:单域名最多 1-2 个并发
# robots.txt 示例
User-agent: *
Disallow: /admin/
Crawl-delay: 2

容错处理

  1. 超时重试:指数退避重试
  2. 死链处理:记录失败次数,超过阈值放弃
  3. 断点续爬:持久化爬取状态

总结

组件 技术选型
任务队列 Kafka / Redis
URL 去重 Bloom Filter / Redis
内容存储 S3 / HDFS
解析器 Jsoup / BeautifulSoup

核心挑战:

  1. 规模性:海量 URL 的存储和去重
  2. 礼貌性:避免对目标网站造成压力
  3. 鲁棒性:处理各种异常和恶意页面