很多站点把导航、列表、分页都交给前端框架渲染,HTML 源码里只剩一个空容器和一串脚本。对用户来说页面正常,但对蜘蛛来说,第一次抓取拿到的文档里可能没有任何可跟随的链接。这不是说蜘蛛一定发现不了,而是 URL 发现的路径变长、变不确定。
抓取和渲染不是同一步
搜索蜘蛛处理页面时,通常先做一次 HTTP 抓取,拿到服务器返回的 HTML,再解析其中的链接、文本和标签。对于需要执行 JavaScript 才能出现的内容,部分搜索引擎会把页面放进渲染队列,用无头浏览器再跑一遍。这里有两个关键点:渲染队列有延迟,不是抓完立刻执行;不同引擎对 JS 的执行能力、执行时长和资源限制也不一样。
所以,如果链接只存在于 JS 执行之后,蜘蛛能不能看到、多久看到,取决于它是否愿意渲染、渲染时脚本是否成功运行、以及接口数据是否返回。把 URL 发现押在这条链上,风险比放在静态 HTML 里高。
首轮 HTML 里没有出链,会发生什么
最直接的影响是抓取队列扩展变慢。蜘蛛抓到一个页面,如果解析不到新的 a 标签,就没有新的 URL 可以排队。页面可能仍然被渲染,链接随后被发现,但发现时间会晚于预期。如果渲染阶段失败——脚本报错、接口超时、资源被 robots.txt 挡住——这些链接可能一直不出现。
另一种情况是页面本身有链接,但写法让蜘蛛无法识别。例如用 onclick 绑定跳转、用 button 加 JS 事件、用 JS 路由只改 URL 不产生真实 a 标签。这些对用户是点击,对解析器不是链接。
几种高风险写法
- 纯 JS 路由:点击后通过 history API 改变地址,源码里没有对应的 href。
- 动态插入链接:等接口返回数据后才用 JS 创建 a 标签,首轮 HTML 为空。
- 依赖用户交互:需要滚动、点击“加载更多”才出现的内容和链接。
- 伪链接:用 span、div 加 onclick 代替 a 标签,蜘蛛不会把它当作链接。
- 登录后才渲染:未登录抓取时拿不到导航或列表链接。
让链接在首轮 HTML 里就可用
目标很简单:蜘蛛第一次请求时,返回的 HTML 里就包含可抓取的 href。常见做法有:
- 服务端渲染或预渲染关键导航、列表和分页链接,至少保证主要路径有静态 a 标签。
- 把“加载更多”改成真实的分页 URL,每一页都能独立访问,而不是只靠 JS 拼接。
- 用 a 标签承载跳转,href 指向真实地址,JS 只做增强,不替代链接。
- 重要入口放在全局导航或页脚,减少对前端异步接口的依赖。
- 如果确实只能靠 JS,至少用 Sitemap 或静态内链把重要 URL 补进发现路径。
Sitemap 和内链的兜底
Sitemap 不能替代页面内链,但它能在首轮 HTML 没有出链时,给蜘蛛一份可读的 URL 清单。对于分页较深、筛选页较多、或前端渲染为主的站点,把重要 URL 放进 XML Sitemap,并在静态页面里提供分类入口和面包屑,能减少对渲染队列的依赖。注意 Sitemap 里的 URL 应该是可返回正常内容的地址,不要放重定向链或大量参数变体。
怎么确认蜘蛛拿到了链接
- 用搜索引擎提供的 URL 检查工具,查看“已抓取的 HTML”里有没有目标链接。
- 查看服务器日志,确认蜘蛛是否请求了那些只由 JS 生成的 URL。
- 在关闭 JavaScript 的情况下打开页面,看是否还能看到主要导航和列表链接。
- 对比 Sitemap 中的 URL 与日志中被抓取的 URL,找出长期没有出现的部分。
把链接放在首轮 HTML 里,本质是降低蜘蛛发现 URL 的不确定性。渲染可以补,但不应该成为唯一的路。
总结一下:蜘蛛抓取和渲染有先后,JS 生成的链接不一定不能被处理,但发现会更晚、更容易受脚本和资源影响。对站点运营来说,能静态输出的链接尽量静态输出,再用 Sitemap 和内链结构兜底,URL 发现会更稳。