很多站长做 SEO 都是 Bing、Yandex、Naver 一个平台一个平台地提交,其实有个协议可以一次提交、多家同步推送,这就是 IndexNow。本文从原理到部署,一步步讲清楚怎么用 PHP 脚本实现批量推送。
一、IndexNow 是什么,支持哪些搜索引擎
IndexNow 是一个开放的推送协议,你在网站上放一个密钥文件,然后通过 API 把新页面 URL 推送给 IndexNow,它会自动分发给所有支持该协议的搜索引擎,不用每个站长平台单独提交。
| 搜索引擎 | 地区 | 支持情况 |
|---|---|---|
| Bing 必应 | 全球 | ✅ 完全支持 |
| Yandex | 俄罗斯 | ✅ 完全支持 |
| Naver | 韩国 | ✅ 支持 |
| Seznam | 捷克 | ✅ 支持 |
| Yep | 全球 | ✅ 支持 |
| Mojek | 波兰 | ✅ 支持 |
| 百度 | 中国大陆 | ❌ 不支持 |
百度不支持 IndexNow,继续用百度自己的普通收录 API,两套并行不冲突。
二、和百度普通收录有什么区别
| 对比项 | 百度普通收录 | IndexNow |
|---|---|---|
| 推送对象 | 百度 | Bing / Yandex / Naver 等 |
| 接口地址 | data.zz.baidu.com | api.indexnow.org/indexnow |
| 推送方式 | POST text/plain | POST application/json |
| 所有权验证 | 不需要,用 token | 需要在根目录放密钥文件 |
| 单次 URL 数 | 每日有额度 | 单次最多 100 条 |
三、第一步:放密钥验证文件
1. 生成密钥
去 indexnow.org 可以自动生成一个随机密钥,也可以自己写一段 8~128 位的字符串(只允许大小写字母、数字、横线)。
比如:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
2. 创建 txt 文件
在网站根目录新建一个 txt 文件,文件名就是密钥本身,例如:
a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.txt
文件内容只写密钥,不要多空格、不要换行:
a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
3. 验证文件能不能访问
浏览器打开:
https://你的域名/a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.txt
必须满足:
- 裸文本直接显示密钥
- HTTP 状态码 200
- 不能 404 / 403 / 301 跳转
- 海外 IP 也能访问(国内能打开不代表海外 Bing 爬虫能打开)
几个容易踩的坑:
- 密钥区分大小写,文件名大小写错一个字符就失败。
- 文件编码必须是 UTF-8 无 BOM。
- 文件内容不能有多余的换行和空格。
- 国内服务器如果有 WAF 或者安全组拦截了海外 IP,搜索引擎后端访问不到这个 txt,会返回 403。
四、第二步:批量推送 PHP 脚本
新建一个 PHP 文件放到网站根目录,比如 push.php:
<?php
// ===== 改成你自己的 =====
$host = "你的域名.com";
$key = "你的密钥";
$keyLocation = "https://你的域名.com/你的密钥.txt";
// 要推送的 URL 列表,单次最多 100 条
$urlList = [
"https://你的域名.com/post-1.html",
"https://你的域名.com/post-2.html",
"https://你的域名.com/post-3.html",
// 继续加,不要超过 100 条
];
// ===== 下面不用改 =====
$postData = json_encode([
"host" => $host,
"key" => $key,
"keyLocation" => $keyLocation,
"urlList" => $urlList,
], JSON_UNESCAPED_SLASHES);
$opts = [
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json; charset=utf-8\r\n",
'content' => $postData,
'timeout' => 30,
],
];
$context = stream_context_create($opts);
$result = file_get_contents('https://api.indexnow.org/indexnow', false, $context);
$responseHeaders = $http_response_header;
echo "推送数量:" . count($urlList) . " 条<br>";
echo "返回内容:" . var_export($result, true) . "<br>";
echo "<pre>响应头:";
print_r($responseHeaders);
echo "</pre>";
?>
怎么用
- 把上面代码保存为
push.php,上传到网站根目录。 - 修改配置区的域名、密钥、密钥文件地址。
- 把要推送的 URL 填进
$urlList数组,单次不要超过 100 条。 - 浏览器访问
https://你的域名.com/push.php。
怎么看成功没有
看页面输出的响应头:
- HTTP 200 OK + Content-Length: 0 = 提交成功,响应体是空的是正常现象。
- 如果看到
X-MSEdge-Ref开头的响应头,说明请求已经到了微软 Bing 的服务器。
五、进阶:自动从数据库读 URL 批量推送
如果你的网站有数据库,可以让脚本自动读取最新文章 URL,不用手动复制粘贴。以 SQLite 数据库为例:
<?php
$host = "你的域名.com";
$key = "你的密钥";
$keyLocation = "https://你的域名.com/你的密钥.txt";
// 连接数据库读最新文章
$dbFile = __DIR__ . '/site.db';
$db = new PDO("sqlite:{$dbFile}");
$stmt = $db->query("SELECT id FROM article ORDER BY create_time DESC LIMIT 100");
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
$urls = [];
foreach ($rows as $r) {
$urls[] = "https://你的域名.com/article-{$r['id']}.html";
}
// 推送
$postData = json_encode([
"host" => $host,
"key" => $key,
"keyLocation" => $keyLocation,
"urlList" => $urls,
], JSON_UNESCAPED_SLASHES);
$opts = [
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json; charset=utf-8\r\n",
'content' => $postData,
'timeout' => 30,
],
];
$context = stream_context_create($opts);
$result = file_get_contents('https://api.indexnow.org/indexnow', false, $context);
echo "推送数量:" . count($urls) . " 条<br>";
echo "返回结果:" . $result;
?>
MySQL 数据库的话,把 PDO 连接串改成 MySQL 的,SQL 查询语句对应修改就行。
六、WordPress 用户:发布文章自动推送
如果你用的是 WordPress,可以把下面代码加到当前主题的 functions.php,实现发布或更新文章时自动推送,以后新增文章不用手动跑脚本:
// IndexNow 自动提交
add_action('save_post', function ($post_id) {
if (wp_is_post_autosave($post_id) || wp_is_post_revision($post_id)) return;
if (get_post_type($post_id) !== 'post') return;
if (get_post_status($post_id) !== 'publish') return;
$url = get_permalink($post_id);
$host = "你的域名.com";
$key = "你的密钥";
$keyLocation = "https://你的域名.com/你的密钥.txt";
$postData = json_encode([
"host" => $host,
"key" => $key,
"keyLocation" => $keyLocation,
"urlList" => [$url],
], JSON_UNESCAPED_SLASHES);
$opts = [
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json; charset=utf-8\r\n",
'content' => $postData,
'timeout' => 15,
],
];
$context = stream_context_create($opts);
@file_get_contents('https://api.indexnow.org/indexnow', false, $context);
}, 10, 1);
这个钩子只管新增和更新文章,存量历史文章还是要用第四节的批量脚本一次性推送。
七、接口返回码对照表
| HTTP 状态码 | 含义 | 排查方向 |
|---|---|---|
| 200 OK | 提交成功 | 响应体为空是正常的 |
| 400 Bad Request | 请求格式错误 | JSON 格式不对、URL 非法 |
| 403 Forbidden | 密钥校验失败 | 搜索引擎访问不到你的 txt 文件,或文件内容不对 |
| 422 Unprocessable Entity | URL 域名不匹配 | urlList 里的域名和 host 字段不一致 |
| 429 Too Many Requests | 请求过多 | 频率太高,隔几分钟再试 |
八、常见问题排查
1. 访问密钥 txt 返回 404
- 检查文件名是否和密钥完全一致(大小写敏感)。
- 检查文件是否在网站根目录。
- 检查 Nginx / Apache 伪静态规则是否拦截了 .txt 文件。
2. 提交返回 403
- 国内浏览器能打开 txt,但海外 Bing 爬虫打不开。
- 检查服务器防火墙 / 安全组是否限制了海外 IP。
- 检查 CDN / WAF 是否拦截了海外请求。
3. 提交返回 400
- JSON 格式错误(少括号、引号没闭合)。
- urlList 为空。
- URL 里带了多余的标记,要填纯 URL。
4. PHP 脚本访问报 500
- 检查 php.ini 的 allow_url_fopen 是否开启(必须 On)。
- 检查 disable_functions 是否禁用了 file_get_contents。
- 看 PHP 错误日志定位。
5. 脚本返回空、没有响应头
- 服务器出站网络无法访问 api.indexnow.org,国内服务器比较常见。
- 可以尝试用 CDN 或者海外中转服务器跑脚本。
九、几个注意事项
- 单次最多提交 100 条 URL,超过就分批。
- 不要反复推送未修改的旧 URL,不会加速收录,反而可能被判定为垃圾提交。
- 批量推送脚本用完就删,不要长期留在公网,防止别人恶意调用触发 429 限流。
- 如果必须保留脚本,加访问密码,只允许自己访问。
- IndexNow 只推海外搜索引擎,百度继续用自己的普通收录 API,两套并行。
- 提交成功只是通知搜索引擎来抓取,不等于立刻收录,收录还要看页面质量和网站权重。
十、快速上手清单
- 生成密钥,根目录放密钥 txt 文件
- 浏览器访问 txt 文件,确认返回 200、裸文本显示密钥
- 确认海外 IP 也能访问这个 txt
- 复制批量脚本,改成自己的域名和密钥
- 填入要推送的 URL(不超过 100 条),访问脚本提交
- 看返回 200 即成功
- WordPress 用户加 functions.php 钩子,实现自动推送
- 用完删除批量脚本
- 百度继续用原来的推送方式,互不影响
