新文章不收录可能因Nginx配置错误导致。文章通过分析Nginx日志,发现爬虫被误拦、死循环或抓取配额浪费。作者提出解决方案,如单开蜘蛛日志、标记蜘蛛User-Agent等,以排查并修复这些问题。
前阵子我给几个站点加了新栏目,连着更新了十几篇长文,主动把链接提交到百度搜索资源平台和 Google Search Console。按理说站点已经稳定跑了一年多,新文章少说也该在一两天内进库。结果等了整整两周,后台的索引量曲线纹丝不动。去站长平台看抓取频次,每天只有零星几次,甚至还有大量抓取失败的报警。
很多人遇到不收录,第一反应往往是怀疑文章质量不够高、原创度低或者域名被进了沙盒。但当我连上服务器翻开 Nginx 的原始访问日志时,才发现问题根本没出在内容上:真实的搜索引擎蜘蛛确实来过,但要么被误配的安全规则挡在门外,要么被复杂的重定向绕进死胡同,要么把有限的抓取额度全耗在垃圾参数页上。
把这套服务器层面的排查过程整理出来,梳理几个最隐蔽的技术 SEO 坑,以及具体的日志定位方法与修复规则。
准备工作:在 Nginx 中单开蜘蛛专属日志
排查爬虫问题,第一步是得看清蜘蛛到底有没有来、抓了什么、拿到了什么状态码。
默认的 Nginx access.log 混杂了普通用户访问、静态资源请求和各种扫描脚本,直接用 grep 搜爬虫既慢又容易漏。在主配置里给各大主流搜索引擎蜘蛛打上标记,并单独输出到独立的蜘蛛日志文件,排查效率会高很多。
在 nginx.conf 的 http 块中加入基于 User-Agent 的变量映射与日志格式定义:
map $http_user_agent $is_spider {
default 0;
~*(Baiduspider|Googlebot|bingbot|Sogou\ web\ spider|YisouSpider) 1;
}
log_format spider_log '$remote_addr - [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" $request_time $upstream_response_time';
然后在对应的 server 块中,设置只记录命中爬虫的请求:
access_log /var/log/nginx/spider_access.log spider_log if=$is_spider;
重载 Nginx 之后,只要有合法的蜘蛛访问,就会实时写入 spider_access.log。排查时只要用一条简单的 awk 命令,就能看到过去 24 小时各大蜘蛛的状态码分布:
awk '{print $9, $1}' /var/log/nginx/spider_access.log | sort | uniq -c | sort -nr
正常情况下,状态码应该以 200 为主,辅以少量的 304 或合规的 301。如果看到大面积的 403、502 或者连续跳转,说明抓取环节已经出问题了。
坑一:防扫描与 WAF 规则把真实蜘蛛拒之门外
现在的服务器天天被各种自动化脚本扫描,很多站长习惯在 Nginx 里配置限流模块(limit_req)或者封禁 User-Agent 的黑名单。
我当初为了防御某个恶意刷接口的脚本,在全局配置里加了一段针对高频请求的速率限制,限制每个客户端 IP 每秒最多只能发起 2 个请求:
limit_req_zone $binary_remote_addr zone=req_limit:10m rate=2r/s;
平时普通用户浏览网页完全不受影响,但搜索引擎爬虫的工作模式完全不同。像百度蜘蛛或者 Googlebot 爬取整站结构时,往往会在几秒钟内高并发地发出几十个探测请求。当抓取频率超过这个阈值时,Nginx 就会给蜘蛛返回 503 Service Temporarily Unavailable。
不仅是限流,更常见的是 User-Agent 正则误杀。比如有些防采集规则写成这样:
if ($http_user_agent ~* (python|curl|bot|spider|crawler)) {
return 403;
}
本意是想拦未授权的爬虫,结果把包含了 Googlebot、bingbot 的合规搜索引擎蜘蛛全部一并干掉了,爬虫每次来访问新文章直接吃 403 Forbidden。
有些站长知道伪造 User-Agent 很简单,于是不敢直接放行。其实判断是不是真正的百度或谷歌蜘蛛,不能单凭客户端带的 User-Agent 字符串,必须通过 IP 反向 DNS 解析(rDNS)来确认。
在 Linux 终端用 host 或 dig 命令对来访 IP 做 PTR 反查:
host 220.181.108.77
# 输出:77.108.181.220.in-addr.arpa domain name pointer baiduspider-220-181-108-77.crawl.baidu.com.
host baiduspider-220-181-108-77.crawl.baidu.com
# 正向解析必须解析回原始 IP:220.181.108.77
确认是正规爬虫的 IP 段后,如果要在 Nginx 里做限流,需要使用 geo 模块将合规蜘蛛的网段从限流池中剥离出来:
geo $white_spider {
default 0;
116.179.32.0/24 1; # 百度常用抓取段示例
220.181.108.0/24 1;
66.249.64.0/19 1; # Googlebot IP 段
}
map $white_spider $limit_key {
0 $binary_remote_addr;
1 ""; # 命中白名单时 key 为空,Nginx 自动跳过限流
}
limit_req_zone $limit_key zone=req_limit:10m rate=2r/s;
这样既保住了抗攻击能力,又避免了蜘蛛爬到一半被频繁 503 拦截。
坑二:尾部斜杠与多层 Rewrite 造成的重定向损耗
第二个非常隐蔽的坑是 URL 规范化配置不严谨带来的连环 301 重定向。
现代搜索引擎对每个网站分配的“抓取配额(Crawl Budget)”是有限的。如果蜘蛛发现抓取一个 URL 需要经历多层跳转,不仅消耗配额,还可能因为重定向次数过多判定该链接不稳定。
常见的死穴是这样的链条:
用户或外链输入:http://example.com/blog/article-1
- 第一跳:Nginx 的 HTTP 强制跳转 HTTPS(跳到
https://example.com/blog/article-1,301) - 第二跳:Nginx 缺少非 www 到 www 的归一化,再次跳转(跳到
https://www.example.com/blog/article-1,301) - 第三跳:CMS 或前端路由强制要求末尾带斜杠,再次跳转(跳到
https://www.example.com/blog/article-1/,301)
一个简单的页面抓取,连续发生了 3 次 301。更糟糕的是如果开发人员在博客模板内部的 canonical 标签里写的又是不带斜杠的链接,就会导致蜘蛛在两个地址之间反复横跳,收录迟迟无法落地。
用一条 curl 命令就能看清真实的跳转链条:
curl -ILs "http://example.com/blog/article-1" | grep -E "HTTP/|Location:"
在 Nginx 接入层实现“一步到位”跳转,把协议、主域名和斜杠规则合并在同一个 server 块或第一条 rewrite 规则中直接处理完毕:
server {
listen 80;
server_name example.com www.example.com;
return 301 https://www.example.com$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
return 301 https://www.example.com$request_uri;
}
针对内容详情页的 URL 形式,在项目一开始就要统一决定是否带斜杠或 .html 后缀。确定后,在页面 HTML <head> 区域必须输出完全一致的 Canonical 标签:
<link rel="canonical" href="https://www.example.com/blog/article-1.html" />
明确告诉搜索引擎哪一个是标准版本,避免权重分散与无谓的二次重定向。
坑三:动态过滤参数吃光了有限的抓取预算
如果打开 spider_access.log,发现蜘蛛每天抓了几千次,但新发布的文章列表依然毫无动静,很可能是爬虫陷入了站内的参数黑洞。
很多独立博客或者内容系统自带有标签页、归档页、站内搜索和排序功能。常见的 URL 形如:
/tag/linux?sort=desc&page=1
/search?keyword=nginx
/post/123?replytocom=45
这些链接对普通访客查阅历史内容很有帮助,但对爬虫来说,只要页面上有排序选项、分页组合或者评论回复锚点,排列组合出来的 URL 数量就是成千上万个。蜘蛛进入网站后,会把大量的抓取配额全部浪费在爬取这些重复内容或空列表上,真正挂在首页和最新发布列表里的文章,反而因为抓取队列排满而轮不上。
排查日志里是否有被参数带偏的情况:
awk -F'"' '{print $2}' /var/log/nginx/spider_access.log | awk '{print $2}' | grep '?' | cut -d'?' -f1 | sort | uniq -c | sort -nr | head -n 10
如果统计出来有大量的带参路径被高频访问,必须在 robots.txt 中加以约束。
一份清晰健康的 robots.txt 配置范例:
User-agent: *
Disallow: /admin/
Disallow: /search
Disallow: /*?*sort=
Disallow: /*?*order=
Disallow: /*?*replytocom=
Sitemap: https://www.example.com/sitemap.xml
对于那些确实需要保留给用户、但不希望搜索引擎建索引的筛选聚合页面,可以在 Nginx 层面通过响应头告知蜘蛛无需索引:
location /search {
add_header X-Robots-Tag "noindex, follow" always;
# 正常代理或处理逻辑
}
让爬虫抓取后直接标记为不建立索引,但继续跟踪页面内的链接,把宝贵的抓取权重引流回具体的正文页。
坑四:动静缓存与协商缓存失控导致的 304 与空白抓取
第四个坑主要出现在配置了反向代理缓存(如 Nginx FastCGI Cache / Proxy Cache)或者使用了单页应用(SPA)的项目中。
第一种情况是 ETag 和 Last-Modified 头配置异常。有些运维为了压榨服务器性能,给所有动态文章也配置了长周期的静态缓存策略,或者 FastCGI 缓存没有在后台发布新文章时及时清理(purge)。蜘蛛带着 If-Modified-Since 发送请求时,服务器一直无条件返回 304 Not Modified,导致搜索引擎判定页面没有任何新内容更新,放弃更新索引快照。
第二种情况更为严重:前后端分离项目直接返回没有正文的空 HTML 壳子。
像 Vue 或 React 搭建的站点,如果直接部署在静态服务器上,Nginx 返回的原始 HTML 往往只有这一段:
<div id="app"></div>
<script src="/js/app.bundle.js"></script>
虽然现代 Googlebot 具备一定的 JavaScript 渲染能力,但国内的百度、搜狗等爬虫对客户端渲染的支持度依然极低。蜘蛛下载 HTML 时正文内容为空,就会被判定为无效的低质空页面,甚至直接丢弃。
检查蜘蛛眼中的实际页面输出非常简单,在终端用 curl 模拟爬虫 UA 抓取:
curl -s -A "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)" https://www.example.com/article/123.html | grep -i "div id=\"app\""
如果 curl 抓出来的 HTML 里搜不到文章正文标题和文字,说明必须要做服务端渲染(SSR)或者预渲染(Prerender)。
对于不想重构现有单页架构的项目,可以在 Nginx 层面结合轻量预渲染服务(如 Rendertron 或 prerender.io),针对爬虫做区分转发:
map $http_user_agent $prerender_bypass {
default 0;
~*(Baiduspider|Googlebot|bingbot|Sogou) 1;
}
location / {
if ($prerender_bypass = 1) {
proxy_pass http://127.0.0.1:3000/render?url=https://$host$request_uri;
break;
}
try_files $uri $uri/ /index.html;
}
只有当探测到来访者是搜索引擎爬虫时,才把请求交给无头浏览器渲染成完整的 HTML 字符串返回,确保蜘蛛拿到的每一次快照都是饱满的有效文本。
建立日常监控检查项
把这四个环节全部梳理一遍之后,两周未收录的问题在两三天内就得到了解决:蜘蛛日志里的状态码稳定在 200,抓取频次恢复正常,站长平台的有效索引量开始平稳上升。
服务器层面的技术 SEO 不需要每天盯着看,但几个基本环节必须理顺:
- 用独立的 log 记录合规蜘蛛抓取,定期看一眼状态码分布。
- 限流和防刷规则必须对正规爬虫网段做白名单豁免,严防 403 和 503 误伤。
- 规范化整站的重定向逻辑,保证协议、域名和路径一次性 301 落地。
- 在 robots.txt 中卡住无意义的动态参数,将抓取预算留给真正的内容页面。
- 用 curl 模拟爬虫检查输出内容,确认返回的 HTML 带有完整的正文文本。
先把通道打通,让爬虫能无障碍、低成本地读到正文,优质的内容才有机会在搜索结果里拿到该有的排名。
文章标题:新发文章搜索引擎死活不收录?排查 Nginx 爬虫误拦、斜杠死循环与抓取配额浪费我踩过的几个坑
文章链接:https://www.llbbs.cn/jishujaocheng/215.html
本站文章均为原创,未经授权请勿用于任何商业用途
评论一下?