不少蜘蛛池入口页为了省事,会把链接列表交给 JavaScript 在浏览器里动态生成。这时一个很实际的问题就来了:搜索蜘蛛访问入口页时,看到的是几乎是空壳的 HTML,它还会不会继续去发现那些目标 URL?答案不是简单的“会”或“不会”,而是取决于这些链接最终出现在哪一个环节里。
一、抓取和渲染是两段流程,别当成一件事
主流搜索引擎对 JavaScript 的处理通常是两段式:先用抓取程序拿到原始 HTML,把里面的链接和资源记下来;如果页面被判定需要渲染,再排进渲染队列,由渲染服务执行 JS、拿到渲染后的 DOM,再做一次链接抽取。问题在于第二段是异步的,而且要排队。
这意味着两件事:
- 链接如果只存在于 JS 执行之后,它的发现会被推迟,通常不是秒级,可能是小时级甚至更久。
- 渲染队列不是所有 URL 都能进,优先级低的页面可能长期只被“抓取”,而一直没被“渲染”。
二、三种常见写法,实际差别很大
1. 初始 HTML 里就带链接
不管页面外面套不套前端框架,只要服务器返回的 HTML 源码里能看到 <a href="...">,抓取程序在第一次请求时就能抽到。这是最稳的一种做法。
2. 内联脚本同步写入
比如在 <script> 里用 document.write,或者先拼好字符串再插入节点。部分渲染器会执行它,但仍然依赖渲染环节,不能指望抓取阶段就拿到这些链接。
3. 外部 JS 异步请求后再注入
先用 fetch 请求接口拿一份 JSON,再循环生成 DOM。这种最不稳定:既要有渲染能力,还要能执行外部脚本、请求接口,任何一步被 robots.txt、网络抖动或超时挡住,链接就完全不可见。
三、怎么确认入口页的链接有没有被真正发现
不要靠猜,用源码和日志来对照:
- 禁用 JS 抓一次入口页,看返回源码里有多少条目标 URL。这个数字就是抓取阶段能拿到的数量。
- 在浏览器里打开同一页,用开发者工具看渲染后 DOM 里的链接数量。两者的差值,就是“只能靠渲染”的部分。
- 翻服务器日志:入口页被抓之后,目标 URL 有没有出现过来访,间隔多久。如果入口页天天被访问、目标 URL 一条都不来,基本可以判断链接没进入发现流程。
- 做对比测试:同一批目标 URL 分别放在静态 HTML 和 JS 注入的位置,观察两边日志的差异。
四、想稳妥,就把关键链接放回初始 HTML
- 入口页优先做服务端渲染,或者干脆输出静态 HTML,让链接在源码里可见。
- JS 只用来做样式、交互和统计,不要用来承载“唯一一份”链接列表。
- 如果确实只能用 JS,至少在 <noscript> 里放一份普通链接,或者在页脚补一组静态链接兜底。
- 把重要的目标 URL 放在 HTML 前部,避免后半部分因为页面体积过大被截断。
需要说明的是,让链接出现在初始 HTML 里,只是“有机会被发现”,并不等于会被抓取或被收录。最终还要看目标 URL 本身的内容质量、服务器响应状态和站点整体的抓取预算。
五、两个容易被忽略的细节
第一,有些入口页用 JS 生成链接后,还会顺手加上 rel="nofollow",或者写成 onclick 跳转而不是真正的 href。这两者都会让链接在抽取阶段失效。跳转请用可点击的 a 标签,不要用 javascript:void(0) 或纯 onclick。
第二,链接的可见性和渲染完成度有关,但和渲染时机无关。如果你在日志里看到入口页被访问的时间点,和渲染服务真正执行的时间点可能相差很远,排查时不要只盯着抓取时间,把渲染队列的延迟也算进去。
总结一句:搜索蜘蛛对 JavaScript 并非无能为力,但渲染是有代价、有排队的。蜘蛛池入口页这类“链接搬运”性质的页面,本身没有多少内容价值,更应该把链路做简单一点——源码里能直接看到的链接,永远比藏在脚本执行之后的链接更可靠。