聊抓取预算时,多數人第一反應是看服務器的响應時間,却容易忽略另一头:頁面本身有多重。同样一條抓取线程,抓一個 20KB 的頁面和抓一個 2MB 的頁面,花掉的時間和带宽完全不是一個量級。当站点有几十萬條 URL 时,這種差异會直接体現在「每天到底抓了多少頁」上。
一次抓取要消耗哪些资源
蜘蛛訪問一個 URL,大致经過几步:建立连接、發送請求、等待首字节、下载完整响應体、解析 HTML、從里面提取新連結放進待抓取队列。响應時間影响的是前几步,而後面下载與解析的耗时,主要由頁面体积和 HTML 结构决定。
也就是说,即使你把 TTFB 压到 100 毫秒,只要每個頁面都是 1.5MB 的庞然大物,抓取速率依然上不去。限額是按請求數或時間窗口算的,單頁越重,單位時間里能走完的 URL 就越少。
HTML 變重的几個常见来源
- 内联的大段資料:為了省一次接口請求,把整份列表、配置項、多語言文案直接塞進 script 标簽。首屏是快了,但每個 HTML 都跟着几百 KB 的文本。
- base64 内嵌的图片和字体:原图轉碼後体积通常會變大,而且它會随每一次 HTML 下载重复传輸,缓存也帮不上忙。
- 层級很深、节点很多的 DOM:模板层层嵌套、包装元素一大串,解析和提取連結都要多花時間。
- 超長的連結列表:一頁塞進几千條連結,常见于全站归档、标簽云、歷史文章匯總這類頁面。
- 過長的 URL 與冗余參數:參數层层叠加,URL 本身就能寫到几百字符,抓取记錄里也不好看。
連結是不是越多越好
有些站点喜欢在一個頁面里罗列所有入口,觉得這样能加快 URL 發現。實际情况是,一頁几千條連結會带来两個副作用:一是解析成本上升,二是分配到單條連結上的關注度被稀释。蜘蛛需要判断先抓哪些、後抓哪些,列表太長反而让它难以取舍。
更稳妥的做法是分层:首頁和栏目頁放最重要的入口,归档頁按時間或分類切分,每頁控制在合理條數,靠翻頁和分類目錄把長尾 URL 一层层展開。這样每條連結都處在相對明确的上下文里,發現路径也更清晰。
传輸层能省的部分
開啟 gzip 或 brotli 压缩,對文本型 HTML 的效果通常很明顯,很多时候能把体积压掉六七成。使用 HTTP/2 可以让同一站点的多次請求复用连接,减少握手的開销。静態资源則尽量走 CDN 並設定合理的缓存头,避免蜘蛛每次抓頁都要连带拉一遍重复内容。
還有一点常被忽略:如果頁面依赖 JS 渲染後才出現正文和連結,蜘蛛需要经歷「先拿 HTML、再排队渲染」两段時間,整体成本會更高。能在服務端直出的内容,尽量直出。
可以動手做的調整
- 检查几個代表性頁面的 HTML 体积,尤其是列表頁和詳情頁,看看排在前面的「重量級選手」是谁。
- 把内联的大段 JSON 挪到獨立接口,或用按需加载的方式拆分。
- 图片、字体改用外鏈资源,配合缓存策略,不要長期用 base64 内嵌。
- 精简模板嵌套,去掉只為样式服務的多余包装层。
- 归档頁、标簽頁設定分頁,每頁連結數量控制在几十到一两百條。
- 確認服務器已開啟压缩,並检查压缩是否對 HTML 類型生效。
抓取效率是「响應速度」和「頁面重量」共同决定的。只優化其中一头,效果往往有限。
這些調整不會立刻带来可见變化,但它們影响的是長期成本:同样一份抓取額度,轻量頁面能覆盖更多 URL,新内容的發現也就更及时。與其反复猜测蜘蛛的偏好,不如先把每個頁面做得更利落一点。