七月初我给个人网站做了一轮 SEO 整改:固定链接从 ?p=123 换成语义化的 /%postname%/,装了 sitemap 插件,提交了百度搜索资源平台,还挂了一个每天早上七点半自动跑的主动推送脚本。做完之后信心十足——sitemap 里五十多篇文章,百度主动推送每天跑,Google 那边已经从收录 1 页涨到 123 页,百度总不至于一个月了还是零。
然而就是零。资源平台的”索引量”写着”数据计算中”,抓取频次图一片空白。
第一反应:一定是服务器的问题
新站收录慢,我可以理解。但一个月一条不收,说不过去。我的第一反应是去查服务器:robots.txt 有没有误拦、百度爬虫的 UA 有没有被 WAF 挡、服务器有没有对百度 IP 返回异常状态码。
全部正常。用百度资源平台的”抓取诊断”工具手动抓了几个 URL,200,正文完整。服务器这头没问题。
第二反应:可能就是慢
于是我安慰自己:百度对新站就是慢,Google 快是因为我提了 GSC 和 sitemap。等着吧。
但这个解释有一个漏洞:我明明挂了主动推送。主动推送是百度给站长开的”加急通道”——你把 URL 推过去,百度承诺优先处理。每天跑,跑了四十多天,一条也没进?这不是”慢”能解释的。
真正的问题:一行日志
七月十五号我决定不猜了,去服务器看推送脚本的实际返回。
{"error":400,"message":"over quota"}
每一天,每一次,都是这个。从六月底挂上 cron 的第一天起,一条 URL 也没成功推送过。
原因极其简单:我的旧脚本每次把 sitemap 里全部五十八条 URL 一次性 POST 给百度的推送接口。而百度给新站的每日配额是十条。超出配额,百度不是只拒多出来的那些——它整批拒收,连前十条也不要。返回 400,全军覆没。
四十多天,每天跑一次,每次全军覆没,脚本没有做返回值检查,cron 不报错,推送日志也没人看。一切都在”正常运行”,只是什么也没推进去。
修法:十条十条地来
修复只花了十五分钟。新脚本做三件事:
一,读 sitemap,提取所有文章 URL。二,对照一个台账文件——记录哪些 URL 已经成功推过——筛出”还没推过的”。三,每次只推前十条(配额数),推送成功(返回里有 "success" 且没有 "error")才把这十条记进台账。明天跑的时候,这十条不再出现,轮到下十条。
首次手动跑:
{"remain":0,"success":10}
remain:0 是”今天的配额用完了”,success:10 是”这十条百度收了”。五十八条积压,按十条一天,六天推完。之后每天只推新发的文章,配额绰绰有余。
这个坑为什么静默了四十天
回头看,问题不在于我不知道百度有配额——注册时文档里写了。问题在于我把”推送”这个动作当成了发后不理的 fire-and-forget:脚本跑了就行,成没成功不看。这是运维里最常见的过度信任:cron 没报错 ≠ 任务成功。
百度这个接口的行为也有点反直觉。你推十一条,它可以只收前十条、拒掉第十一条——大多数人会预期这种”部分成功”的行为。但它实际上是整批拒收:超配额 = 400,一条不留。这意味着你越努力推(每次推得越多),效果越差。一个”勤快反而吃亏”的接口设计。
通用教训
这个坑不大——修十五分钟,等六天恢复——但它的形状很典型,值得画出来:
“自动化运行”和”自动化生效”是两件事。 cron 保证了脚本每天跑,但跑了不等于推了,推了不等于进了。任何推送/同步/上报类的自动化任务,都得检查返回值,而且得有一个人类能看到的信号告诉你”今天没成功”。哪怕只是往一个文件里追加一行”失败”。
配额类接口,永远按配额分批,不要一次性全推。 这条不止百度适用。几乎所有有速率限制的 API(邮件、推送、索引提交)都有类似行为:超了就全拒,或者超了就限速二十四小时。正确做法是先查配额剩多少,再推不超过剩余额度的量,推完记账。
“反正每天跑”不是容错,是遮掩。 如果第一天失败了、第二天用同样的方式重试,结果也是失败——那每天跑只是每天失败一次。真正的容错是检测到失败后改变策略,而非重复同一个策略指望不同结果。
现在是修完后第四天。百度资源平台的”索引量”仍然显示”计算中”——据说新站出数要几天到一周。下个月一号是我给自己定的月度复盘节点,届时看数字。
如果你也在用百度主动推送,先去服务器 cat 一下你那个脚本的日志。说不定它也在每天勤勤恳恳地失败着。