with one click
gzh-publisher
微信公众号统一发布技能:通过 OpenClaw Browser 自动化完成登录、写文章、一键排版、封面、存草稿。
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
微信公众号统一发布技能:通过 OpenClaw Browser 自动化完成登录、写文章、一键排版、封面、存草稿。
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
霸下销售总监大师技能包 — 全球顶尖B2B销售能力。对标华为铁三角+Salesforce+麦肯锡谈判法。
墨白首席美学官大师技能包 — 全球顶级视觉战略能力。对标伦敦皇家艺术学院 + 奥美全球 + 苹果Jony Ive设计标准。
轩辕AI编码舰队——OpenClaw作为大脑,指挥Claude Code/Cursor/Windsurf/Trae/Codex CLI集群并行开发。覆盖:ACP配置、IDE接入、权限管理、任务分发、windsurf+cursor双IDE调度、worktree隔离、舰队看板。触发词:IDE舰队、编码集群、AI IDE、多工具编排、ACP配置、Cursor舰队、Windsurf集群、Trae接入、IDE调度、并行编码、AI编码引擎、IDE编排、coding fleet
项目进度追踪与SDLC全周期管理——ETA承诺、实时看板、风险预警、多项目并行调度。覆盖:任务拆解协议、ETA估算模型、进度追踪机制、日报/周报模板、风险预警系统、承诺驱动开发。触发词:项目进度、SDLC、ETA、甘特图、看板、燃尽图、里程碑、进度追踪、project management、进度汇报、阻塞告警
2025年最前沿的AI原生开发范式——VibeCoding。覆盖:Prompt-to-Product工作流、多轮对话管理、AI编码助手协作策略、代码质量保障、v0.dev/Lovable/Claude Code/Replit Agent工具链集成。触发词:vibecoding、VibeCoding、AI原生开发、提示即产品、AI pair programming、conversation-driven coding、prompt engineering for products
飞书云文档内容优化与格式美化。当用户需要优化飞书文档的排版、结构、格式、美观度时使用此技能。支持:(1) 读取飞书文档内容 (2) 优化文档结构和层次 (3) 清空并替换文档内容 (4) 通过浏览器自动化编辑文档。触发词:优化飞书文档、美化文档、整理文档格式、文档排版。
| name | gzh-publisher |
| description | 微信公众号统一发布技能:通过 OpenClaw Browser 自动化完成登录、写文章、一键排版、封面、存草稿。 |
| metadata | {"version":"3.2.0","author":"Daniel Li","domains":["content","publishing","automation","wechat"],"type":"automation"} |
唯一官方微信公众号发布方式。基于 OpenClaw Browser 自动化。
# 推荐:自动扫描 gzh/ 目录图片
python3 scripts/publish.py --article gzh/article.md --author "Daniel"
# 跳过一键排版
python3 scripts/publish.py --article gzh/article.md --author "Daniel" --no-format
# 跳过封面
python3 scripts/publish.py --article gzh/article.md --author "Daniel" --no-cover
需要 OpenClaw Browser 运行中(openclaw browser start)。
📋 发布前确认内容合规:
~/clawd/projects/MediaClaw/references/platforms/weixin-mp.md
┌─────────────────────────────────────────────────────┐
│ Step 1: 检查登录状态 │
│ browser → navigate(mp.weixin.qq.com) │
├─────────────────────────────────────────────────────┤
│ Step 2: 新建文章(新标签页 appmsg_edit) │
├─────────────────────────────────────────────────────┤
│ Step 3: 填标题(JS evaluate, textarea) │
├─────────────────────────────────────────────────────┤
│ Step 4: 填作者(JS evaluate, input) │
├─────────────────────────────────────────────────────┤
│ Step 5: 粘贴素材图片(clipboard + Ctrl+V) │
│ → 每张等8秒 CDN 转换 → 收集 mmbiz URL │
├─────────────────────────────────────────────────────┤
│ Step 6: 设封面「从正文选择」← 必须在 HTML 注入前! │
├─────────────────────────────────────────────────────┤
│ Step 7: 注入正文 HTML(CDP WebSocket, 含 CDN 图片) │
├─────────────────────────────────────────────────────┤
│ Step 8: 一键排版(新标签页 articlestruct) │
│ → 点"使用此排版" → 图片不会丢失 ✅ │
├─────────────────────────────────────────────────────┤
│ Step 9: 保存草稿 │
└─────────────────────────────────────────────────────┘
innerHTML 注入 <img> → 图片不加载DOM.setFileInputFiles → 上传但不插入编辑器browser upload → 同上Type not supportedarticlestruct,需切换 targetId 后点"使用此排版"fill() 在微信 textarea 上会超时ta.value = ... + dispatchEvent('input') via browser evaluateevaluate 的 fn 有字符长度限制,>2000字会被截断/tmp/wechat-article.html → CDP WebSocket Runtime.evaluate 注入browser(action="navigate", profile="openclaw", url="https://mp.weixin.qq.com")
browser(action="snapshot", profile="openclaw")
// 点"新的创作"
browser(action="act", kind="evaluate", fn="""
() => {
const h2s = document.querySelectorAll('h2');
for (const h of h2s) {
if (h.textContent.trim() === '新的创作') { h.click(); return 'clicked'; }
}
}
""")
// 等1秒 → 点"文章"(y>300 的第一个文本="文章"的元素)
// 等待6秒 → 用 tabs 找 appmsg_edit 标签页
browser(action="tabs", profile="openclaw")
browser(action="act", kind="evaluate", targetId=编辑器, fn="""
() => {
const ta = document.querySelector('textarea[placeholder*="标题"]');
ta.focus(); ta.value = '文章标题';
ta.dispatchEvent(new Event('input', {bubbles:true}));
return 'filled: ' + ta.value;
}
""")
browser(action="act", kind="evaluate", targetId=编辑器, fn="""
() => {
const inp = document.querySelector('input[placeholder*="作者"]');
inp.focus(); inp.value = 'Daniel';
inp.dispatchEvent(new Event('input', {bubbles:true}));
return 'filled';
}
""")
必须用 CDP WebSocket 方式(browser 工具的 evaluate 传 base64 太大):
# 写成独立脚本 /tmp/paste_images.py,exec 运行
import asyncio, json, base64, httpx, websockets, os
async def paste_all(images, target_id):
async with httpx.AsyncClient() as c:
r = await c.get("http://127.0.0.1:18800/json/list")
ws_url = next(t["webSocketDebuggerUrl"] for t in r.json() if target_id in t["id"])
async with websockets.connect(ws_url, max_size=50*1024*1024) as ws:
# Grant clipboard
await ws.send(json.dumps({"id":0,"method":"Browser.grantPermissions",
"params":{"permissions":["clipboard-read","clipboard-write"],"origin":"https://mp.weixin.qq.com"}}))
await ws.recv()
for img_path in images:
with open(img_path, "rb") as f:
b64 = base64.b64encode(f.read()).decode()
# Write to clipboard
await ws.send(json.dumps({"id":1,"method":"Runtime.evaluate",
"params":{"expression":f"""
(async () => {{
const b = await fetch('data:image/png;base64,{b64}').then(r=>r.blob());
await navigator.clipboard.write([new ClipboardItem({{'image/png': b}})]);
}})()
"""}}))
await ws.recv()
await asyncio.sleep(0.5)
# Focus + Ctrl+V
await ws.send(json.dumps({"id":2,"method":"Runtime.evaluate",
"params":{"expression":"document.querySelector('.ProseMirror').focus()"}}))
await ws.recv()
for ev in ["keyDown","keyUp"]:
await ws.send(json.dumps({"id":3,"method":"Input.dispatchKeyEvent",
"params":{"type":ev,"modifiers":2,"key":"v","code":"KeyV","windowsVirtualKeyCode":86}}))
await ws.recv()
await asyncio.sleep(8) # Wait for CDN conversion
JPG 必须先转 PNG(Pillow):Image.open(p).save(p.with_suffix('.png'), 'PNG')
收集 CDN URL:
browser(action="act", kind="evaluate", targetId=编辑器, fn="""
() => JSON.stringify(
Array.from(document.querySelectorAll('.ProseMirror img'))
.filter(i => i.src.includes('mmbiz')).map(i => i.src)
)
""")
⚠️ 必须在 Step 7 HTML 注入之前做!
// 1. 点"从正文选择"
browser(action="act", kind="evaluate", targetId=编辑器, fn="""
() => {
const items = document.querySelectorAll('#js_cover_description_area a, a');
for (const el of items) {
if (el.textContent.includes('从正文选择')) { el.click(); return 'clicked'; }
}
return 'not found';
}
""")
// 2. 选第一张图
browser(action="act", kind="evaluate", targetId=编辑器, fn="""
() => {
const items = document.querySelectorAll('.appmsg_content_img_item');
if (items.length > 0) { items[0].click(); return 'selected'; }
return 'empty';
}
""")
// 3. 下一步 → 确认
长 HTML 必须用 CDP(先写文件再注入):
# 1. 生成 HTML 写入文件(图片 URL 替换为 CDN)
write(path="/tmp/wechat-article.html", content=生成的HTML)
# 2. CDP 注入
python3 << 'EOF'
import json, asyncio, httpx, websockets
async def inject():
async with httpx.AsyncClient() as c:
r = await c.get("http://127.0.0.1:18800/json/list")
ws_url = next(t["webSocketDebuggerUrl"] for t in r.json() if TARGET in t["id"])
with open("/tmp/wechat-article.html") as f:
html = f.read()
async with websockets.connect(ws_url) as ws:
await ws.send(json.dumps({"id":1,"method":"Runtime.evaluate","params":{
"expression": f"(() => {{ const e = document.querySelector('.ProseMirror'); e.innerHTML = {json.dumps(html)}; e.dispatchEvent(new Event('input', {{bubbles:true}})); return 'ok'; }})()",
"returnByValue": True
}}))
print(json.loads(await ws.recv())["result"]["result"]["value"])
asyncio.run(inject())
EOF
// 1. 在编辑器页点"一键排版"
browser(action="act", kind="evaluate", targetId=编辑器, fn="""
() => {
const all = document.querySelectorAll('span, div, button, a');
for (const el of all) {
if (el.textContent.trim() === '一键排版' && el.offsetParent !== null) {
el.click(); return 'clicked';
}
}
}
""")
// 2. 等待 → 用 tabs 找 articlestruct 标签页
// 3. 在排版页点"使用此排版"
browser(action="act", kind="click", ref=使用此排版ref, targetId=排版页)
// 4. 排版自动应用,回到编辑器
browser(action="act", kind="evaluate", targetId=编辑器, fn="""
() => {
const btns = document.querySelectorAll('button');
for (const b of btns) {
if (b.textContent.includes('保存为草稿') && b.offsetParent !== null) {
b.click(); return 'clicked';
}
}
}
""")
| Markdown | HTML 样式 |
|---|---|
# H1 | 22px bold, text-align center |
## H2 | 18px bold, border-left 4px #1a73e8 |
### H3 | 16px bold |
**bold** | <strong> |
*italic* | <em> |
`code` | bg #f6f8fa, padding 2px 6px |
> quote | border-left 3px #ddd, color #666 |
 | 居中, max-width 100% |
正文段落:font-size:15px; color:#3f3f3f; line-height:1.75; margin:8px 0
输入:
article_path: string # Markdown 文章路径(必需)
author: string # 作者名(可选)
image_paths: list # 素材图片(可选,默认自动扫描 gzh/ 目录)
输出:
status: ok | error
draft_saved: true/false
appmsgid: string
title: string
images_uploaded: number
format_applied: boolean
cover_set: boolean
| Skill | 关系 |
|---|---|
wemp-operator | 全 API(统计/评论/粉丝/素材/群发) |
daily-gzh-content | 公众号内容生成 |
wechat-toolkit | 文章下载工具 |
v3.2.0 (2026-04-22): 修复图片位置bug
v3.1.0 (2026-04-18): 实战验证固化
v3.0.0 (2026-04-18): 大重写