在蜘蛛池入口页里放目标链接时,有时会顺手带上锚点,比如 example.com/article#part2,或者单页应用的 example.com/#/detail/123。这种带 # 的 URL,搜索蜘蛛会怎么处理,会不会因此抓不到目标地址,是不少人问过的问题。先说结论:大多数情况下,搜索蜘蛛会把 # 及其后面的内容当作页面内的定位标记,而不是一个新的 URL。
# 后面的内容不会发给服务器
HTTP 请求本身就不包含片段标识符(fragment)。浏览器访问 example.com/page#section2 时,实际发给服务器的请求只是 example.com/page,服务器看不到 #section2 这一截。搜索抓取器遵循同样的规则,它发出的请求里不会带 # 后面的部分。所以只要入口页里的链接去掉片段后指向同一个地址,抓取器请求到的就是那个真实资源。
同页不同片段会被合并成一个 URL
在 URL 归一化环节,片段通常会被剥离。可以这样理解:
- example.com/page、example.com/page#a、example.com/page#b 一般被视为同一个 URL;
- 入口页里把这三条链接都放一遍,不会让目标地址被多抓两次;
- 抓取预算也不会因为你多写了几个 # 就多分出来。
想靠给同一个地址加不同 # 来“多引几次蜘蛛”,基本是无效操作,反而让入口页显得杂乱。
真正会出问题的是 hash 路由
如果目标地址是单页应用,靠 # 切换路由,例如 example.com/#/list 或 example.com/#/detail?id=9,情况就不一样了:
- 服务器收到的请求仍然只是站点根路径,返回的通常是同一份 HTML 外壳;
- 正文由前端 JS 在浏览器端渲染;
- 抓取器能否拿到渲染后的内容,取决于它是否执行 JS、渲染是否成功、内容是否在首屏可见。
这时入口页里放带 # 的链接,抓取器确实会去请求,但拿到的很可能是一个空壳,这些内容也不会被当成独立页面来处理。
确实要用 hash 路由的站点怎么办
- 优先改成 history 模式,让每篇内容有独立的可请求地址;
- 短期无法改造时,为关键内容补一份静态 HTML 或服务端渲染版本,让抓取器至少能读到正文;
- 在入口页里同时提供几条指向静态地址的普通链接,不要只依赖 hash 地址。
入口页写法上的几个建议
- 链接直接写最终要被抓取的那个地址,不要为了好看额外加锚点;
- 需要锚点跳转时,把带 # 的链接当作站内导航使用,别指望它带出新 URL;
- 同一个目标地址在入口页出现一次就够了,重复堆叠没有额外收益;
- 投放前先确认目标页面在无脚本环境下是否有可读内容。
想知道链接到底有没有被真正请求,看服务器访问日志最直接——你会发现日志里从来没有 # 后面的部分。
怎么验证
- 查看访问日志里请求的完整路径,和入口页写的链接做对比;
- 用抓取工具或日志分析脚本模拟请求,观察返回内容是否为空壳;
- 对单页应用,用“查看网页源代码”而不是开发者工具,确认 HTML 里是否真的有正文。
小结:# 片段在抓取层面基本是透明的,它既不会帮你多要一次抓取,也不会打断对真实地址的请求。真正需要警惕的是把内容完全交给 hash 路由的站点结构——那种情况下,问题不在入口页写不写 #,而在目标地址本身能不能被当作一个可独立请求、可独立阅读的页面。