搜尋抓取

JS 渲染队列與蜘蛛抓取:脚本生成的連結什么时候才進入路径

頁面上的連結如果由 JavaScript 在加载後生成,搜尋蜘蛛首轮抓取拿到的 HTML 里就没有這些入口,只能等渲染队列的後續訪問。本文說明首轮抓取與渲染两轮之間的時間差,哪些連結适合由服務端直接輸出,以及怎样用禁用 JS 對比、日誌抽查来確認關键 URL 是否真的進入了抓取路径。

搜尋抓取

JS 渲染队列與蜘蛛抓取:脚本生成的連結什么时候才進入路径

很多站点的連結並不是寫在 HTML 里,而是頁面加载後由 JavaScript 拼出来的。對用戶来说,点開就看到了;對搜尋蜘蛛来说,這件事要分两步看。第一轮請求拿到的往往只是一段初始 HTML,脚本還没执行,連結自然也不存在。這就是“頁面上明明有入口,蜘蛛却像没看见”的常见原因。

第一轮抓取,蜘蛛先拿到什么

蜘蛛發出的第一次請求和普通的抓取請求很接近:它拿到服務器返回的 HTML,解析里面的 a 标簽、link 标簽、图片地址等。如果這份 HTML 里没有目标 URL,這一轮就發現不了它,後面的路径也就無從谈起。

蜘蛛确實具备渲染能力,但渲染成本更高,通常不是首轮就做,而是把需要渲染的 URL 放進队列,稍後再用另一轮請求以渲染方式訪問。也就是说,脚本生成的連結不是不能被抓,而是要等,而且不保證等到。

渲染队列带来的時間差

  • 連結出現在渲染之後,不等于出現在首轮抓取路径里;
  • 排队意味着延迟,越靠後、越不被重视的頁面等得越久;
  • 資料依赖接口返回,接口拒绝了蜘蛛的請求,連結就直接消失;
  • 需要滚動、点击、登入才出現的連結,大概率永遠進不了队列。

所以真正的問题不是“渲染會不會被處理”,而是“你愿不愿意把關键入口押在第二轮上”。更新频繁的列表頁、商品頁、文章頁,等一轮队列的代價很明顯;而登入後、後台類頁面本来也不需要被抓,延迟甚至抓不到都無所谓。

把结构性連結放回初始 HTML

最省事的做法是先分清楚哪些連結属于结构性入口——主導航、分類頁、分頁、上一頁下一頁、面包屑、相關推荐。這些應该由服務端直接輸出成可点击的 a 标簽,而不是留给脚本补上。

  1. 列表頁與詳情頁的静態部分優先做服務端渲染或预渲染;
  2. 分頁使用真實 URL,例如 ?page=2 或 /list/2,不要只在脚本里追加資料;
  3. 篩選、排序這類交互,至少保證有一個可抓取的預設版本;
  4. 跳轉寫成带 href 的連結,避免用 onclick 或 div 模拟。
判断标准很简單:把浏览器 JS 關掉再刷新頁面,如果關键入口還在,蜘蛛第一轮大概率也能看到。

几項可以自己做的自查

  • 用抓取工具分別查看禁用 JS 與啟用 JS 两種狀態下的連結列表,對比差异;
  • 在服務器日誌里观察同一個 URL 是否被多次訪問,以及两次訪問之間隔了多久;
  • 抽查 URL 检查類工具返回的原始 HTML 與渲染後 HTML,確認目标連結出現在哪一份里。

容易被忽略的连带影响

渲染後的頁面還可能改變地址本身:脚本里带 hash、附加追踪參數、動態拼接路径,都會让同一份内容變成多個 URL,抓取路径随之走偏。渲染前和渲染後如果 canonical、标题、内鏈不一致,蜘蛛两次看到的就不是同一頁,之前建立起来的路径判断也會被推翻。

结论並不复杂:渲染可以当作补充,但不适合当成發現 URL 的主通道。把结构性連結放回初始 HTML 和 Sitemap,让首轮抓取就能顺着走;剩下的交互再交给脚本處理,這样路径才稳定。