蜘蛛池的入口页大多是静态 HTML,原因很直接:链接写在源码里,蜘蛛不用执行脚本就能发现。但实际维护中,不少入口页为了好看或省事,把链接交给 JavaScript 生成,结果页面上人能看到,蜘蛛却拿不到。这里只讨论一件事:当链接依赖 JS 渲染时,会遇到什么问题,以及怎么改回可控的状态。
搜索引擎能跑 JS,但不等于会为你的 JS 排队
主流搜索引擎确实具备执行 JavaScript 的能力,流程通常是先抓取 HTML 源码,再放进渲染队列执行脚本。问题在于渲染是额外一步,成本比直接读源码高,所以它有自己独立的节奏。
- 渲染队列有排队时间,短则几分钟,长则数天,这期间页面上的 JS 链接等于不存在。
- 渲染有预算,单个站点能分到的渲染次数通常远少于普通抓取次数。
- 渲染会超时,脚本报错、请求第三方资源失败、接口响应太慢,都可能让这次渲染白做。
- 渲染结果不一定会被当成新的链接来源再扩散一次,深层页面尤其如此。
换句话说,JS 渲染是“可能被抓到”,静态链接是“大概率被抓到”。对入口页这种以发现 URL 为主要目的的页面,主动把概率压低并不划算。
入口页里几种典型的“假链接”
- onclick 绑定跳转:用 div、span 加 onclick 执行 location.href,源码里没有 href,蜘蛛拿不到目标地址。
- data 属性加脚本拼接:地址先放在 data-href 里,页面加载后再由脚本生成 a 标签,抓取时源码中只是一堆空容器。
- 异步接口返回列表:入口页只放一个空壳,链接列表由接口返回后渲染,接口本身没被索引,链接也就无从扩散。
- 延迟加载与滚动加载:链接元素进入视口才加载,渲染器不一定滚动到底部,靠后的链接容易被漏掉。
- iframe 里嵌套的列表:iframe 内容有可能被抓,但被发现的速度和继承到的权重,通常不如主文档里的直链。
最省事的改法:让链接在源码里就存在
- 优先用原生 a 标签:href 指向真实 URL,脚本只负责样式和交互,不负责生成地址。
- 服务端渲染或静态生成:入口页内容本来就不多,用模板在服务端拼好 HTML 直出,比前端渲染更稳。
- 预渲染兜底:确需前端框架生成时,对入口页做预渲染,向抓取端返回一份包含链接的静态快照。
- noscript 兜底:在 noscript 中放一份基础的分类链接,至少保证主路径可达。它只是兜底,不要当成主要方案。
- 保留一个纯静态列表页:把 URL 发现集中在这类页面,动态部分只做展示,不承担扩散任务。
确实要用 JS 渲染时,把成本降下来
- 首屏直出:关键链接放在 HTML 靠前的位置,别等脚本跑完才出现。
- 减少第三方脚本:外部 JS、统计、字体、广告都会拖慢渲染,任何一个卡住都可能让整次渲染超时。
- 控制渲染体积:入口页 DOM 节点数量不要无节制膨胀,长列表考虑分页。
- 接口尽量稳定:渲染依赖的接口如果经常超时,抓取端的渲染成功率也会跟着下降。
- 保持结果一致:移动端与桌面端渲染差异过大时,容易出现同一页面两套链接的情况,反而不利于判断。
怎么自查入口页的链接是否可发现
- 直接查看网页源码,搜索目标 URL 是否出现在 HTML 中,而不是只出现在脚本字符串里。
- 禁用浏览器 JavaScript 后打开入口页,看还剩多少可点击的链接。
- 查看服务器日志,确认抓取端是否请求过页面依赖的 JS 和接口文件;如果连这些都没抓,说明渲染这一步还没走到。
- 用抓取诊断类工具对比源码版与渲染版,看两者链接数量差多少。
- 抽查新发布的目标页,观察一段时间内是否有抓取请求,而不是只看页面在前端展示是否正常。
需要说明的是,链接能被发现只是第一步,之后还要经过抓取、解析、去重和索引判断。把入口页做成静态直链,能减少一个不确定环节,但并不代表内容一定会被收录。
小结
入口页的任务是把 URL 稳定地交到蜘蛛面前。能用 HTML 直出的链接就不要交给脚本,能用服务端渲染的就别依赖前端异步。JS 渲染不是不能用,但它应当是特殊场景下的可选项,而不是入口页链接的默认实现方式。