搜尋抓取

蜘蛛的两趟活:先取 HTML,再排队渲染

蜘蛛處理一個頁面通常分两趟:先下载服務器返回的原始 HTML,再把頁面放進渲染队列执行 JS。連結只寫在 JS 里,URL 的發現就要排队等第二趟。本文說明两趟流程的差別、渲染排队變慢的原因,以及把導航、分頁、列表連結放回首屏源碼的具体做法與驗證方法。

搜尋抓取

蜘蛛的两趟活:先取 HTML,再排队渲染

抓取和渲染,在蜘蛛那里是两件事

很多人把「蜘蛛来過」理解成一個動作:請求、下载、看懂頁面。實际流程至少能拆成两段。第一段是普通的 HTTP 抓取,服務器返回什么 HTML,蜘蛛就先拿到什么;第二段是把頁面丢進渲染队列,用浏览器内核执行 JavaScript,等 DOM 稳定之後再讀一遍。两段之間可能只隔几分钟,也可能隔上好几天。

這個時間差直接决定了一件事:如果 URL 只存在于 JS 执行之後的 DOM 里,它被發現的時間就要往後推。

第一趟:原始 HTML 里有什么,就先認什么

第一次請求返回的源碼,如果只有一個空容器节点加一段脚本引用,那這一趟能讀到的信息就非常有限。蜘蛛不會在這一步替你执行脚本,它只是把源碼里現成的线索收走。

能在第一趟被發現的

  • 服務端直接輸出在 HTML 里的 a 标簽連結;
  • Sitemap 中列出的 URL;
  • RSS、Atom 等订阅文件里的條目;
  • HTTP 响應头中的重定向目标與 Link 信息。

要等第二趟的

  • 由前端路由在浏览器里生成的内鏈;
  • 点击「加载更多」才會出現的列表項;
  • 依赖接口返回資料拼出来的詳情入口。

這里的区別不是「能不能被抓到」,而是「什么时候被抓到」。前者進入常規抓取队列,後者得先過渲染這一關。

渲染队列慢在哪里

渲染比纯抓取贵得多:要起浏览器進程、下载脚本和样式、执行代碼、等接口回包。资源有限,站点一多就必然排队。

  • 頁面脚本多、体积大,單頁渲染耗时更長,队列被占用的時間也長;
  • 渲染失敗或超时的頁面,通常不會立刻重新排队;
  • 层級深、外部入口少的 URL,排位更靠後,等待更明顯。

另外要分清:這里讨论的是發現和获取的节奏,不是收錄结果。渲染成功也不等于頁面一定會被索引。

让關键連結出現在原始 HTML 里

做法不复杂,核心是別把發現入口全交给 JS。可以按下面的顺序排查和調整:

  1. 栏目頁、列表頁、詳情頁之間的互相連結,優先用服務端渲染或静態輸出。
  2. 交互可以保留 JS,但基础導航用普通 a 标簽兜底。
  3. 分頁和「下一頁」给出真實 URL,而不是绑定点击事件。
  4. Sitemap 只提交确實需要被發現的 URL,並尽量與站内可见連結保持一致。
  5. 不必整站 SSR,至少把導航、面包屑、列表連結放進首屏源碼。

這样做的好處是可预期的:蜘蛛第一趟就能顺着連結往下走,渲染队列只承担补充角色,而不是唯一的入口。

怎么確認自己有没有踩坑

  1. 關閉 JS,或只用源碼抓取工具跑一遍,看能顺連結点到第几层。
  2. 對比源碼里的連結數量和渲染後 DOM 里的連結數量,差得越多,依赖越重。
  3. 查看抓取日誌,看同一批 URL 是否在渲染請求里才出現,是否比首轮抓取晚很多。
  4. 抽查若干深层頁,確認它們至少有一條来自原始 HTML 的入口。
蜘蛛並不是看不见 JS 頁面,而是它走在两條不同的队列上。把關键連結放回第一趟就能讀到的地方,URL 的發現节奏會稳定很多。

最後补一句服務器侧的因素:渲染請求同样要占用连接和带宽。如果源站响應偏慢,渲染阶段的等待會叠加在抓取等待之上,整体节奏更慢。保持响應時間稳定、避免長時間無响應,對两趟流程都有帮助。