CodeArts Agent实战:API直调发布华为云博客的踩坑与修复
CodeArts Agent实战:API直调发布华为云博客的踩坑与修复
本文记录了使用华为云码道(CodeArts)代码智能体,通过 Playwright 浏览器自动化 + API 逆向分析,实现博客自动发布的完整过程。详细记录了从 UI 自动化到 API 直调的演进中遇到的 6 个关键问题及修复方案。
背景
在上一篇博客 [用 AI Agent 自动发布华为云博客:从踩坑到成功的完整实战](https://bbs.huaweicloud.cn/blogs/481268) 中,我们实现了基于 Playwright UI 自动化 + 后端 API 直调的博客发布方案。
但在后续的实践中,将这篇博客整理成 Markdown 后再次发布时,遇到了新的问题——UI 自动化踩过的坑在 API 直调时又换了一种形式出现。本文记录了再次踩坑与修复的完整过程。
整体流程
用户登录 → CSRF Token获取 → Markdown转HTML → 构造请求体 → 调用API发布
踩坑记录
坑1:TinyMCE 内容注入后发表按钮仍然禁用
问题: 使用 tinyMCE.activeEditor.setContent() 注入 Markdown 内容后,#submit-btn 按钮始终带有 write-blog-publish-btn-no 禁用样式类,无法点击。
原因: 华为云博客编辑器的前端验证逻辑无法感知通过 TinyMCE API 设置的内容和标签。编辑器内部维护了一套独立的状态管理,直接操作 DOM 无法触发验证状态更新。
尝试过的方案:
- 手动移除禁用 CSS 类 → 按钮可点击但不触发提交
- 触发
change、input事件 → 无效 - 调用
tinyMCE.activeEditor.save()→ 无效
最终方案: 放弃前端 UI 交互,改为直接调用后端发布 API。这是最彻底的解决方案。
坑2:Markdown 格式错乱
问题: 将 Markdown 原文直接传入 TinyMCE 后,代码块显示为单反引号、列表未格式化、表格显示为纯文本、标题未渲染。
原因: TinyMCE 接收的是 HTML 而非 Markdown。直接传递 bold 和 ## Title 这类 Markdown 语法,编辑器不会自动转换。
修复: 编写完整的 Markdown → HTML 解析器,逐行解析:
标题 (# → <h1-6>)
代码块 (``` → <pre><code>)
表格 (| → <table><th><td>)
列表 (-/1. → <ul>/<ol><li>)
引用 (> → <blockquote>)
行内格式 (** → <strong>, ` → <code>)
分隔线 (--- → <hr>)
链接/图片 ([text](url) → <a>/<img>)
特别注意 Windows \r\n 换行符问题:split('\n') 后每行末尾残留 \r,导致标题正则 /^(#{1,6})\s+(.+)$/ 中的 $ 无法匹配。需在解析前统一处理:
const lines = md.replace(/\r\n/g, '\n').replace(/\r/g, '').split('\n');
坑3:API 域名错误导致 404
问题: 调用发布 API 返回 404。
POST https://bbs.huaweicloud.cn/rest/developer/fwdu/... → 404
原因: 登录后的页面域名为 bbs.huaweicloud.cn,但博客发布 API 的服务端点在 devdata.huaweicloud.cn 域名下。两个域名指向不同的后端服务。
修复: 将 API 请求域名硬编码为 https://devdata.huaweicloud.cn:
正: https://devdata.huaweicloud.cn/rest/developer/fwdu/... → 200
误: https://bbs.huaweicloud.cn/rest/developer/fwdu/... → 404
坑4:CSRF Token 缺失导致 403
问题: 域名修正后,API 返回 403。
{"error":"no request_csrf found"}
原因: 华为云的 API 要求在请求头中携带 CSRF Token,用于防跨站请求伪造。初始脚本未携带任何 CSRF 信息。
修复: 从浏览器 Cookie 中提取 CSRF Token:
const cookies = await context.cookies();
const csrfCookie = cookies.find(c =>
c.name === 'csrf' || c.name === 'hd-csrf');
const csrfToken = csrfCookie ? csrfCookie.value : '';
然后将 Token 放入请求头:
headers: {
'Content-Type': 'application/json',
'csrf': csrfToken,
}
关键细节: Cookie 的名称是 hd-csrf,但请求头的字段名是 csrf(不是 hd-csrf)。使用错误的 header 名称同样会返回 no request_csrf found。
坑5:API 请求体字段名
问题: 构造请求体时,直观地使用 title、content、label 作为字段名,但 API 返回错误。
修复: 通过逆向分析前端 JS 源码 window.saveBlog.toString(),找到正确的字段名映射:
| 前端显示 | API 字段名 |
|---|---|
| 标题 | titleData |
| 正文 HTML | contentData |
| 摘要 | introData |
| 标签 | tagNameData |
| 是否锁定 | isLock: 0 |
| 是否原创 | isOriginal: 1 |
| 资源来源 | blogResource: 1 |
| 允许转载 | isReship: 1 |
坑6:浏览器登录等待超时
问题: page.waitForURL() 等待登录跳转时,如果登录后页面 URL 未按预期变化,会抛出 Timeout 异常。
修复: 改用轮询机制,同时检查 URL 变化和 DOM 元素存在:
for (let attempt = 0; attempt < 120; attempt++) {
const u = page.url();
// 检查 URL 是否已离开登录页
if (!u.includes('login') && !u.includes('passport')) {
loggedIn = true; break;
}
// 同时检查编辑器元素是否出现
const hasEditor = await page.evaluate(() =>
!!document.querySelector('#blogTitle'));
if (hasEditor) { loggedIn = true; break; }
await sleep(2000);
}
最终方案
完整的自动发布流程如下:
步骤
- Playwright 启动 Edge 浏览器,导航到博客发布页
- 用户手动登录华为云账号
- 提取 CSRF Token(从
hd-csrfCookie) - Markdown → HTML 转换(逐行解析,支持完整语法)
- 构造请求体(使用正确的 API 字段名
titleData/contentData/introData/tagNameData) - 发送 POST 请求到
https://devdata.huaweicloud.cn/rest/developer/fwdu/rest/developer/user/hdblogservice/v1/blog/blogging - 解析响应,提取
blogId,验证发布结果
核心代码
const submitData = {
titleData: title,
contentData: contentHtml,
introData: introText.substring(0, 200),
tagNameData: 'AI Agent,华为云,大模型',
isLock: 0,
blogResource: 1,
isReship: 1,
disclaimerFlag: 1,
blogType: 0,
isOriginal: 1,
source: 1,
};
const resp = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'csrf': csrfToken,
},
body: JSON.stringify(submitData),
credentials: 'include',
});
成功响应
{
"code": "HD.92300000",
"msg": "success",
"blogId": "9fbb669737044bbd983572ce6d9b2025"
}
经验总结
- UI 自动化有上限:当组件内部状态与 DOM 不同步时,直接操作 DOM 往往无效。此时应转向 API 层面。
- Cookie 名 ≠ Header 名:CSRF 的 Cookie 名为
hd-csrf,但 HTTP Header 名为csrf。两者不同,需要仔细区分。 - API 域名可能不同于页面域名:
bbs.huaweicloud.cn是前端展示域,devdata.huaweicloud.cn是后端 API 域。 - 逆向 JS 源码:通过
function.toString()或搜索页面内嵌脚本,可以快速定位 API 端点、字段名和参数格式。 - Windows 换行符坑:
\r\n会导致 Markdown 解析器的正则失效,务必先统一换行符。 - Markdown 转 HTML 需要逐行解析:简单的正则替换无法正确处理多层嵌套结构(如代码块内的 Markdown 语法)。
完整代码
完整脚本已开源在项目目录:
- C:\Users\33808\IDEProjects\hermestest1\publish-api.mjs — API 直调版
- C:\Users\33808\IDEProjects\hermestest1\playwright-publish.mjs — UI 自动化版
运行方式:
cd C:\Users\33808\IDEProjects\hermestest1
npm run api # API 直调版(推荐)
npm run agent # UI 自动化版
总结
从最初的 Playwright UI 自动化,到最终的后端 API 直调,这个过程展示了当前端自动化遇到瓶颈时,如何通过 API 逆向分析找到根本解决方案。6 个坑涵盖了域名、认证、数据格式、状态同步等多个维度,是 Web 自动化实战的典型案例。
最终实现的 API 直调方案稳定可靠,无需处理 UI 状态同步问题,是博客自动发布的推荐方式。
*本文由 CodeArts Agent 协助撰写并自动发布到华为云社区。* *发布时间:2026年7月8日*
- 点赞
- 收藏
- 关注作者
评论(0)