谈抓取预算时,讨论常常停留在 URL 數量上:有多少頁面、有多少内鏈、有多少參數组合。但蜘蛛的時間並不是按頁面數量平均分配的,而是按一次請求從建立连接到讀完响應体所消耗的时長来分配。同样是一千個 URL,每個返回 30KB 的 HTML 與每個返回 500KB 的 HTML,能走完的轮次差別很大。
一次抓取的成本由什么构成
把一次抓取拆開看,大致包含几段開销:
- 连接建立:DNS 解析、TCP 握手,使用 HTTPS 时還有 TLS 协商;
- 服務端處理與首字节時間(TTFB);
- 响應体传輸:字节數、压缩方式、可用带宽;
- 客戶端解析與渲染:构建 DOM、执行必要的脚本、提取連結。
其中传輸和解析這两段最容易在改版中被悄悄放大。模板里多塞几百 KB 的内容,成本會平摊到之後的每一次抓取上,而且很难從抓取數量上直接看出原因。
HTML 体积是從哪里膨胀起来的
把几類常见情况列出来,通常能對上号:
- 把接口返回的 JSON 直接序列化進頁面,作為初始狀態;
- 图标、小图、字体用 base64 内联在 HTML 或 CSS 中;
- 模板注释、調试代碼、已经下线的模块没有清理;
- 統計、客服、實驗類脚本在模板里同步加载;
- 同一套 SVG 图标在列表中被反复内联。
這些内容對蜘蛛發現 URL 几乎没有帮助,却要和正文、連結一起传輸和解析。它們不會直接導致頁面不被抓取,但會让同一份抓取能力覆盖的頁面變少。
压缩與传輸方式的影响
開啟 gzip 或 brotli 之後,HTML 的传輸体积通常可以降到原来的三分之一甚至更低,這是投入产出比很高的一項調整。需要注意的是压缩要覆盖 HTML 本身,而不只是静態资源;有些配置只對 css、js 文件生效,動態頁面反而没有压缩。
分块传輸本身不是問题,但如果頁面是邊查資料库邊輸出的流式渲染,首字节時間會被拉長,蜘蛛需要更久才能拿到完整响應。缓存命中率高的頁面通常首字节更快,這也是列表頁、分類頁值得做缓存的直接原因。
DOM 深度與連結提取
拿到 HTML 之後,蜘蛛還要解析结构才能提取連結。連結埋在十几层容器之下,或者必须等脚本执行後才插入,提取成本都會上升。這不是要求把所有结构压平,而是導航、分類、分頁這類承担 URL 發現职责的連結,應该尽量放在稳定、浅层、服務端就已存在的结构里。
瘦身的優先顺序
- 先統計响應体大小分布,找出体积最大的那批頁面模板,通常集中在列表頁和詳情頁;
- 確認 HTML 响應是否開啟压缩,静態资源是否設定了合理的缓存头;
- 把内联的脚本、样式、图标改為可缓存的外部文件,减少重复传輸;
- 清理模板中的注释、調试代碼和已经下线的组件;
- 對首屏不需要的第三方脚本做延迟加载,避免阻塞頁面輸出。
調整之後不必期待抓取量立刻變化,可以對照服務器日誌里的响應字节數和响應時間,看一段時間内的趋势是否稳定下降。
抓取吞吐大致是時間與字节數的乘积關系:让每個頁面更轻,等于在同一段抓取時間里腾出了更多 URL 的位置。
URL 發現、内鏈结构、Sitemap 决定了蜘蛛能被带到哪里,而頁面本身的重量决定了它在一段時間内能走多遠。两者不是替代關系,但後者常常因為不顯眼而被長期忽略。