被"收录异常"坑过的站长,都栽在同一个盲点上
先说一个很常见的场景:站长在 Search Console 或者百度搜索资源平台里看到一批"已发现,但尚未编入索引"的 URL,于是判断"页面质量不行""新站权重不够",接着去做外链、去改标题、去发原创内容——折腾一个月,那批 URL 还是没被索引。
实际上,"已发现未编入索引"绝大多数不是质量问题,而是抓取预算(Crawl Budget)被无关 URL 吃光了。搜索引擎知道你的页面存在(Discover),但排不出资源来抓(Crawl),更谈不上收录(Index)。这条链路是"发现 → 抓取 → 收录"三段式,站长最常犯的错是跳过抓取直接谈收录。
本文用一个真实的中文博客站做例子:n1 收录率长期卡在 42%,站内只有 300 多篇文章,一天却有近两万次抓取请求,几乎全打在了参数页上。下面是一整套从定位到修复的实操流程。
第一步:先量化——把 "发现/抓取/收录" 三个数字分开
很多人一上来就看"收录数",这是错的。先拉这三组数据:
- 已发现(Discovered):站内链接、sitemap 里出现但还没被访问的 URL;
- 已抓取(Crawled):搜索引擎实际取过 HTTP 响应的 URL,看服务器日志最准;
- 已收录(Indexed):进入了索引库的 URL。
然后是关键一步——从你自己的 Nginx 日志里统计爬虫的真实抓取分布。这是所有判断的基础,比任何平台报表都细:
# 1) 按搜索引擎统计最近一天抓取量
zcat -f /var/log/nginx/*access*.log.* 2>/dev/null | awk '{print $12}' | \
grep -i -E 'Baiduspider|Googlebot|bingbot|Sogou|360Spider' | sort | uniq -c | sort -rn
# 2) 统计被爬最多的 URL 路径(去掉 querystring 看真实页面)
grep -i 'Baiduspider' /var/log/nginx/access.log | \
awk '{print $7}' | sed 's/?.*//' | sort | uniq -c | sort -rn | head -30
# 3) 统计"带参数 URL"占爬虫总请求的比例
total=$(grep -ic 'Baiduspider' /var/log/nginx/access.log)
withquery=$(grep -i 'Baiduspider' /var/log/nginx/access.log | awk '{print $7}' | grep -c '?')
echo "总数=$total 带参数=$withquery 占比=$(awk -v a=$withquery -v b=$total 'BEGIN{printf "%.1f%%", a/b*100}')"
# 4) 统计爬虫拿到的状态码分布(404 和 302 是预算黑洞)
grep -i 'Baiduspider' /var/log/nginx/access.log | awk '{print $9}' | sort | uniq -c | sort -rn那次的结果非常刺眼:带参数 URL 占爬虫请求的 78%,而且状态码里 404 占 21%、302 占 12%。真正的文章页只被爬了几百次。抓取预算被垃圾 URL 吃光了,这才是收录上不去的直接原因。
第二步:找出"预算黑洞"的四类 URL
绝大多数中文站,超出常理地消耗抓取预算的 URL 逃不出这四类:
1. 带参数的动态 URL
/index.php?p=123
/post.html?from=weixin&utm_source=xxx
/search.php?q=关键词&page=2
?replytocom=456搜索引擎会把每个不同的 querystring 当成不同 URL。一条 utm_source 能裂变出几百个"新页面",全是重复内容,纯消耗。
2. 分页与归档的无限组合
/tag/xxx/page/2/
/date/2026/09/
/author/admin/page/15/标签页 + 分页笛卡尔积,能生成上千个低价值页面。站内链接只要有一处指向 /tag/a/page/3/,爬虫就会顺着爬完整棵子树。
3. 站内搜索结果页
/search?q= 这类页面是典型的"无限空间"——搜索引擎能通过站内搜索爬出成千上万的低质页面。必须从一开始就禁掉。
4. 陈旧或被废弃的 URL
改版、换 CMS、换 URL 结构之后,老的 URL 如果返回 302 跳到首页,爬虫会认为"这个链接还有戏",反复来爬。正确做法是返回 410 Gone,明确告诉爬虫"这个地址永久没了,别再来了"。
第三步:robots.txt 的正确写法(别用 Disallow 处理收录问题)
这里是本文最想强调的一个认知陷阱。
Disallow 只控制"抓取",不控制"收录"。一个被 Disallow 的 URL,如果别处有链接指向它,搜索引擎仍然可能把它收录进索引(只是无法读取内容,展示时没有摘要)。所以:
- 想让页面彻底不在索引里 → 用
noindex(meta 标签或 X-Robots-Tag 响应头),并且必须允许抓取,否则爬虫读不到 noindex; - 想省抓取预算、页面本身无害 → 用
robots.txt Disallow。
一套适用于个人内容站的 robots.txt 模板:
User-agent: *
# 省预算:这些 URL 不必抓
Disallow: /search
Disallow: /*?replytocom=
Disallow: /*?utm_
Disallow: /admin/
Disallow: /action/
Disallow: /*?p=
# 注意:不要 Disallow 分页,否则文章页的发现路径会断
# Allow: /page/
Sitemap: https://www.example.com/sitemap.xml两个高频误区:
- 误 Disallow 分页。分页本身不产生收录价值,但它是爬虫发现老文章的重要通道。砍掉之后你会发现老文章开始从索引里掉落。
- 用 Disallow 试图"清理"已收录的重复页。已收录的页面必须靠 noindex 或 301/410 让它退场,Disallow 只会让爬虫看不到 noindex 而继续保留。
第四步:规范链接与参数统一
从源头上砍掉重复 URL 的裂变:
# Nginx:把无意义的 tracking 参数重定向到干净 URL(去掉 querystring)
if ($args ~ (^|&)(utm_[a-z]+|from|spm|ref)=) {
return 301 $uri;
}
# 统一 www / 非 www 与 http → https,避免两套 URL 同时被抓
server {
listen 80;
server_name example.com www.example.com;
return 301 https://www.example.com$request_uri;
}
# 给所有页面输出 canonical
add_header Link '<https://www.example.com$uri>; rel="canonical"' always;页面级 canonical 要保证:每篇内容只有一个 canonical,且指向自己(自指 canonical)。分类页、标签页可以 canonical 到上一级列表页,避免"分页第一页 + 分类页 + 首页"三份重复内容。这比堆外链有效得多。
同时用 X-Robots-Tag 兜底拦掉不该被索引的响应:
location ~ ^/(search|admin|action)/ {
add_header X-Robots-Tag "noindex, nofollow" always;
}
# 未找到的静态资源返回 410 而不是 404
location ~* \.(jpg|png|gif|css|js)$ {
error_page 404 =410 /empty;
}第五步:让 sitemap 只包含"值得收录"的 URL
sitemap 不是"越全越好"。把 3000 个 URL 塞进去、其中 2500 个是标签分页,等于告诉搜索引擎"优先抓这些垃圾"。正确做法:
- sitemap 只放文章页、高质量分类页,标签页、归档页、搜索结果页一律不放;
- 超过 5 万个 URL 或未压缩超过 50MB 才需要分片,个人站通常一个文件就够;
lastmod必须是"内容真实修改时间",不要每次生成都刷成当天——爬虫会识别出这个字段不可信,进而降低 sitemap 的抓取优先级。
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://www.example.com/1122.html</loc>
<lastmod>2026-09-22T19:56:00+08:00</lastmod>
<changefreq>monthly</changefreq>
<priority>0.8</priority>
</url>
</urlset>生成 sitemap 时直接从数据库取 modified 字段,不要用 time():
SELECT cid, title, FROM_UNIXTIME(modified) AS lastmod
FROM typecho_contents
WHERE type='post' AND status='publish'
ORDER BY cid DESC;第六步:修复后的验收指标
做完上面五步,别急着喊成功。用这些量化指标验收,抓取结构的变化通常 3~7 天能在日志里看出来:
| 指标 | 修复前 | 目标 |
|---|---|---|
| 带参数 URL 占爬虫请求比 | 78% | < 10% |
| 爬虫请求中 404 + 410 占比 | 21% | < 5% |
| 文章页日抓取次数 | 约 500 | > 3000 |
| "已发现未编入索引"数量 | 持续增长 | 逐步下降 |
| 收录率 | 42% | > 70% |
监控脚本可以每天跑一次,把结果写进日志:
#!/bin/bash
LOG=/var/log/nginx/access.log
total=$(grep -ic 'Baiduspider' $LOG)
q=$(grep -i 'Baiduspider' $LOG | awk '{print $7}' | grep -c '?')
bad=$(grep -i 'Baiduspider' $LOG | awk '$9==404 || $9==410' | wc -l)
echo "$(date '+%F') 总=$total 带参=$q 死链=$bad 带参率=$((q*100/total))%" \
>> /var/log/crawl-budget.log踩坑清单
- 别用 Disallow 处理收录问题,该用 noindex 的地方不能省抓取权限。
- 别 Disallow 分页,会断掉老文章的发现路径。
- canonical 不要跨站乱指,页内 canonical 必须自指,只有真重复才指向他页。
- URL 参数重定向不要用 302 长跳首页,会被当成软 404,浪费预算,应直接 301 到干净 URL。
- 410 比 404 更能省预算,废弃 URL 立刻改 410。
- sitemap 的 lastmod 不要造假,这会让整份 sitemap 失去可信度。
- 改完要等,抓取结构的调整通常需要 3~7 天,甚至两周,别第二天就下结论。
常见问题(FAQ)
Q:站点很小、只有几十篇原创,也需要管抓取预算吗?
需要,但角度不同。小站的问题不是"预算被吃光",而是"发现路径太窄"——爬虫找不到你的文章。这时要做的是补全站内链接、提交 sitemap、开启 IndexNow,而不是 Disallow。
Q:日志里发现 Googlebot 来的很少,是坏事吗?
看你面向哪个市场。做中文站,百度、必应、搜狗才是主战场,Googlebot 少很正常。但如果你的目标是海外,Googlebot 抓取量极少就说明有问题,通常是不够权威或没有外链。
Q:把参数页全部 301 到主页,会不会导致收录大掉?
会,而且这是错误做法。301 到主页等于告诉搜索引擎"所有参数页都是主页的重复",还可能被判定为软 404。正确做法是 301 到去掉参数的干净 URL,或返回 410。
Q:多久能看到效果?
Disallow 生效最快,几天内抓取量就会掉;收录结构的变化慢,通常 1~4 周。写这个流程时,我们站的收录率用了 12 天才从 42% 提到 71%。
Q:这个思路和"内容质量论"冲突吗?
不冲突,是先后关系。先保证爬虫能高效地爬到你的内容,再谈内容质量。抓取通道堵着的时候,写再好的文章也进不了索引。这也是为什么很多站长拼命写原创却看不到收录增长的根本原因。
写在最后
收录异常这件事,七分是结构问题,三分才是内容问题。对个人站长来说,最划算的一件事就是给自己的站做一次"抓取预算审计":花一小时扒日志,比花一个月写外链有效得多。
把日志统计脚本挂进 crontab,每天一行数据入档。等你有了两周的曲线,你对这个站的理解会超过市面上任何一篇泛泛而谈的 SEO 教程。