图标变灰地球多与SEO无关,而是favicon文件、声明或MIME配置有坑。先诊断真缺失还是抓取失败,再补齐根目录图标、HTML声明,并警惕nginx的types{}替换全局导致类型错乱;必应抓取不走Bingbot日志。全套配置不足百行即可修复。
搜索结果里站点左侧那个小图标,三个月前还是自己的 LOGO,某天突然变成了一个灰扑扑的地球。绝大多数人这时候会做一件事:反复刷新、反复等、反复怀疑是不是被降权了。其实九成情况跟SEO 无关,是图标文件或声明方式有坑。
这篇记录我在 997笔记上的完整排查:从怎么确认「是真没图标还是工具没显示」,到站点根要放哪些文件、HTML 怎么声明、nginx 有个能把全站图片类型搞坏的坑,以及最关键的——必应图标为什么根本不看你的日志。全套配置不到 100 行,不改主题文件。
一、先诊断:分清「真没有」和「抓不到」
动手改之前,先分清三种完全不同的情况。搞混了会白折腾很久。
| 现象 | 真实原因 | 该做什么 |
|---|---|---|
| 搜索结果图标是灰色地球 | 搜索引擎没抓到你的图标 | 往下看,补全配置 |
| 浏览器标签页也是地球 | HTML 声明缺失或路径 404 | 检查 link 标签和文件可达 |
| 昨天还有今天没了 | 多为工具侧反爬降级或缓存波动 | 换非隐私窗口复核,别改站点 |
先跑这三条命令拿到硬数据,别靠猜:
# 1. 站点根favicon 是否可达
curl -sI https://你的域名.com/favicon.ico | head -5
# 2. HTML 里声明了哪些 icon
curl -s https://你的域名.com/ | grep -o '<link[^>]*icon[^>]*>'
# 3. 逐个验证文件真实存在
for f in favicon.ico favicon-32.png apple-touch-icon.png site.webmanifest; do
printf '%-24s ' "$f"
curl -s -o /dev/null -w '%{http_code} %{content_type}n' "https://你的域名.com/$f"
done
重点看第三项的 content_type。很多新手只看到 200 就放心了,但文件返回 application/octet-stream 时,多数爬虫会直接放弃解析——这是最常见的隐藏坑,第四、五节专门讲。
二、搜索结果图标是怎么来的(原理)
先搞懂机制,才知道该改哪里。三个关键认知:
1. 大部分搜索引擎优先抓根目录的 /favicon.ico
这是历史约定。不是去解析你 HTML 里的 <link> 标签。所以只在后台设置站点图标、但根目录没有这个文件的话,搜索引擎大概率找不到。
2. 抓到了不等于会用
搜索引擎抓到图标后会做缓存,缓存里是一张 32×32 的小图。这张图一旦生成,很长时间不会更新——除非你主动催它。所以「配置全对了但还是地球」是正常状态,不是没配好。
3. 必应的图标抓取不走 Bingbot
这点很反直觉。检查服务器日志:
grep -i 'bingbot' access.log | grep -i 'favicon'
# 输出:空
是不是很慌?别慌,这是正常的。必应派了独立服务去抓图标,不以 Bingbot 身份请求,日志里自然看不到。所以「日志里没人来取 favicon」不能作为「我配置错了」的证据。
三、站点根要放哪些文件
一套完整配置需要这几个。缺哪个补哪个:
| 文件 | 必需 | 尺寸 / 格式 | 作用 |
|---|---|---|---|
favicon.ico |
必需 | 16/32/48/64 多帧 | 搜索引擎的首选抓取目标 |
favicon-32.png |
推荐 | 32×32 PNG | HTML 里显式声明 32 尺寸 |
favicon-192.png |
推荐 | 192×192 PNG | 高分屏 / PWA |
favicon-512.png |
可选 | 512×512 PNG | 后台选站点图标用 |
apple-touch-icon.png |
推荐 | 180×180 不透明底 | iOS 主屏图标 |
site.webmanifest |
可选 | JSON | PWA 应用名与图标 |
apple-touch-icon 必须用不透明底。iOS 会把透明区域渲染成黑色,你的 LOGO 会被一块黑底包住。在生成时铺一层白底再合成:
bg = Image.new("RGBA", (512, 512), (255, 255, 255, 255)) # 白底
bg.alpha_composite(logo) # 合成你的透明 LOGO
at = bg.resize((180, 180), Image.LANCZOS)
at.save("apple-touch-icon.png")
生成脚本(Python,可直接跑)
从一张 512×512 的透明底源图,一键派生全套:
from PIL import Image
im = Image.open("logo-512.png").convert("RGBA")
# 多帧 ICO —— 覆盖 16/32/48/64,各尺寸搜索引擎认得最清楚
im.save("favicon.ico", "ICO", sizes=[(s, s) for s in (16, 32, 48, 64)])
# 各尺寸 PNG
for s in (32, 192, 512):
im.resize((s, s), Image.LANCZOS).save("favicon-%d.png" % s, "PNG")
# apple-touch-icon:白底,避免 iOS 黑块
bg = Image.new("RGBA", (512, 512), (255, 255, 255, 255))
bg.alpha_composite(im)
bg.resize((180, 180), Image.LANCZOS).save("apple-touch-icon.png", "PNG")
im.save("icon-512.png", "PNG")
manifest = {
"name": "你的站名",
"short_name": "站名",
"icons": [
{"src": "/favicon-192.png", "sizes": "192x192", "type": "image/png"},
{"src": "/icon-512.png", "sizes": "512x512", "type": "image/png"},
],
"theme_color": "#0b111c",
"background_color": "#ffffff",
"display": "standalone",
"start_url": "/",
}
import json
json.dump(manifest, open("site.webmanifest", "w", encoding="utf-8"),
ensure_ascii=False, indent=2)
四、🔴 最大的坑:nginx 的 types{} 是替换不是叠加
如果你想让 site.webmanifest 被浏览器正确识别,需要加 MIME 映射。然后你多半会写这么一段:
types {
application/manifest+json webmanifest;
}
看起来很无害。提交 nginx -t 通过,reload 成功。但刷新站点后会发现全站图片、JS、CSS 全都变成了 application/octet-stream——包括你刚做好的 favicon。
原因:nginx 的 types{} 块一旦出现,就会完全替换掉从全局 mime.types 继承的映射,而不是与它合并。你在 server 块里只写了一行,等于宣布「本站点只认 webmanifest 这一种类型,其他全部未知」。
还有一个更隐蔽的连带坑:很多人发现类型不对时会去加
default_type application/octet-stream;
这行更糟——它会把整个 mime.types 彻底顶掉,全站每个静态文件的 Content-Type 都变成 octet-stream。站点看着还能用(浏览器会猜类型),但搜索引擎的解析会全面受影响。
正确做法:显式列全你用到的类型,并去重
types {
application/manifest+json webmanifest;
image/x-icon ico;
image/png png;
image/jpeg jpg jpeg;
image/gif gif;
image/svg+xml svg svgz;
image/webp webp;
image/avif avif;
text/css css;
text/javascript js mjs;
application/json json map;
text/xml xml;
text/plain txt md;
font/woff2 woff2;
font/woff woff;
font/ttf ttf;
font/otf otf;
}
同一扩展名只能映射一个类型。比如你既写 application/xml xml; 又写 text/xml xml;,nginx 会告警:
nginx: [warn] duplicate extension "xml", content type: "text/xml",
previous content type: "application/xml"
这不是致命错误,但会让启动输出变脏。养成改完跑 nginx -t 看有没有 warn 的习惯,做到零警告才算干净。
改完必须验证
nginx -t # 语法 + 看有无 duplicate 警告
nginx -s reload
# 逐个核对 Content-Type,别只看 200
for f in favicon.ico favicon-192.png site.webmanifest; do
printf '%-24s ' "$f"
curl -sI "https://你的域名.com/$f" | grep -i '^content-type'
done
期望看到 image/x-icon、image/png、application/manifest+json。如果看到 application/octet-stream,就是踩了上面那个坑。
五、HTML 声明:顺序比数量重要
文件放好了,还得在 HTML 里声明。这里有个容易忽略的细节:浏览器和爬虫取 sizes="32x32" 时,读的是第一条匹配的声明。所以把正确的那条放前面,别指望「后面那条也能被认到」。
顺序上还有一层:WordPress 主题通常在 wp_head 里输出自己的图标声明。如果你的声明排在主题之后,优先级就低了。
| 优先级 | 挂载点 | 效果 |
|---|---|---|
| 高 | mu-plugin 挂 wp_head 优先级 2 |
排在主题模板之前,推荐 |
| 低 | 主题 header.php 直接改 | 能用,但主题升级即失效 |
完整 mu-plugin(不改主题,升级不失效)
<?php
/**
* Plugin Name:站点 favicon 增强
* Description: 补齐主题未输出的 favicon 声明。
* Version: 1.0
*/
if (!defined('ABSPATH')) {
exit;
}
final class N997_Favicon
{
public static function init()
{
add_action('wp_head', array(__CLASS__, 'printTags'), 2);
}
public static function printTags()
{
if (is_admin() || (defined('DOING_AJAX') && DOING_AJAX)) {
return;
}
$home = home_url('/');
$lines = array();
// .ico 直指 —— 搜索引擎图标服务的标准抓取目标
$lines[] = '<link rel="icon" type="image/x-icon" sizes="32x32" href="' . esc_url($home . 'favicon.ico') . '">';
$lines[] = '<link rel="icon" type="image/png" sizes="32x32" href="' . esc_url($home . 'favicon-32.png') . '">';
$lines[] = '<link rel="icon" type="image/png" sizes="192x192" href="' . esc_url($home . 'favicon-192.png') . '">';
// apple-touch-icon —— 根目录白底版,避免透明底被压黑
$lines[] = '<link rel="apple-touch-icon" sizes="180x180" href="' . esc_url($home . 'apple-touch-icon.png') . '">';
// PWA
$lines[] = '<link rel="manifest" href="' . esc_url($home . 'site.webmanifest') . '">';
$lines[] = '<meta name="theme-color" content="#0b111c">';
echo "n" . implode("n", $lines) . "n";
}
}
N997_Favicon::init();
放到 wp-content/mu-plugins/ 目录下(不是普通插件目录)。mu-plugin 会被自动加载、后台无法禁用、主题更新也不会覆盖它。
六、验证:4 个命令确认到位
# 1. 第一条 32x32 是不是 .ico(关键)
curl -s https://你的域名.com/ | grep -o '<link[^>]*sizes="32x32"[^>]*>' | head -1
# 期望:href=".../favicon.ico"
# 2. Content-Type 全部正确
curl -sI https://你的域名.com/favicon.ico | grep -i content-type
# 期望:image/x-icon
# 3. nginx 无警告
/www/server/nginx/sbin/nginx -t 2>&1 | grep -c warn
# 期望:0
# 4. 浏览器实际取到的图标
# 打开首页 → F12 → Network → 过滤 favicon → 看第一个请求
七、必应图标刷新的真实机制
这是新手最容易被坑的地方:配置全对,图标还是地球。
原因很简单:搜索引擎把图标缓存了。缓存的刷新由它自己决定,通常几天到两周。配置正确只是「让下次刷新时能抓到新图」,不能立刻生效。
能做什么加速
- 必应站长工具 → URL 检查:提交首页 URL,额度有限,用在真正重要的页面上。
- IndexNow 协议:必应官方推送接口,不消耗 URL 检查额度。IndexNow 规范只接受 HTML 页面 URL,所以能催页面抓取,但对 favicon 图标缓存无直接作用。
预期管理很重要。把 favicon 配置做好 = 排除了一个故障因素,剩下交给时间。如果配置不全,等两周也是白等;配置全了,两周内大概率自己就变了。不要因为「今天还是地球」就反复改动站点——每次改动都可能触发新的缓存失效。
八、一句话总结
搜索结果图标采集不到,按这个顺序查:
- 确认是不是真问题 —— 换个非隐私窗口查,排除工具反爬降级
- 站点根放齐文件 ——
favicon.ico(多帧)+ 32/192 PNG + apple-touch(白底) - 核对 Content-Type —— 不只是看 200,要看类型对不对
- HTML 补声明 —— mu-plugin 挂
wp_head优先级 2,确保sizes="32x32"第一条是 .ico - 避开 nginx 坑 ——
types{}是替换不是叠加,别加default_type,改完跑nginx -t看零警告 - 然后等 —— 缓存刷新由搜索引擎自己决定,一到两周
整套配置不到 100 行、一个 mu-plugin 文件、一次 nginx 改动。剩下的就是交给时间。
- 文章名称:搜索结果图标采集不到怎么办:favicon 完整排查与修复攻略
- 文章永久网址:https://www.997wan.com/favicon-not-crawled-fix-guide/
- 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长 997笔记 进行删除处理。
- 本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
- 本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
- 本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
- 如无特别声明本文即为原创文章仅代表个人观点,版权归《997笔记》所有,欢迎转载,转载请保留原文链接。