建站快两年了,感觉国内的搜索引擎是真的谜!我的网站同时提交给了 Google 、必应、百度、搜狗、360 ,目前 Google 和 必应 基本已经收录了所有网页,新网页也能在 24 小时内收录,很容易就能搜到我的网站。但国内的搜索引擎就很难搜到我的网站,百度的 sitemap 基本上也是半个月前的,点击 手动更新文件 也是一直显示等待:

百度网站地图提交页面

吐槽的差不多了,下面是用 PHP 主动给百度推送 sitemap.xml 也就是网站地图。

推送方式

目前百度的推送方式包括 主动推送、自动推送、sitemap、手动提交 URL。主动推送就是通过 POST 方式把 URL 提交给百度。自动推送就是在网站 HTML 中添加百度的 JS 推送代码,通过访问者的浏览器推送。sitemap 就是把网站地图的访问地址提交给百度,百度定期访问网站地图来获取 URL。

sitemap 基本上是长时间不会抓取,我的最近一次抓取还是在半个月前。JS 需要手动访问网页,而且可能还会被浏览器阻止,网络不好的情况下可能会影响速度。目前只剩下了主动推送方式提交 URL,百度对提交格式的要求是每行一个 URL,也就是用换行符分隔,百度也给出了一段 PHP 示例,如下:

$urls = array(
    'http://www.example.com/1.html',
    'http://www.example.com/2.html',
);
$api = 'http://data.zz.baidu.com/urls?site=xxx&token=xxx';
$ch = curl_init();
$options =  array(
    CURLOPT_URL => $api,
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => implode("\n", $urls),
    CURLOPT_HTTPHEADER => array('Content-Type: text/plain'),
);
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
echo $result;

这里用到了 Client URL 库 ,我之前写的 PHP 发送 GET 和 POST 请求 也用到了 Client URL 库。百度的示例是把 URL 放在数组里,然后在把数组转为字符串 用 \n 分隔。提交地址后面的 site 参数就是网站域名,token 就是 推送秘钥。

处理 XML

我的网页数量虽然不多 但也不可能手动写 URL,所以只能把 sitemap.xml 中的 URL 转换为 1行 1个 提交给百度。生成 sitemap 的工具和网站有很多,这里推荐一个我正在用的在线生成 sitemap.xml 的网站:https://www.xml-sitemaps.com/ ,只需要输入网站域名就能生成 sitemap.xml

下面是 sitemap.xml 的格式:

<url>
  <loc>https://www.misterma.com/</loc>
  <lastmod>2019-07-08T06:55:06+00:00</lastmod>
  <priority>1.00</priority>
</url>
<url>
  <loc>https://www.misterma.com/cross.html</loc>
  <lastmod>2019-07-08T06:55:06+00:00</lastmod>
  <priority>0.80</priority>
</url>
<url>
  <loc>https://www.misterma.com/category/php/</loc>
  <lastmod>2019-07-08T06:55:06+00:00</lastmod>
  <priority>0.80</priority>
</url>

提交的时候只需要 loc ,下面是 PHP 代码:

<?php

//  读取 sitemap.xml 文件 并 转换为 PHP 对象
$xml = simplexml_load_file('sitemap.xml');

$urls = array();  //  稍后用来存储 URL

foreach ($xml->url as $val) {
    //  把 loc 中的 URL 添加到 $urls 数组
    array_push($urls, $val->loc);
}

这里得到了一个包含 URL 的数组,只需要把数组转换为 1 行 1个的字符串就可以提交给百度了,转换函数为: implode("\n", $urls) 。提交后会返回一个 JSON 格式的字符串,需要把 JSON 字符串转换为 PHP 对象才能方便的判断,转换函数为: json_decode() 传入需要转换的 JSON 字符串,返回转换后的 PHP 对象,如果要更详细的了解 PHP 操作 JSON 可以看: PHP 操作 JSON 格式数据

因为上面的代码很多都有注释且比较简单,就不逐句介绍了。

返回结果

如果成功会返回:

{
    "remain": 4999998,
    "success": 2
}

或者:

{
    "remain": 4999998,
    "success": 2,
    "not_same_site": [],
    "not_valid": []
}

下面是返回结果说明:

字段是否必选参数类型说明
successint成功推送的url条数
remainint当天剩余的可推送url条数
not_same_sitearray由于不是本站url而未处理的url列表
not_validarray不合法的url列表

如果发生错误会返回:

{
    "error": 401,
    "message": "token is not valid"
}

其中 error 是错误码,message 是错误信息。

完整示例

下面是完整示例:

<?php

//  读取网站地图并转换为 PHP 对象
$xml = simplexml_load_file('sitemap.xml');

$urls = array();  //  用来存储 URL

foreach ($xml->url as $val) {
    //  把 URL 添加到 $urls
    array_push($urls, $val->loc);
}

$api = 'http://data.zz.baidu.com/urls?site=xxx&token=xxx';  //  提交地址

$ch = curl_init();

$options =  array(
    CURLOPT_URL => $api,
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => implode("\n", $urls),
    CURLOPT_HTTPHEADER => array('Content-Type: text/plain'),
);

curl_setopt_array($ch, $options);

$result = curl_exec($ch);

$result = json_decode($result);  //  把返回的json字符串转换为php对象

//  是否推送成功
if (isset($result->success)) {
    //  输出已推送的 URL 数量和网站地图中的 URL 数量
    echo '推送完成,已推送的 URL 数量:' . $result->success . '网站地图中的 URL 数量:' . count($xml->url);
}else {
    echo '推送失败,错误代码:' . $result->error;
}