用 Hermes 自动写博客、发博客:原理、脚本和完整流程
什么是 Hermes
Hermes 是一个 AI 代理框架,可以通过飞书、Telegram、微信等平台跟你对话。它能操作终端、编辑文件、控制浏览器,甚至派出子代理并行工作。
今天我想说的是它的一个用法:自动写博客、发博客。
原理:Typecho 的 XML-RPC 接口
Typecho 自带一个 XML-RPC 接口,地址是 /index.php/action/xmlrpc。这个接口遵循 MetaWeblog 协议,支持以下操作:
| 方法 | 功能 |
|---|---|
metaWeblog.newPost | 发布文章 |
metaWeblog.editPost | 编辑文章 |
metaWeblog.deletePost | 删除文章 |
metaWeblog.getRecentPosts | 获取最近文章 |
metaWeblog.newMediaObject | 上传图片/文件 |
metaWeblog.getCategories | 获取分类列表 |
Python 标准库里自带 xmlrpc.client,不需要安装任何第三方库,几行代码就能调用。
核心代码
发布一篇文章只需要三步:
1. 连接服务器
import xmlrpc.client
server = xmlrpc.client.ServerProxy('https://你的博客/index.php/action/xmlrpc')2. 上传图片(可选)
with open('image.png', 'rb') as f:
data = xmlrpc.client.Binary(f.read())
media = {'name': 'image.png', 'type': 'image/png', 'bits': data}
result = server.metaWeblog.newMediaObject(1, '用户名', '密码', media)
print(result['url']) # 返回图片地址3. 发布文章
post = {
'title': '文章标题',
'description': '文章内容(Markdown 或 HTML)',
'categories': ['默认分类'],
'mt_keywords': '标签1,标签2',
}
post_id = server.metaWeblog.newPost(1, '用户名', '密码', post, True)第四个参数 True 表示立即发布,False 表示存为草稿。
完整脚本
以下是脱敏后的完整脚本,把顶部三个配置项改成你自己的就能用:
#!/usr/bin/env python3
# Typecho 博客自动发文章脚本 (XML-RPC)
#
# 用法:
# python3 typecho-post.py --title "标题" --content "内容" [--category "分类"] [--tags "标签"] [--draft]
# python3 typecho-post.py --list
# python3 typecho-post.py --delete <文章ID>
# python3 typecho-post.py --edit <文章ID> --title "新标题"
# python3 typecho-post.py --upload <文件路径>
import xmlrpc.client
import argparse
import os
BLOG_URL = 'https://你的博客/index.php/action/xmlrpc'
BLOG_ID = 1
USERNAME = '你的用户名'
PASSWORD = '你的密码'
def get_server():
return xmlrpc.client.ServerProxy(BLOG_URL)
def post_article(title, content, category=None, tags=None, draft=False):
server = get_server()
post = {'title': title, 'description': content}
if category:
post['categories'] = [category]
if tags:
post['mt_keywords'] = tags
publish = not draft
post_id = server.metaWeblog.newPost(BLOG_ID, USERNAME, PASSWORD, post, publish)
status = "草稿" if draft else "已发布"
print(f"成功! ID: {post_id}")
return post_id
def list_posts(number=10):
server = get_server()
posts = server.metaWeblog.getRecentPosts(BLOG_ID, USERNAME, PASSWORD, number)
for p in posts:
print(f" [{p['postid']}] {p['title']}")
def edit_post(cid, title=None, content=None):
server = get_server()
post = server.metaWeblog.getPost(cid, USERNAME, PASSWORD)
if title: post['title'] = title
if content: post['description'] = content
server.metaWeblog.editPost(cid, USERNAME, PASSWORD, post, True)
print(f"编辑成功! ID: {cid}")
def delete_post(cid):
server = get_server()
server.blogger.deletePost('', cid, USERNAME, PASSWORD, True)
print(f"删除成功! ID: {cid}")
def upload_media(file_path):
server = get_server()
with open(file_path, 'rb') as f:
data = xmlrpc.client.Binary(f.read())
ext = os.path.splitext(file_path)[1].lower()
mime = {'.jpg':'image/jpeg','.png':'image/png','.gif':'image/gif',
'.webp':'image/webp','.mp4':'video/mp4'}.get(ext, 'application/octet-stream')
media = {'name': os.path.basename(file_path), 'type': mime, 'bits': data}
result = server.metaWeblog.newMediaObject(BLOG_ID, USERNAME, PASSWORD, media)
print(f"上传成功: {result['url']}")
return result['url']
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--title', '-t')
parser.add_argument('--content', '-c')
parser.add_argument('--category')
parser.add_argument('--tags')
parser.add_argument('--draft', '-d', action='store_true')
parser.add_argument('--list', '-l', action='store_true')
parser.add_argument('--number', '-n', type=int, default=10)
parser.add_argument('--edit', '-e', type=int)
parser.add_argument('--delete', type=int)
parser.add_argument('--upload', '-u')
args = parser.parse_args()
if args.list:
list_posts(args.number)
elif args.delete:
delete_post(args.delete)
elif args.edit:
edit_post(args.edit, title=args.title, content=args.content)
elif args.upload:
upload_media(args.upload)
elif args.title and args.content:
post_article(args.title, args.content, args.category, args.tags, args.draft)
else:
parser.print_help()
if __name__ == '__main__':
main()和 Hermes 配合的用法
脚本只是工具,Hermes 做的是把整个流程自动化:
- 你:说"帮我发一篇关于 XXX 的博客"
- Hermes:回顾上下文、撰写文章内容
- Hermes:用浏览器自动截图作为配图
- Hermes:调用脚本上传图片,拿到 URL
- Hermes:调用脚本发布文章,返回链接给你
全程不需要你打开浏览器、登录后台、手动操作任何东西。这篇文章就是这么发出来的。
注意事项
- 图片上传用
metaWeblog.newMediaObject,不要用wp.newMediaObject,Typecho 不支持后者 - 文章内容格式取决于后台设置:开启了 Markdown 解析就传 Markdown,否则传 HTML
- 密码明文写在脚本里,注意文件权限(
chmod 600),别提交到公开仓库 - XML-RPC 接口默认开启,如果关了可以在 Typecho 后台或源码中重新启用
本文由 Hermes Agent 自动撰写、截图、上传图片并发布。