搜尋抓取

頁面越重,蜘蛛走得越慢:HTML 体积與 DOM 深度如何影响抓取

抓取問题常被简化為“蜘蛛有没有找到 URL”,但頁面本身的体积與结构复杂度同样消耗抓取资源。本文拆開两筆帳:請求數與响應字节數,說明 HTML 膨胀和 DOM 深度怎样拖慢解析、脚本渲染為什么成本更高,並给出用日誌自查與几項可落地的精简動作。

搜尋抓取

頁面越重,蜘蛛走得越慢:HTML 体积與 DOM 深度如何影响抓取

讨论抓取时,多數人盯着“蜘蛛有没有發現這個 URL”。但發現只是第一步,蜘蛛還要把頁面讀完、抽出連結、判断内容,然後才决定下一次来不来。頁面本身有多重、解析起来有多費劲,會直接影响一台爬虫在一段時間里能走完多少頁面。

抓取预算的两筆帳:請求數和字节數

搜尋引擎分配给站点的抓取资源,大致可以從两個维度看:單位時間内發起的請求數,以及愿意為每個請求讀取的响應字节。請求數决定蜘蛛能覆盖多少 URL,字节數决定它一次能讀多深。两者會互相挤占:如果一個頁面的响應体特別大,蜘蛛在這個 URL 上停留的時間變長,同样的抓取窗口里能處理的 URL 就變少。

對小站来说這通常不是問题;但当站点有成千上萬個 URL,且其中一部分頁面異常臃肿时,抓取队列的推進速度會明顯被拖住。

HTML 体积從哪里膨胀

同一個頁面,内容差不多,輸出体积可能差好几倍。常见的几個来源:

  • 内联资源:把大量 CSS、JavaScript 甚至 base64 编碼的图片直接寫進 HTML,每次响應都要重复传輸一遍。
  • 模板残留:注释掉的模块、隐藏的 DOM、重复輸出的结构化資料,用戶看不到,蜘蛛照單全收。
  • 列表渲染:列表頁一次輸出几百條记錄,每條又带完整的卡片结构。
  • 未压缩的响應:服務端没有開啟 gzip 或 brotli,文本類 HTML 白白多传好几倍。

DOM 深度與节点數量

体积之外,结构本身的复杂度也有成本。蜘蛛需要解析 HTML、构建节点树,再從里面提取連結。层次很深、节点极多的文档,解析耗时更長,連結也更容易被埋在大段样板里。

常见的坏味道包括:為了布局而寫下的多层無意义嵌套、在每個列表項里重复完整導航、把正文拆成大量细碎的行内标簽。這些都不會让頁面變得更好理解。

連結密度比連結數量更重要

頁面里連結多不等于對蜘蛛友好。如果一頁有几百個連結,但绝大多數指向同一批 URL(導航、頁脚、推荐位),有效入口就被稀释了。真正有帮助的是让不同区域的連結指向不同目标,並且把重要入口放在文档靠前、结构更浅的位置。

渲染抓取會額外放大成本

如果頁面依赖 JavaScript 才能呈現内容,蜘蛛除了取回 HTML,還要排队执行脚本、等待接口返回。這一步的成本遠高于静態解析:脚本执行有時間上限,接口慢或超时,蜘蛛可能只看到空壳。

對内容頁而言,把正文和主要内鏈放在服務端直出的 HTML 里,能同时降低抓取成本和不稳定性。

怎么自查

不需要复杂工具,服務器日誌里就能看出线索:

  1. 看蜘蛛請求的响應字节數分布,找出明顯偏大的那批 URL。
  2. 看單次請求的處理時間,区分是服務端慢還是頁面大。
  3. 看狀態碼,2xx 才是有效讀取;5xx、429 會打断队列。
  4. 抽样把頁面 HTML 存下来,看体积和节点结构是否符合预期。
  5. 對比列表頁與詳情頁的抓取频率,判断哪一類更拖後腿。

可以做的事

  • 開啟传輸压缩,减少 HTML 的實际传輸量。
  • 把内联的大段脚本、样式外鏈,並做缓存。
  • 控制單頁連結總量,優先保留指向不同 URL 的入口。
  • 列表頁分頁輸出,避免一頁塞進上千條记錄。
  • 内容與核心内鏈服務端直出,脚本负责增强而非承载。
不要為了“让蜘蛛轻松”而删掉對用戶有用的内容。先解决浪費:重复传輸、隐藏模块、無意义嵌套。抓取效率的改善,通常来自這些看得见的冗余,而不是内容的削减。

抓取是一個持續的過程,蜘蛛每次来訪都在做取舍:讀這個頁面值不值。降低單頁成本,等于把同样的抓取窗口让给更多 URL,尤其是那些還需要被發現的頁面。