很多站点的連結並不是寫在 HTML 里,而是頁面加载後由 JavaScript 拼出来的。對用戶来说,点開就看到了;對搜尋蜘蛛来说,這件事要分两步看。第一轮請求拿到的往往只是一段初始 HTML,脚本還没执行,連結自然也不存在。這就是“頁面上明明有入口,蜘蛛却像没看见”的常见原因。
第一轮抓取,蜘蛛先拿到什么
蜘蛛發出的第一次請求和普通的抓取請求很接近:它拿到服務器返回的 HTML,解析里面的 a 标簽、link 标簽、图片地址等。如果這份 HTML 里没有目标 URL,這一轮就發現不了它,後面的路径也就無從谈起。
蜘蛛确實具备渲染能力,但渲染成本更高,通常不是首轮就做,而是把需要渲染的 URL 放進队列,稍後再用另一轮請求以渲染方式訪問。也就是说,脚本生成的連結不是不能被抓,而是要等,而且不保證等到。
渲染队列带来的時間差
- 連結出現在渲染之後,不等于出現在首轮抓取路径里;
- 排队意味着延迟,越靠後、越不被重视的頁面等得越久;
- 資料依赖接口返回,接口拒绝了蜘蛛的請求,連結就直接消失;
- 需要滚動、点击、登入才出現的連結,大概率永遠進不了队列。
所以真正的問题不是“渲染會不會被處理”,而是“你愿不愿意把關键入口押在第二轮上”。更新频繁的列表頁、商品頁、文章頁,等一轮队列的代價很明顯;而登入後、後台類頁面本来也不需要被抓,延迟甚至抓不到都無所谓。
把结构性連結放回初始 HTML
最省事的做法是先分清楚哪些連結属于结构性入口——主導航、分類頁、分頁、上一頁下一頁、面包屑、相關推荐。這些應该由服務端直接輸出成可点击的 a 标簽,而不是留给脚本补上。
- 列表頁與詳情頁的静態部分優先做服務端渲染或预渲染;
- 分頁使用真實 URL,例如 ?page=2 或 /list/2,不要只在脚本里追加資料;
- 篩選、排序這類交互,至少保證有一個可抓取的預設版本;
- 跳轉寫成带 href 的連結,避免用 onclick 或 div 模拟。
判断标准很简單:把浏览器 JS 關掉再刷新頁面,如果關键入口還在,蜘蛛第一轮大概率也能看到。
几項可以自己做的自查
- 用抓取工具分別查看禁用 JS 與啟用 JS 两種狀態下的連結列表,對比差异;
- 在服務器日誌里观察同一個 URL 是否被多次訪問,以及两次訪問之間隔了多久;
- 抽查 URL 检查類工具返回的原始 HTML 與渲染後 HTML,確認目标連結出現在哪一份里。
容易被忽略的连带影响
渲染後的頁面還可能改變地址本身:脚本里带 hash、附加追踪參數、動態拼接路径,都會让同一份内容變成多個 URL,抓取路径随之走偏。渲染前和渲染後如果 canonical、标题、内鏈不一致,蜘蛛两次看到的就不是同一頁,之前建立起来的路径判断也會被推翻。
结论並不复杂:渲染可以当作补充,但不适合当成發現 URL 的主通道。把结构性連結放回初始 HTML 和 Sitemap,让首轮抓取就能顺着走;剩下的交互再交给脚本處理,這样路径才稳定。