SWE(多帖) · Phone / VO Coding Q1

Anthropic Web Crawler:同主机 BFS、Fragment 去重与并发扩展

围绕公开面经的 HtmlParser API,实现同 hostname 爬取;说明去 fragment 去重、线程安全调度和多服务恢复。

题目重点:围绕公开面经的 HtmlParser API,实现同 hostname 爬取;说明去 fragment 去重、线程安全调度和多服务恢复。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 输入 startUrl 为可解析的绝对 URL,parser 给出可解析 URL;比较的是解析后的 hostname,不自动把 `http`/`https` 合并成同一文档。
  • 本训练版唯一规范化只移除 fragment,保留路径、查询参数、大小写等原样;题目提示需要 urldefrag,但未授权任意 URL 规范化。
  • 一次成功获取的页面最多扩展一次;抓取失败是否重试、返回结果顺序与重定向语义未见公开题面,先和面试官确认。

解题路线

  1. 单线程从 startUrl 入队;每次读 parser 返回链接,先 urldefrag,再解析 hostname,只有同 host 且未访问才原子地加入 visited 与待抓队列。visited 在入队时标记,可阻止环和菱形链接重复调度。
  2. 并发版把‘检查并加入 visited’置于同一把锁或单一调度器内;fetch 在锁外运行。Future 完成后将新链接提交池,保持有界 in-flight 数,避免页面爆炸把任务无界塞进 executor。
  3. 多个进程或服务器时,任务队列与去重集合需要共享且有持久化/租约语义:任务认领、处理、提交新链接、确认完成的顺序决定崩溃后会漏抓还是重抓。可接受至少一次抓取时,结果幂等去重比追求跨网络精确一次更简单。

手动走一遍

start 页面返回 `https://a.test/x#one` 与 `https://a.test/x#two`。去 fragment 后两者均为 `https://a.test/x`,只调度一次;`https://b.test/x` hostname 不同,被跳过。若 x 再链接 start,visited 阻止循环。

规模与取舍

设可达且规范化后唯一的同 host 页面 V、解析出的链接 E。单线程每条链接常数次解析/哈希,期望 O(V+E) 时间、O(V+E_frontier) 空间;网络耗时另计。并发版工作量仍相近,墙钟时间受请求延迟、worker 数、host 限速与锁竞争制约,不能简单除以线程数。

易错点与追问

容易失分的边界

  • 先查 visited、后加 visited 而不加锁,两个 worker 可同时重复提交。
  • 把 fragment 当页面身份,隐藏测试中的 unique URL 数会偏大。
  • 无界 Future 集合或多服务器无限抢占,内存与目标 host 都可能被压垮。
  • 把 URL 字符串切割当 hostname 解析,端口、查询、userinfo 容易误判。
  • 声称原题要求 Redis、重试次数和 politeness;这些是扩展讨论而非已知题面。

继续深挖

  • 如果获取超时而服务端已返回,如何避免链接遗漏并容忍重复抓取?
  • 多进程下 CPU 与 I/O 负载分别如何影响线程/进程选择?
  • 多服务器怎样用租约与幂等 frontier 处理 worker 崩溃?
✓已复制微信号!