Hugo 站长必看:百度 API 推送显示“成功0条”?原来是 localhost 在捣鬼!

作为 科技刺猬 (Keji Ciwei) 的博主,记录这个“踩坑与填坑”的过程非常有价值,不仅能复盘技术,还能为其他 Hugo 站长提供实战参考。
刺猬
问题背景:最近在折腾我的垂直站 霍山铁皮枫斗网 时,为了加快百度收录,我写了一个 Python 脚本,利用 Hugo 生成的 sitemap.xml 自动向百度站长平台推送链接。

然而,脚本运行后,出现了一个诡异的现象:终端显示 API 接口调用成功,剩余配额扣除了,但“成功推送条数”却是 0。

🚀 百度反馈结果:
🎉 成功推送: 0 条
📅 今日剩余配额: 10

明明我的 Sitemap 里有 90 多个链接,为什么百度一条都不收?

🔍 排查过程

我在脚本里加了一行 print 代码,打印出脚本到底抓取了什么链接。



真相瞬间大白:

👀 正在尝试推送的链接示例: http://localhost:1313/science/efficacy-liver-immunity/

原来,我推给百度的全是 localhost 的本地预览链接!

百度蜘蛛肯定访问不了我家里的电脑,自然全部拒收。

💡 原因分析

这是一个 Hugo 初学者(包括我)非常容易忽视的机制:

  1. 当你运行 hugo server 时:

    Hugo 会在内存中生成网站,为了方便本地调试,它会强制把 sitemap.xml 里的域名替换为 http://localhost:1313。


  2. 当你只运行 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("--- 执行完毕 ---")



发表评论