作为一个内容创作者,我长期被一个问题困扰:写完文章之后,要发博客、发头条、发公众号,三个平台格式不同、上传方式不同,每次手动操作要半小时以上。
用 OpenClaw 实现博客 · 头条 · 公众号一键三连发布:从零到全自动的完整实践,科技感横幅海报,16:9宽屏构图,简洁大气
现在,我用 OpenClaw + 几个 Node.js 脚本,把这个流程压缩到了一行命令:
node publish-all.cjs posts/2026/0319-xxx.md --all这篇文章,完整记录这套系统的设计思路、核心实现,以及踩过的所有坑。
一、整体架构
整个系统分四层:
输入层:Markdown 文章文件(含 front-matter 元数据)
处理层:
- 豆包自动配图(调用豆包网页版生图 API)
- 图床上传(CloudFlare R2 私人图床)
- Markdown 内容解析与转换
发布层:
- Git push → Vercel 自动部署(博客)
- Playwright 自动化(今日头条)
- 微信公众号草稿 API(公众号)
验证层:
- 50秒后自动访问博客 URL 验证部署
- 头条发布截图存档
- 公众号 media_id 记录
核心入口是 publish-all.cjs,它按顺序调度其他三个脚本:doubao-image.cjs(配图)、publish-wechat.cjs(公众号)、publish-toutiao.cjs(头条)。
二、技术栈
| 模块 | 技术选型 | 原因 |
|---|---|---|
| AI 助手 | OpenClaw(Claude Sonnet) | 负责写文章、调度脚本、决策 |
| 自动配图 | 豆包网页版 + Cookie 鉴权 | 免费额度充足,生图质量好 |
| 图床 | CloudFlare R2 + 自定义域名 | 免费、稳定、国内可访问 |
| 博客框架 | VitePress 1.2 + Vercel | Git push 触发自动部署 |
| 头条发布 | Playwright(headless Chromium) | Cookie 登录,全程模拟人工操作 |
| 公众号 | 微信公众号 API(草稿接口) | 自动上传图片素材 + 草稿 |
| 脚本语言 | Node.js 22(CommonJS) | 生态完整,和 Playwright 配合好 |
三、核心脚本详解
3.1 一键发布入口:publish-all.cjs
这是整个流水线的调度中心,负责按顺序执行各步骤:
// 用法示例
// 只发博客(默认)
node publish-all.cjs posts/2026/0319-xxx.md
// 全平台发布
node publish-all.cjs posts/2026/0319-xxx.md --all
// 博客 + 头条
node publish-all.cjs posts/2026/0319-xxx.md --with-toutiao
// 博客 + 公众号
node publish-all.cjs posts/2026/0319-xxx.md --with-wechat执行顺序:
- 自动配图:检测文章是否已有图片,没有则生成 1-3 张 16:9 配图
- git push:推送到 GitHub,触发 Vercel 自动部署
- 公众号草稿(可选):图片转微信内链,上传草稿
- 头条发布(可选):Playwright 自动填写并发布
3.2 自动配图:doubao-image.cjs
核心思路:根据文章标题和各章节 H2 标题生成图片描述,调用豆包生图。
// 图片描述生成逻辑(示意)
const prompts = [
`${title},科技感横幅海报,16:9宽屏构图,简洁大气`,
`${h2Titles[1]},信息图表风格,蓝色调,横幅16:9`,
`${h2Titles[3]},数据可视化风格,现代感,横幅16:9`,
];关键细节:
- 图片比例统一 16:9(宽屏横幅,适配博客和头条)
- 豆包通过 Cookie 鉴权(需要定期更新 Cookie)
- 生图完成后自动下载原图并上传到私人图床
- 上传成功后将图片 Markdown 语法插入文章对应位置
3.3 今日头条发布:publish-toutiao.cjs
头条创作平台(mp.toutiao.com)没有开放 API,只能用 Playwright 模拟浏览器操作。
完整流程:
打开创作平台
↓
检测登录状态(Cookie 鉴权)
↓
关闭 AI 助手弹窗
↓
填写标题(textarea.fill)
↓
填写正文(document.execCommand 注入)
↓
上传封面图(触发 Drawer → file input → 点确定)
↓
点击「预览并发布」
↓
点击「确认发布」
↓
完成踩坑记录:
坑1:正文输入超时
头条编辑器是 ProseMirror,逐字符输入(keyboard.type)在长文章时会超时。解决方案:用 document.execCommand('insertText') 直接注入全文,速度提升 100 倍。
await page.evaluate((text) => {
const el = document.querySelector('.ProseMirror');
el.focus();
document.execCommand('selectAll');
document.execCommand('insertText', false, text);
}, bodyText);坑2:「预览并发布」点击无反应
头条必须先上传封面图,否则点击「预览并发布」按钮毫无反应(不报错,也不跳转)。解决方案:在点击发布前,先触发封面上传 Drawer,上传图片并点「确定」。
// 触发封面上传
const coverAdd = await page.$('.article-cover-add');
await coverAdd.click();
await page.waitForTimeout(2500);
// 上传文件
const inp = await page.$('input[type=file]');
await inp.setInputFiles(tmpCoverPath);
await page.waitForTimeout(4000);
// 点「确定」(用 evaluate 直接触发,避免选择器兼容问题)
await page.evaluate(() => {
const btns = Array.from(document.querySelectorAll('button'));
const btn = btns.find(b => b.innerText.trim() === '确定' && b.offsetParent !== null);
if (btn) btn.click();
});坑3:确认发布按钮选择器
点击「预览并发布」后会跳转到预览页,确认发布按钮的选择器需要精确匹配,否则容易误触「定时发布」:
// 正确的选择器
const confirmBtn = await page.$('[class*="publish"] button[class*="primary"]');3.4 微信公众号草稿:publish-wechat.cjs
公众号使用官方 API,核心流程:
获取 access_token
↓
扫描文章内所有外链图片
↓
逐一上传到微信素材库(/cgi-bin/material/add_material)
↓
将外链替换为微信内链(mmbiz.qpic.cn)
↓
渲染 HTML(markdown-it + 内联样式)
↓
上传草稿(/cgi-bin/draft/add)
↓
返回 media_id为什么必须把图片转为微信内链?
微信公众号文章不允许外链图片显示,所有图片必须上传到微信素材库,替换为 mmbiz.qpic.cn 域名的内链,否则发布后图片一片空白。
关键限制:
- 未认证订阅号无法使用
freepublish(一次性发布)和群发接口(48001 错误) - 只能上传草稿,需要人工到后台点击发布
- 认证后可解锁全自动发布
// 图片上传到微信素材库(核心代码示意)
async function uploadImageToWechat(token, imgUrl) {
// 下载图片到本地临时文件
execSync(`curl -sL "${imgUrl}" -o ${tmpFile} --max-time 30`);
// 构造 multipart 请求上传
const form = new FormData();
form.append('media', fs.createReadStream(tmpFile));
const res = await axios.post(
`https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=${token}&type=image`,
form
);
return res.data.url; // 返回微信内链 URL
}四、配置文件结构
所有敏感配置集中在 publish-config.json(不提交到 Git):
{
"wechat": {
"appid": "YOUR_WECHAT_APPID",
"secret": "YOUR_WECHAT_SECRET",
"default_thumb": "YOUR_DEFAULT_THUMB_MEDIA_ID"
},
"toutiao": {
"cookie": "YOUR_TOUTIAO_COOKIE_STRING"
},
"imgbed": {
"url": "https://your-imgbed.example.com/upload"
}
}安全注意事项:
publish-config.json加入.gitignore,绝对不能提交到公开仓库- 豆包 Cookie 存储在独立的
.doubao-cookie.txt文件,同样 gitignore - 头条 Cookie 定期更新(一般有效期 60 天左右)
五、博客文章格式规范
博客基于 VitePress,每篇文章必须包含标准 front-matter:
---
title: 文章标题
date: 2026-03-19 10:00:00
tags: [标签1, 标签2]
categories: [AI看天下] # 必须是预设分类之一
description: 简短描述(15字左右)
articleGPT: 详细摘要(150字左右,用于公众号封面文字)
---预设分类(必须从中选一):
- 技术共享
- 生活
- 精华拾取
- AI看天下
- 个人空间
六、部署与使用流程
环境准备
# 1. 克隆博客项目
git clone https://github.com/your-username/your-blog.git
cd your-blog
# 2. 安装依赖
npm install
# 3. 安装 Playwright
npx playwright install chromium
# 4. 配置 publish-config.json(复制模板并填入真实值)
cp publish-config.example.json publish-config.json日常使用
# 写好文章后,一键全平台发布
node publish-all.cjs posts/2026/MMDD-article.md --all
# 只发博客(最常用)
node publish-all.cjs posts/2026/MMDD-article.md
# 只发博客 + 头条
node publish-all.cjs posts/2026/MMDD-article.md --with-toutiao发布完成后,脚本会输出:
- 博客访问地址
- 公众号草稿 media_id
- 头条发布状态
七、实际运行效果
目前这套系统已稳定运行,实测数据:
| 步骤 | 耗时 |
|---|---|
| 豆包生图(3张) | 约 45 秒 |
| 图片上传图床 | 约 5 秒 |
| Git push + Vercel 部署 | 约 50 秒 |
| 公众号图片上传 + 草稿 | 约 20 秒 |
| 头条 Playwright 发布 | 约 60-90 秒 |
| 总计 | 约 3-4 分钟 |
过去手动操作需要 30-60 分钟,现在一条命令 3-4 分钟搞定,节省了 90% 以上的时间。
八、常见问题
Q:豆包 Cookie 失效怎么办? A��手动登录豆包网页版,用浏览器开发者工具复制最新 Cookie,更新 .doubao-cookie.txt。
Q:头条 Cookie 失效? A��登录 mp.toutiao.com,F12 复制 Cookie,更新 publish-config.json 中的 toutiao.cookie。
Q:公众号草稿图片不显示? A��检查 publish-wechat.cjs 是否正确执行了图片转内链步骤,外链图片在公众号内无法显示。
Q:头条「预览并发布」点了没反应? A��确认封面图是否已上传并点了确定,没有封面图时该按钮被静默拦截。
九、下一步计划
- [ ] 公众号认证后接入全自动发布(无需手动点发布)
- [ ] 支持小红书平台
- [ ] 接入自定义写作风格配置
- [ ] 增加文章质量检查(字数、图片数量、格式校验)
整套方案的代码目前在个人博客仓库中维护,核心脚本不到 800 行,任何有 Node.js 基础的开发者都可以参考这个思路搭建自己的多平台发布系统。
如果你也在用 OpenClaw 做类似的事,欢迎交流。


