蜘蛛第一次拿到的往往是空壳
单页应用把渲染工作交给了浏览器:一次请求返回的 HTML 通常只有固定的头部、一个空的挂载节点和几段打包脚本,正文和链接都要等 JavaScript 执行、接口返回之后才出现。蜘蛛抓取的第一份内容就是这份外壳,里面既没有可读文本,也没有指向路由的 a 标签,路由背后的 URL 自然也就没被登记进来。
三种路由写法,被发现的难度不同
- history 模式:地址看起来是正常的路径,例如 /list/2,本身具备被抓取的形式,难点在于页面里要先有指向它的链接。
- hash 模式:地址里带 #,片段部分通常不作为独立 URL 处理,路由再多也可能只对应一个抓取入口。
- 查询参数路由:形如 ?page=3 的写法容易被抓取,但参数一旦叠加,容易生出大量近似地址。
写法本身没有绝对的好坏,关键在于能否在 HTML 层面暴露足够多、指向明确的链接。
把链接写回 href
很多 SPA 的导航是可点击的,但对蜘蛛来说不可读:点击事件挂在 div 上,地址靠脚本 push 进去,HTML 里什么也没留下。要改变这一点,思路其实很朴素——让每个需要被发现的路由,都有一个真实的链接地址。
- 导航与列表项用 a 标签承载 href,而不是给 div 绑定点击事件。
- href 写真实路径,避免 javascript:void(0) 或只做页内锚点跳转。
- 滚动加载之外,给出可访问的分页地址,让靠后的内容有独立入口。
- 路由切换时同步更新 title 与主要内容区域,不要只替换一小块组件。
渲染成本的另一面
服务端渲染或预渲染能把首屏 HTML 直接吐出来,蜘蛛不必执行脚本就能读到内容和链接,这是最省事的一条路。但它也有代价:每个需要跑脚本的页面都会占用额外的抓取资源,接口响应慢时还会把整体抓取时间拉长。因此常见的做法是分层处理——首页、栏目页、详情页这类需要被发现的内容走服务端输出,交互密集的个人中心、购物车之类留在客户端渲染。
渲染不是免费的:让每个 URL 都跑一遍脚本,等于把发现成本转嫁给抓取资源,能静态输出的路径尽量静态输出。
几个自查动作
- 临时关闭 JavaScript 打开页面,看看还剩多少可读文本和可点链接。
- 查看页面源码,确认关键链接出现在源码里,而不是运行时才注入。
- 翻服务器日志,看蜘蛛抓到的是各个路由路径,还是反复访问同一个外壳地址。
- 把重要路由写进 Sitemap,作为内链之外的一条补充发现通道。
SPA 的抓取问题,说到底不是技术选型的问题,而是链接有没有以蜘蛛读得到的形式出现。把发现路径铺好,后面的抓取节奏才有讨论的基础。