AI自动化发稿实战:227次操作踩9坑,浏览器自动化发布文章全流程
1. 项目缘起与整体设计思路
1.1 为什么想让 AI 自己去发稿
事情的起因很简单。我手上有一个持续在维护的技术内容账号,日常需要在腾讯云开发者社区保持更新频率。写过技术博客的人都知道,从选题、写稿、排版、配图到最终发布,一篇文章的完整链路走下来,纯手工操作少说也要一两个小时。如果遇到需要反复调整格式、上传图片、填写标签的情况,时间成本还会进一步拉高。
我当时的想法是:既然 AI 已经能帮我写稿了,那为什么不让它把“发布”这一步也一起干掉?换句话说,我希望构建一个端到端的自动化流程,让 AI 从拿到一篇成稿开始,自己打开浏览器、登录社区、进入编辑器、粘贴正文、上传封面图、填写分类标签,最后点击发布。整个过程不需要我盯着屏幕,我只需要在最后确认一下结果就行。
这个想法听起来不算复杂,但真正动手之后才发现,里面涉及的坑远比想象中多。最终这次实战跑下来,AI 一共执行了227 次操作,耗时4.3 小时,踩了9 个比较典型的坑。我把整个过程完整复盘一遍,希望能给同样在做浏览器自动化、AI Agent 操作网页的朋友一些参考。
1.2 核心关键词与涉及的技术点
这次实战涉及的核心技术点主要有这么几个:
- browser-skill:这是我用来驱动浏览器操作的核心能力模块,负责把“点击”“输入”“滚动”“截图”这些动作封装成 AI 可以调用的技能。
- bsk:这是 browser-skill 的简称,在日志和调试过程中我大量使用这个缩写来标记操作来源。
- tencent-cloud-community-publish:这是本次任务的场景标识,代表“在腾讯云开发者社区发布文章”这一具体流程。
- execCommand:这是富文本编辑器里插入内容时绕不开的一个老 API,也是本次踩坑的重灾区。
- upload:文件上传环节,涉及封面图、正文配图的处理,同样是自动化里最容易出问题的地方。
这几个关键词基本覆盖了整条链路的核心难点。下面我会按照“整体设计—核心细节—实操过程—问题排查”的顺序,把每个环节拆开讲清楚。
1.3 整体方案选型与背后的考量
在方案设计阶段,我其实面临几个选择。
第一个选择是:用纯 API 方式发布,还是用浏览器自动化方式发布?理论上如果社区提供开放的发布接口,直接调 API 是最稳的。但实际情况是,很多内容平台的发布接口并不对外开放,或者需要复杂的鉴权流程。所以我最终选择了浏览器自动化这条路——让 AI 像真人一样操作页面。这样做的好处是通用性强,不依赖平台是否开放接口;坏处是稳定性受页面结构影响大,任何一个 DOM 变化都可能导致流程失败。
第二个选择是:用现成的自动化框架,还是自己封装 browser-skill?我最终选择了自己封装。原因是我需要让 AI 能够“理解”当前页面状态,而不是机械地执行固定脚本。比如当页面加载慢的时候,AI 应该知道等待;当某个按钮找不到的时候,AI 应该尝试滚动或者换一种定位方式。这种“带判断的操作”是普通脚本很难做到的,必须把操作封装成 skill,让 AI 在每一步都能做决策。
第三个选择是:一次性跑完,还是分阶段执行?我最终选择了分阶段。因为整个流程太长,如果一次性跑,一旦中间出错,前面的操作就白费了。分阶段执行的好处是每个阶段可以单独验证、单独重试,大大降低了整体失败率。
提示:做浏览器自动化时,不要一上来就追求“全自动一把过”。先把流程拆成若干可独立验证的阶段,每个阶段跑通之后再串联,这是最省时间的做法。
2. 核心细节解析与实操要点
2.1 browser-skill 的能力边界与设计原则
browser-skill 本质上是一层封装,它把浏览器里常见的操作抽象成 AI 可以调用的函数。我设计的 skill 主要包括这几类:
- 导航类:打开指定 URL、前进、后退、刷新。
- 定位类:根据文本、CSS 选择器、XPath 找到页面元素。
- 交互类:点击、输入文本、清空输入框、选择下拉项。
- 文件类:上传文件到指定 input 元素。
- 状态类:获取页面文本、获取元素属性、截图、等待某个条件成立。
设计这些 skill 的时候,我遵循了一个原则:每个 skill 只做一件事,并且返回足够的信息让 AI 判断下一步。比如“点击”这个 skill,不仅要执行点击,还要返回点击后页面是否发生了变化、有没有弹窗出现、当前 URL 是否改变。这样 AI 才能根据返回结果决定是继续还是重试。
这里有个很容易被忽略的点:skill 的返回值设计比 skill 本身更重要。如果返回值信息不足,AI 就会“盲操作”,出错率会飙升。我在早期版本里就是因为点击 skill 只返回了“成功/失败”,导致 AI 在页面没加载完的时候误判为成功,后面一连串操作全部错位。
2.2 富文本编辑器的 execCommand 陷阱
腾讯云开发者社区的编辑器是富文本编辑器,这类编辑器最大的特点是不是一个简单的 textarea,而是一个 contenteditable 的 div。往里面插入内容,最直接的方式就是用document.execCommand('insertText', false, text)。
但 execCommand 有几个非常坑的地方:
第一,它已经被标记为废弃。虽然目前主流浏览器还支持,但行为在不同浏览器、不同版本之间可能有差异。我在测试的时候就发现,同样的代码在某个版本里能正常插入,换一个版本就插不进去。
第二,它对换行和特殊字符的处理很不稳定。普通文本还好,一旦遇到代码块、表格、有序列表这些结构,execCommand 经常会把格式搞乱。我最初尝试直接把整篇 Markdown 转成 HTML 再插入,结果编辑器把很多标签都过滤掉了,代码块直接变成了一坨纯文本。
第三,它和编辑器的内部状态可能不同步。有些富文本编辑器会在内部维护一份数据模型,execCommand 直接操作 DOM 之后,编辑器的数据模型并没有更新,导致你看着内容进去了,但一提交就发现内容是空的。
我最终的解决方案是:分段插入 + 模拟真实输入。具体来说,就是把文章按段落拆开,逐段调用 execCommand 插入,每插入一段就触发一次 input 事件,让编辑器同步状态。对于代码块这种特殊结构,我改用模拟键盘输入的方式,一个字符一个字符地敲进去,虽然慢,但稳定性高很多。
注意:execCommand 的废弃状态意味着它不是长久之计。如果平台后续升级编辑器,这套方案可能需要重写。做自动化时要对这类“依赖废弃 API”的环节保持警惕,留好备选方案。
2.3 文件上传环节的 upload 处理
文件上传是另一个重灾区。浏览器的文件上传通常依赖<input type="file">元素,但自动化工具没法直接操作系统的文件选择对话框。解决办法是绕过对话框,直接把文件路径设置到 input 元素的 files 属性上。
具体做法是:先找到页面上隐藏的 file input,然后用自动化工具提供的“设置文件”能力,把本地文件路径传进去。这一步的关键是找到正确的 input 元素。很多网站会把 file input 隐藏起来,用一个漂亮的按钮代替,你点击按钮的时候,实际上是触发了那个隐藏 input 的 click。
我在实操中遇到的坑是:页面上有多个 file input,分别对应封面图、正文配图、附件等不同用途。如果定位错了,就会出现“封面图传到了正文里”这种尴尬情况。解决办法是通过 input 的 accept 属性、name 属性或者它所在的父容器来精确定位。
另外,上传之后一定要等待上传完成的信号。有些网站上传是异步的,你设置完文件之后,图片还在后台上传,这时候如果直接点发布,图片就会丢失。我的做法是监听网络请求,或者轮询检查图片的 src 是否已经变成了真实的 CDN 地址。
3. 实操过程与核心环节实现
3.1 阶段一:登录态与页面准备
整个流程的第一步是确保登录态。我没有让 AI 去模拟输入账号密码,因为那样涉及验证码、二次验证等问题,太不稳定。我的做法是复用已有的浏览器用户数据目录,也就是让自动化浏览器加载一个已经登录过的 profile。这样打开社区页面时,直接就是登录状态。
这一步的实操要点是:启动浏览器时要指定userDataDir参数,指向一个已经手动登录过的目录。第一次使用前,我会手动打开这个浏览器登录一次,之后自动化流程就能直接复用。
页面准备阶段,AI 需要做的是:打开社区创作页面,等待编辑器加载完成。这里的判断条件是“编辑器区域出现且可编辑”。我用的检测方法是轮询检查 contenteditable 元素的 presence,同时检查页面是否有 loading 遮罩。
3.2 阶段二:正文内容的插入
正文插入是整个流程里最耗时、最容易出错的部分。我最终采用的策略是“分块处理”:
- 把文章按 Markdown 结构拆分成块:标题块、段落块、代码块、图片块、列表块。
- 对每种块类型,采用不同的插入策略。
- 每插入一块,就验证一次内容是否正确进入编辑器。
普通段落用 execCommand 插入,代码块用模拟输入,图片块先上传再插入引用。这个过程中,我记录了一个关键数据:平均每插入一个块需要 3 到 5 次操作,包括定位、插入、验证。一篇文章大概有 40 到 50 个块,所以光正文插入就消耗了 150 次左右的操作。
这里有个实操心得:插入顺序要从后往前,或者从前往后,但不要跳着插。因为富文本编辑器的光标位置很容易乱,如果你跳着插,光标可能跑到意想不到的地方,导致内容错位。我一开始就是随机插入,结果文章结构全乱了,后来改成严格顺序插入才稳定下来。
3.3 阶段三:封面图与标签填写
正文搞定之后,接下来是封面图和标签。封面图的上传相对独立,找到对应的 file input,设置文件,等待上传完成即可。标签填写则是在输入框里输入标签文字,然后从下拉建议里选中。
标签这一块有个小坑:有些标签需要精确匹配才能选中。如果你输入的标签文字和平台已有的标签不完全一致,可能创建出一个新标签,或者干脆选不上。我的做法是先把目标标签文字输入,然后等待下拉列表出现,再从列表里选择完全匹配的项。
3.4 阶段四:发布前的最终校验
在点击发布之前,我做了一次完整的校验,包括:
- 标题是否正确填入
- 正文块数量是否和预期一致
- 代码块格式是否保留
- 封面图是否上传成功
- 标签是否选中
- 分类是否选择
这个校验环节帮我避免了好几次“带病发布”。有一次就是封面图实际上传失败了,但页面上显示了一个占位图,如果不仔细检查就会误以为成功。
校验通过之后,点击发布按钮,等待跳转到文章详情页,确认文章 ID 和标题正确,整个流程才算结束。
4. 常见问题与排查技巧实录
4.1 九个坑的完整记录
这次实战踩的 9 个坑,我整理成了一张表,方便大家对照排查:
| 序号 | 问题现象 | 根本原因 | 解决方案 |
|---|---|---|---|
| 1 | 编辑器内容插入后消失 | execCommand 未触发 input 事件,编辑器状态未同步 | 每次插入后手动触发 input 事件 |
| 2 | 代码块格式丢失 | 直接插入 HTML 被编辑器过滤 | 改用模拟键盘逐字符输入 |
| 3 | 封面图传到了正文 | file input 定位错误 | 通过 accept 属性和父容器精确定位 |
| 4 | 图片上传后立即发布导致丢失 | 未等待异步上传完成 | 轮询检查图片 src 是否为 CDN 地址 |
| 5 | 标签选不上 | 输入文字与平台标签不完全匹配 | 从下拉建议中精确选择 |
| 6 | 页面加载慢导致点击无效 | 未等待元素可交互 | 增加显式等待和可交互检测 |
| 7 | 光标位置错乱 | 跳序插入内容 | 严格按顺序插入 |
| 8 | 登录态失效 | profile 过期 | 定期手动刷新登录态 |
| 9 | 发布按钮点击无反应 | 存在未填必填项 | 发布前做完整校验 |
4.2 排查思路的通用方法
遇到问题的时候,我总结了一套通用的排查思路:
第一步,截图。不管什么问题,先截图看当前页面状态。很多时候问题一眼就能看出来,比如弹了个错误提示、页面还在 loading、某个必填项是空的。
第二步,看日志。browser-skill 的每次操作我都会记录日志,包括操作类型、目标元素、执行结果。通过日志能快速定位到是哪一步开始出错的。
第三步,缩小范围。如果整个流程失败,不要从头重跑,而是从失败的那一步单独重试。这样可以快速验证是偶发问题还是必现问题。
第四步,手动复现。如果自动化怎么都跑不通,就手动操作一遍,看看真人操作时页面是什么反应。很多时候自动化失败是因为它模拟的操作和真人操作有细微差别。
提示:做浏览器自动化,日志和截图是你的两条命。没有这两样,排查问题基本靠猜。
4.3 提升稳定性的几个实操技巧
除了排查问题,我还总结了一些提升稳定性的技巧:
- 给每个操作加超时和重试。不要假设一次就能成功,失败后自动重试 2 到 3 次,成功率会大幅提升。
- 用文本定位代替 CSS 选择器。CSS 选择器容易因为页面改版失效,而按钮上的文字相对稳定。
- 关键操作后加短暂等待。不要操作完立刻进行下一步,给页面一点反应时间。
- 把长流程拆成短流程。每个短流程独立验证,降低整体失败率。
这次 227 次操作、4.3 小时的实战,虽然踩了不少坑,但最终跑通了整条链路。对我来说,最大的收获不是“AI 能发稿”这个结果,而是摸清了浏览器自动化在真实内容平台上的能力边界和稳定性瓶颈。后续如果要做类似的事情,这套经验可以直接复用,少走很多弯路。