老Q的自动化之路

分享QClaw使用心得、自动化运营技巧、副业盈利方案。从0开始,记录一个普通人用AI工具赚钱的真实过程。

老Q的自动化之路

分享QClaw使用心得、自动化运营技巧、副业盈利方案。从0开始,记录一个普通人用AI工具赚钱的真实过程。

Python + WordPress XML-RPC 自动发文章:完整实操记录、踩坑与效果

为什么选 XML-RPC 而不是 REST API

先说结论:WordPress 有两套接口可以远程发文,REST API 和 XML-RPC。很多人第一反应是用 REST API,毕竟 JSON 格式看着舒服,文档也多。但我实际试了一圈下来,XML-RPC 更适合自动发文章这个场景。

原因很简单:

1. REST API 需要搞 Application Passwords,WordPress 5.6 以后才原生支持,而且有些主机环境会拦截 REST 请求

2. XML-RPC 是 WordPress 老牌接口,几乎所有版本都支持,开箱即用

3. 用 Python 的 python-wordpress-xmlrpc 库,几行代码就能发文章,比 REST API 少写一半代码

4. 批量操作时 XML-RPC 更稳定,不容易被安全插件拦截

有人说 XML-RPC 不安全,容易被打暴力破解。这个确实要注意,后面会说我怎么处理的。

环境准备

我用的是腾讯云轻量应用服务器,2核2G,装了宝塔面板 + WordPress。服务器选腾讯云主要是因为便宜,新用户一年几十块钱就能搞一台,而且备案流程也方便。

如果你还没有服务器,可以先领个优惠券:https://curl.qcloud.com/7Znu7m7b

Python 环境

# 装 python-wordpress-xmlrpc 库
pip install python-wordpress-xmlrpc

这个库是官方推荐的 XML-RPC Python 客户端,封装得很好,不需要自己拼 XML。

确认 XML-RPC 已开启

WordPress 默认是开启 XML-RPC 的,但有些安全插件会把它关掉。访问你的站点:

https://你的域名/xmlrpc.php

如果返回 “XML-RPC server accepts POST requests only.”,说明是开着的。如果返回 403 或 404,那可能是被安全插件拦了,去插件设置里放行。

完整代码:自动发一篇文章

from wordpress_xmlrpc import Client, WordPressPost
from wordpress_xmlrpc.methods.posts import NewPost

连接 WordPress

wp = Client('https://你的域名/xmlrpc.php', '用户名', '密码')

创建文章

post = WordPressPost() post.title = '测试文章标题' post.content = '<p>这是文章内容,支持 HTML 标签</p>' post.post_status = 'publish' # 直接发布,改成 draft 就是草稿

设置分类(用分类 ID,别用名称)

post.terms = [{'id': 6}] # 6 是"自动化运营"分类的 ID

发布

post_id = wp.call(NewPost(post)) print(f'发布成功!文章 ID: {post_id}')

就这么多代码,是不是比想象中简单?

批量发文:从 1 篇到 100 篇

单个发文没啥技术含量,批量发文才是真正要折腾的。我的需求是一次发几十篇文章,还不能被服务器判定为攻击。

批量发布脚本

import time
from wordpress_xmlrpc import Client, WordPressPost
from wordpress_xmlrpc.methods.posts import NewPost

wp = Client('https://你的域名/xmlrpc.php', '用户名', '密码')

articles = [
    {'title': '文章1标题', 'content': '文章1内容', 'category_id': 6},
    {'title': '文章2标题', 'content': '文章2内容', 'category_id': 6},
    # ... 更多文章
]

success_count = 0
fail_count = 0

for i, article in enumerate(articles):
    try:
        post = WordPressPost()
        post.title = article['title']
        post.content = article['content']
        post.post_status = 'publish'
        post.terms = [{'id': article['category_id']}]

        post_id = wp.call(NewPost(post))
        print(f'[{i+1}/{len(articles)}] 发布成功: ID {post_id} - {article["title"]}')
        success_count += 1

        # 每篇间隔 3-5 秒,别太快
        time.sleep(3 + (i % 3))

    except Exception as e:
        print(f'[{i+1}/{len(articles)}] 发布失败: {article["title"]} - {str(e)}')
        fail_count += 1
        # 失败后等久一点再试
        time.sleep(10)

print(f'\n发布完成!成功 {success_count} 篇,失败 {fail_count} 篇')

几个关键点:

1. 每篇之间加 3-5 秒间隔,随机化一下,避免触发限流

2. 失败后等 10 秒再继续,别硬冲

3. 记录成功和失败数量,方便事后检查

踩过的坑

坑1:分类用名称字符串,结果文章全没分类

刚开始我用的是 terms_names 传分类名称:

# 错误写法
post.terms_names = {'category': ['自动化运营']}

结果文章发出来了,但分类全是”未分类”。排查了半天才搞明白,terms_names 在某些 WordPress 版本下有 bug,中文分类名会识别失败。

正确做法是用 terms + 分类 ID:

# 正确写法
post.terms = [{'id': 6}]

怎么查分类 ID?用 XML-RPC 的 wp.getTerms 方法:

from wordpress_xmlrpc.methods.taxonomies import GetTerms
terms = wp.call(GetTerms('category'))
for t in terms:
    print(f'ID: {t.id} | 名称: {t.name}')

坑2:SSL 证书验证报错

腾讯云装的免费 SSL 证书,Python 默认会验证证书链,偶尔会报 SSL 验证失败。解决办法:

import ssl

创建不验证 SSL 的上下文(仅开发环境用,生产环境建议修复证书)

ssl_context = ssl.create_default_context() ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE

Client 初始化时传入

注意:python-wordpress-xmlrpc 底层用 xmlrpc.client,需要这样处理

import xmlrpc.client transport = xmlrpc.client.SafeTransport(context=ssl_context)

然后用底层方式连接

或者更简单的方式,直接用 Node.js 的 https 模块发 XML-RPC 请求(对,我后来转 Node.js 了,Python 的 SSL 处理太折腾)。

坑3:PowerShell 执行 Node.js 代码时特殊字符炸了

在 Windows 上用 PowerShell 执行 node -e "..." 的方式跑 JS 代码,XML 里的 < > & 引号等字符会被 PowerShell 先解析一遍,然后 Node.js 收到的就是残缺的代码。

解决办法:别用 -e 参数了,把 JS 代码写成 .js 文件再执行:

# 错误:PowerShell 会破坏特殊字符
node -e "const xml = '<?xml version=\"1.0\"?>...'"

正确:写文件再执行

node publish_article.js

这个坑浪费了我好几个小时。

坑4:单引号导致 Python 语法错误

文章内容里有 Let's Encrypt 这种带撇号的字符串,如果用单引号包裹:

content = 'SSL证书:免费Let's Encrypt'  # 语法错误!

Python 会把 Let' 后面的 s Encrypt' 当成语法错误。必须用双引号或转义:

content = "SSL证书:免费Let's Encrypt"  # 用双引号
content = 'SSL证书:免费Let\'s Encrypt'  # 或转义

这种小问题很难排查,因为报错行号不一定准确。

坑5:批量发 100 篇导致文章无分类

有一次批量发了 100 篇文章,全部用的 terms_names,结果所有文章都归到了"未分类"。后来不得不写脚本批量修改分类,又折腾了半天。

教训就是:永远用 terms + 分类 ID,别图省事用 terms_names

实际效果

我用这套方案跑了一个多月,说说真实数据:

  • 批量发文速度:每分钟大约 15-20 篇(加了间隔保护)
  • 成功率:99% 以上,偶尔网络波动会失败一篇
  • 单篇文章发布耗时:0.5-2 秒
  • 对服务器压力:2 核 2G 轻量应用服务器完全扛得住

相比手动在 WordPress 后台一篇篇发,效率提升了至少 50 倍。以前发 50 篇文章要点一整个下午,现在脚本跑 3 分钟搞定。

还有一个意想不到的好处:因为发文节奏稳定(每天定时发 2-3 篇),搜索引擎抓取频率明显提高了。之前一周来一次的百度蜘蛛,现在隔天就来。

Node.js 版本(补充)

后来我主要用 Node.js 做自动发布了,因为 Python 的 SSL 和编码问题在 Windows 上太闹心。Node.js 用 https 模块直接发 XML-RPC 请求,简单粗暴但管用:

const https = require('https');

function publishPost(title, contentHtml, categoryId) {
  const xml = <?xml version="1.0" encoding="UTF-8"?>
  <methodCall>
    <methodName>wp.newPost</methodName>
    <params>
      <param><value><int>1</int></value></param>
      <param><value><string>你的用户名</string></value></param>
      <param><value><string>你的密码</string></value></param>
      <param><value><struct>
        <member><name>post_title</name><value><string>${escapeXml(title)}</string></value></member>
        <member><name>post_content</name><value><string>${escapeXml(contentHtml)}</string></value></member>
        <member><name>post_status</name><value><string>publish</string></value></member>
        <member><name>terms</name><value><array><data>
          <value><struct>
            <member><name>taxonomy</name><value><string>category</string></value></member>
            <member><name>id</name><value><int>${categoryId}</int></value></member>
          </struct></value>
        </data></array></value></member>
      </struct></value></param>
    </params>
  </methodCall>;

  return new Promise((resolve, reject) => {
    const req = https.request({
      hostname: '你的域名',
      path: '/xmlrpc.php',
      method: 'POST',
      headers: { 'Content-Type': 'text/xml', 'Content-Length': Buffer.byteLength(xml) }
    }, res => {
      let body = '';
      res.on('data', c => body += c);
      res.on('end', () => {
        const idMatch = body.match(/<name>post_id<\/name>.*?<value>(?:<string>)?(\d+)/);
        if (idMatch) resolve(idMatch[1]);
        else reject(new Error('发布失败: ' + body.substring(0, 200)));
      });
    });
    req.on('error', reject);
    req.write(xml);
    req.end();
  });
}

function escapeXml(str) {
  return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

// 使用
publishPost('测试文章', '<p>这是内容</p>', 6).then(id => console.log('发布成功: ' + id));

Node.js 版本不需要额外装库,直接用内置的 https 模块,而且不用折腾 SSL 证书问题。

安全建议

XML-RPC 确实容易被暴力破解攻击,建议做好防护:

1. 在 Nginx 层面限制 xmlrpc.php 的访问频率

2. 使用强密码(16位以上,含特殊字符)

3. 如果不需要离线发布(如 Windows Live Writer),可以只允许特定 IP 访问 xmlrpc.php

4. 定期检查访问日志,看有没有异常的批量请求

Nginx 限流配置示例:

# 在 http 块中
limit_req_zone $binary_remote_addr zone=xmlrpc:10m rate=30r/m;

在 server 块中

location /xmlrpc.php { limit_req zone=xmlrpc burst=5 nodelay; fastcgi_pass unix:/tmp/php-cgi.sock; # ... 其他 fastcgi 配置 }

这样每分钟最多 30 次请求,正常发文绰绰有余,暴力破解就很难了。

最后

自动发文这事儿,上手不难,但细节真的多。从选接口到处理编码,从 SSL 到批量限流,每一步都可能踩坑。我花了一周时间才把整个流程跑通,希望这篇文章能帮你少走点弯路。

如果你还没买服务器,这里有个腾讯云优惠链接:https://curl.qcloud.com/7Znu7m7b ,新用户价格很划算,我自己的站就是跑在腾讯云上的。

有问题可以留言,我会回复的。关注我,后面还会分享更多自动化运营的实操经验。

Python + WordPress XML-RPC 自动发文章:完整实操记录、踩坑与效果
Scroll to top