很多做站点运营的人会遇到一个现象:导航里明明放了入口,页面也没有被屏蔽,但几个月过去,目标 URL 还停留在「已发现,尚未抓取」,或者干脆没出现在索引报告里。排查一圈 robots、sitemap、canonical 都没发现问题,最后发现症结在最基础的一环——链接根本没有以爬虫能看见的形式存在。
抓取和渲染是两步,不是一步
搜索引擎处理一个 HTML 页面时,通常先取回原始 HTML 源码,解析其中的 a 标签、图片地址等静态链接;之后才会安排渲染,执行页面上的 JavaScript,拿到渲染后的 DOM。
如果你的链接是 JS 动态加进去的,那它只在第二步之后才存在。第一步的解析结果里,这些 URL 是空白的。渲染是有成本的动作,不会对所有页面、所有时间点都无条件执行,所以纯 JS 生成的链接,被发现的时间点会明显靠后,甚至一直不出现。
这也是为什么「在浏览器里能看到入口」和「爬虫能发现入口」是两回事:你在浏览器里看到的,永远是渲染后的结果。
四种常见的不易发现写法
- 点击后才生成。下拉菜单、选项卡里的链接写在 click 回调里,不点就不存在,爬虫不会替你点。
- 滚动到底才加载。无限滚动、懒加载列表,第一屏 HTML 里没有任何指向后续内容的 a 标签。
- 只用 pushState 路由。页面用 history API 切换视图,地址栏变了,但 HTML 里没有对应链接,爬虫找不到这些虚拟地址。
- 链接由接口返回。列表数据来自 fetch,HTML 里只有一个空容器。
这几种写法本身没有对错,用户体验往往更好。问题在于它们把 URL 的发现完全交给了渲染,而渲染是你不完全可控的一环。
自查顺序
- 看源码,不看元素面板。在浏览器里右键查看网页源代码,搜索 href。开发者工具显示的是渲染后的 DOM,会掩盖问题。
- 用抓取测试工具跑一遍。多数站长平台都提供页面抓取或渲染测试,能看到原始 HTML、渲染后 HTML 以及被发现的链接列表,两者对比最直观。
- 看服务器日志里有没有渲染请求。有的渲染服务带特定 UA,有的来自不同的 IP 段。如果日志里完全没有相关请求,说明渲染这一环根本没有触发。
- 检查是否被技术手段挡住。robots 里屏蔽 JS、CSS 文件,或者对静态资源做了鉴权、按 UA 返回 403,都会让渲染失败,链接自然出不来。
- 确认没有互相打架的指令。比如页面本身可抓取,但 JS 文件被 robots 屏蔽,等于给爬虫送了一个残缺页面。
给关键 URL 留一条静态路径
渲染不该是 URL 发现的唯一通道。对真正希望被收录的页面,最省事的做法是至少保留一条静态可达路径:
- 主导航、面包屑、页脚这类全站出现的区域,用原生 a 标签写死关键栏目和一批重要详情页。
- 列表页尽量做成分页 URL,而不是纯无限滚动;或者在首屏之外保留「下一页」的静态链接。
- 把重要页面按分组放进 sitemap。sitemap 是发现渠道,不是收录保证,但至少让 URL 有一个出口。
- 对确实无法静态暴露的页面,先评估数量。几十个可以靠 sitemap 兜底,上万条就别指望这条路了。
判断标准很简单:把 JavaScript 全部关掉,看还能不能从首页走几步点到目标页面。能点到,发现就不成问题;点不到,就要靠渲染或 sitemap 补。
几个容易忽略的细节
一是锚点与 hash 路由。地址里 # 后面的内容不会作为独立 URL 参与抓取,靠 hash 区分的「页面」在抓取视角里属于同一个地址。
二是前端路由的返回状态。用 JS 做路由的站点,如果所有路径都返回 200 并渲染同一份骨架,容易让爬虫分不清哪些是真实存在的页面。服务端能区分的话,尽量给出准确的 HTTP 状态。
三是别为了发现而堆链接。把几千个链接塞进页脚、塞进隐藏容器,既影响体验,也不会因为数量多就更快被发现,反而可能让页面失去重点。
小结:URL 发现的第一步,是让链接以可解析的形式出现在 HTML 里,渲染只是补充手段。排查时按源码、渲染结果、日志、屏蔽规则这个顺序走,通常能比较快地定位到底是哪一环断了。