- 自动会话管理
- 锁定 195 个国家/地区的任意城市
- 无限并发会话
URL 待爬取队列
简而言之:URL 待爬取队列是一种数据结构,用于保存爬虫已发现但尚未抓取的所有 URL。它决定接下来爬取什么,并确保向同一主机发送的请求保持合理间隔。
URL 待爬取队列是任何网页爬虫的核心。新发现的 URL 进入队列,爬虫从中取出 URL 进行抓取,再将页面中新发现的链接加入队列。对于简单的爬虫,待爬取队列可能只是一个列表;对于生产环境中的爬虫,它则是一个复杂组件,需要在数十亿个 URL 的规模下处理优先级、礼貌爬取、去重以及持久化。
待爬取队列需要处理什么:
- 排序:根据发现顺序、优先级得分或内容新鲜度要求,决定接下来抓取哪个 URL。
- 确保礼貌爬取:即使同一主机有数千个 URL 排队等待,也要确保向该主机发送的连续请求保持间隔。
- 去重:在URL 规范化合并等效变体后,拒绝已爬取或已进入队列的 URL。
- 持久化:在爬虫重启后保留队列中的任务;对于持续数天的爬取任务,这一点尤为重要。
- 规模化:保存数量远超内存容量的 URL,因此需要将数据写入磁盘或分布式存储。
双层队列架构:
斯坦福大学的《信息检索导论》介绍了一种经典的待爬取队列架构,将问题拆分为两个队列层。
前端队列负责优先级管理。每个前端队列保存某个优先级的 URL,选择器会更频繁地从高优先级队列中取出 URL。优先级可以反映页面的重要性、更新频率或业务价值。
后端队列负责礼貌爬取。每个后端队列只保存一台主机的 URL。堆结构会记录各主机最早可再次接收请求的时间。爬虫始终从下一个可发送请求的主机队列中取出 URL,因此既能遵守爬取延迟,又不必在等待某台主机时暂停整个任务。
这种分层设计使爬虫能够在保持较高总体速度的同时,合理控制对每台服务器的请求频率。
待爬取队列中的状态:
DISCOVERED → 已从页面中提取 URL,尚未验证 QUEUED → 已通过范围和去重检查,正在队列中等待 IN_FLIGHT → 正在抓取 COMPLETED → 已成功抓取并提取链接 FAILED → 抓取失败,可在退避后重试 SKIPPED → 因范围规则、robots.txt 或深度限制而被跳过
明确跟踪状态,可以避免待爬取队列最常见的两类问题:重复抓取已经处理的 URL,以及工作进程崩溃时丢失正在抓取的 URL。
大规模去重:
对于每个新发现的链接,待爬取队列都必须回答“此前是否见过这个 URL?”。一次爬取任务中,这种检查可能需要执行数十亿次。当规模达到一定程度后,用哈希集合保存完整 URL 就不再切合实际。
生产环境中的爬虫通常会将规范化后的 URL 哈希为固定长度的指纹,并且只存储指纹。如果能够接受较低的误判率,布隆过滤器是常见选择,因为它占用的内存远少于精确集合。代价是:误判会悄然丢弃实际上从未爬取过的 URL。因此,需要完整覆盖的系统通常会将布隆过滤器与精确的后端存储结合使用。
分布式待爬取队列:
当爬取任务跨越多台机器时,待爬取队列必须共享或分区。按主机分区是标准做法:通过主机名的哈希值,确定由哪个工作节点负责该主机的 URL。这样,同一主机的礼貌爬取逻辑就集中在一台机器上,便于执行单主机速率限制。
另一种方案是使用集中共享的待爬取队列。这种方案更容易理解,但可能成为吞吐量瓶颈和单点故障。大多数大规模系统选择分区,并接受将新发现的 URL 路由给对应工作节点所带来的额外复杂性。
待爬取队列如何影响结果:
待爬取队列的设计决定了爬取任务最终会获得什么。纯先进先出队列采用广度优先遍历,先处理较浅层级的页面。按优先级排序的队列可以更早抓取高价值页面,这在任务可能提前结束时尤为重要。如果队列不考虑内容新鲜度,就会以相同频率重新爬取新旧页面,浪费请求去获取自上次增量爬取以来并未变化的内容。
Bright Data 的爬虫 API会在内部管理待爬取队列的状态、去重和单主机请求调度,让爬取任务能够扩展规模,而无需自行构建队列层。