sitemap.xml 自动向百度站长平台推送链接。然而,脚本运行后,出现了一个诡异的现象:终端显示 API 接口调用成功,剩余配额扣除了,但“成功推送条数”却是 0。
🚀 百度反馈结果:
🎉 成功推送: 0 条
📅 今日剩余配额: 10
明明我的 Sitemap 里有 90 多个链接,为什么百度一条都不收?
🔍 排查过程
我在脚本里加了一行 print 代码,打印出脚本到底抓取了什么链接。
真相瞬间大白:
👀 正在尝试推送的链接示例: http://localhost:1313/science/efficacy-liver-immunity/
原来,我推给百度的全是 localhost 的本地预览链接!
百度蜘蛛肯定访问不了我家里的电脑,自然全部拒收。
💡 原因分析
这是一个 Hugo 初学者(包括我)非常容易忽视的机制:
-
当你运行 hugo server 时:
Hugo 会在内存中生成网站,为了方便本地调试,它会强制把 sitemap.xml 里的域名替换为 http://localhost:1313。
-
当你只运行 hugo 时:
Hugo 才会读取配置文件 hugo.toml 中的 baseURL(例如 https://huoshantiepifengdou.com/),生成真正的生产环境文件。
我之前的操作习惯是开着 hugo server 预览,然后直接运行 Python 脚本,读取到的自然是“假”的 Sitemap。
✅ 解决方案
第一步:修正 Hugo 配置
确保 hugo.toml 中的 baseURL 是带 HTTPS 且以斜杠结尾的标准格式:
baseURL = "[https://huoshantiepifengdou.com/](https://huoshantiepifengdou.com/)"
第二步:正确的构建流程
在运行推送脚本前,必须先生成正式文件(最好先清理一下缓存):
# 1. 清理旧文件
rm -rf public
# 2. 生成正式环境文件 (千万别加 server 参数)
hugo
# 3. 运行 Python 推送脚本
python baidu_push.py
附:优化后的 Python 推送脚本
如果你也需要这个功能,这是我修复 SSL 警告并增加了配额限制的最终版脚本:记得将配置区域的BAIDU_TOKEN换成你的哦。
import requests
import xml.etree.ElementTree as ET
import os
# ================= 配置区域 =================
# 1. 您的网站域名
SITE_URL = 'https://huoshantiepifengdou.com'
# 2. 您的百度准入密钥 (保持您原来的 Token 不变)
BAIDU_TOKEN = '您的百度准入密钥'
# 3. Sitemap 文件路径
SITEMAP_FILE = 'public/sitemap.xml'
# 4. ⚠️ 每日最大推送数量限制 (新站建议设为 10 或 20)
# 百度普通收录配额:新站通常只有 10-100 条/天
MAX_PUSH_LIMIT = 10
# ===========================================
def get_urls_from_sitemap(file_path):
"""从 sitemap.xml 中提取 URL"""
if not os.path.exists(file_path):
print(f"❌ 错误:找不到文件 {file_path}")
return []
urls = []
try:
tree = ET.parse(file_path)
root = tree.getroot()
namespace = {'ns': 'http://www.sitemaps.org/schemas/sitemap/0.9'}
for url in root.findall('ns:url', namespace):
loc = url.find('ns:loc', namespace).text
if loc:
urls.append(loc)
print(f"✅ Sitemap 中共有 {len(urls)} 个链接。")
return urls
except Exception as e:
print(f"❌ 解析 Sitemap 失败: {e}")
return []
def push_to_baidu(urls):
"""将 URL 推送到百度 API"""
if not urls:
print("⚠️ 没有链接需要推送。")
return
# 截取前 N 个链接进行推送
urls_to_push = urls[:MAX_PUSH_LIMIT]
# 👉 加上这一行,看看推的第一个链接长啥样
print(f"👀 正在尝试推送的链接示例: {urls_to_push[0]}")
print(f"✂️ 为防止超额,本次仅推送前 {len(urls_to_push)} 条链接...")
api_url = f'http://data.zz.baidu.com/urls?site={SITE_URL}&token={BAIDU_TOKEN}'
headers = {
'User-Agent': 'curl/7.12.1',
'Content-Type': 'text/plain'
}
try:
response = requests.post(api_url, headers=headers, data='\n'.join(urls_to_push))
result = response.json()
print("\n🚀 百度反馈结果:")
if 'success' in result:
print(f"🎉 成功推送: {result['success']} 条")
print(f"📅 今日剩余配额: {result['remain']}")
else:
# 打印详细错误
print(f"⚠️ 推送失败: {result}")
if result.get('error') == 400 and result.get('message') == 'over quota':
print("💡 提示:今日配额已用完,请明天再试,或降低 MAX_PUSH_LIMIT。")
except Exception as e:
print(f"❌ 网络请求失败: {e}")
if __name__ == '__main__':
print("--- 开始执行百度 SEO 主动推送 (安全模式) ---")
# 1. 获取所有链接
all_urls = get_urls_from_sitemap(SITEMAP_FILE)
# 2. 执行受限推送
if all_urls:
push_to_baidu(all_urls)
print("\n--- 执行完毕 ---")
🎯 总结
技术路上全是细节。
hugo server 是给博主看的,hugo 是给搜索引擎看的。
搞清楚这个区别,SEO 自动化之路才能走得通。
-----------2026-1-17 更新-------------
今天推送发现了一个问题:今天推送的和昨天推送的文章链接完全一样,这样下去的话,就浪费了推送名额。程序还需要修改。
改为只推送最近3天时间里,文章有过更新或者修改的链接。
需要修改配置文件:可以将这段代码放在 hugo.yaml 的最后。
# --- Sitemap 与 Git 时间配置 ---
enableGitInfo: true # 开启 Git 信息功能(关键)
sitemap:
changefreq: "daily"
filename: "sitemap.xml"
priority: 0.5
frontmatter:
# 告诉 Hugo:文章的“最后修改时间”优先读取 Git 提交时间
lastmod:
- ":git"
- "lastmod"
- "date"
- "publishDate"
同时还需要修改推送的文件,我把代码放在最后了,替换 Python 脚本 (baidu_push.py)。
由于脚本加入了 pytz 库,还需要安装依赖:pip install pytz
最后运行 hogo ,等明天再提交一次。
import requests
import xml.etree.ElementTree as ET
import os
from datetime import datetime, timedelta
import pytz # 需要安装:pip install pytz
# ================= 配置区域 =================
# 1. 您的网站域名 (不带斜杠)
SITE_URL = 'https://huoshantiepifengdou.com'
# 2. 您的百度 Token
BAIDU_TOKEN = '请填入您的百度Token'
# 3. Sitemap 文件路径
SITEMAP_FILE = 'public/sitemap.xml'
# 4. 筛选最近 N 天的文章 (建议设为 3 或 7)
DAYS_WINDOW = 3
# ===========================================
def parse_date(date_str):
"""解析 Sitemap 中的时间字符串 (处理时区)"""
try:
# 处理 Hugo 生成的类似 "2026-01-20T10:00:00+08:00" 格式
return datetime.fromisoformat(date_str)
except ValueError:
try:
# 备用格式处理
return datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%S%z")
except:
return None
def get_recent_urls(file_path):
"""从 Sitemap 中提取最近更新的 URL"""
if not os.path.exists(file_path):
print(f"❌ 错误:找不到文件 {file_path}")
return []
urls_to_push = []
# 获取当前时间 (带时区,假设是 UTC+8 或系统本地时间)
now = datetime.now().astimezone()
# 计算截止时间
cutoff_date = now - timedelta(days=DAYS_WINDOW)
try:
tree = ET.parse(file_path)
root = tree.getroot()
namespace = {'ns': 'http://www.sitemaps.org/schemas/sitemap/0.9'}
print(f"🔍 正在筛选 {cutoff_date.date()} 之后更新的文章...")
for url in root.findall('ns:url', namespace):
loc = url.find('ns:loc', namespace).text
lastmod_node = url.find('ns:lastmod', namespace)
should_push = False
# 如果有最后修改时间,判断是否在最近 N 天内
if lastmod_node is not None and lastmod_node.text:
mod_date = parse_date(lastmod_node.text)
if mod_date and mod_date > cutoff_date:
should_push = True
print(f" [新] {mod_date.date()} - {loc}")
else:
# 如果没有时间标签,默认不推,或者您可以改为 True 强制推
pass
if should_push and loc:
urls_to_push.append(loc)
return urls_to_push
except Exception as e:
print(f"❌ 解析 Sitemap 失败: {e}")
return []
def push_to_baidu(urls):
"""推送逻辑"""
if not urls:
print("⚠️ 没有发现最近更新的文章,跳过推送。")
return
print(f"⚡️ 准备推送 {len(urls)} 条链接...")
api_url = f'http://data.zz.baidu.com/urls?site={SITE_URL}&token={BAIDU_TOKEN}'
headers = {
'User-Agent': 'curl/7.12.1',
'Content-Type': 'text/plain'
}
try:
response = requests.post(api_url, headers=headers, data='\n'.join(urls))
result = response.json()
print("\n🚀 百度反馈结果:")
if 'success' in result:
print(f"🎉 成功推送: {result['success']} 条")
print(f"📅 今日剩余配额: {result['remain']}")
else:
print(f"⚠️ 推送失败: {result}")
except Exception as e:
print(f"❌ 网络请求失败: {e}")
if __name__ == '__main__':
print("--- 百度 SEO 智能增量推送 ---")
target_urls = get_recent_urls(SITEMAP_FILE)
if target_urls:
push_to_baidu(target_urls)
print("--- 执行完毕 ---")