搜索引擎收录异常排查实战:用 Nginx 日志做抓取预算审计,把「已发现未编入索引」降下来

被"收录异常"坑过的站长,都栽在同一个盲点上

先说一个很常见的场景:站长在 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

两个高频误区:

  1. 误 Disallow 分页。分页本身不产生收录价值,但它是爬虫发现老文章的重要通道。砍掉之后你会发现老文章开始从索引里掉落。
  2. 用 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

踩坑清单

  1. 别用 Disallow 处理收录问题,该用 noindex 的地方不能省抓取权限。
  2. 别 Disallow 分页,会断掉老文章的发现路径。
  3. canonical 不要跨站乱指,页内 canonical 必须自指,只有真重复才指向他页。
  4. URL 参数重定向不要用 302 长跳首页,会被当成软 404,浪费预算,应直接 301 到干净 URL。
  5. 410 比 404 更能省预算,废弃 URL 立刻改 410。
  6. sitemap 的 lastmod 不要造假,这会让整份 sitemap 失去可信度。
  7. 改完要等,抓取结构的调整通常需要 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 教程。

Last modification:September 22nd, 2026 at 08:24 pm

Leave a Comment