ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI自动化发稿实战:Playwright浏览器自动化227次操作与9个坑

AI自动化发稿实战:Playwright浏览器自动化227次操作与9个坑 1. 项目缘起为什么要让 AI 自己去发一篇稿1.1 一个看似简单却暗藏玄机的需求事情的起因很朴素。我手头有一个持续运营的技术内容账号日常需要在腾讯云开发者社区发布技术文章。手动发布一篇文章的流程大概是登录、进入创作中心、填写标题、粘贴正文、上传封面、选择分类标签、预览、提交、等待审核。单次操作大概五到八分钟听起来不多但当你每周要发三到五篇、每篇还要反复调整格式的时候这个时间成本就变得相当可观了。于是我冒出一个念头能不能让 AI 自己去把这个稿子发了不是那种帮我生成一段发布脚本的浅层辅助而是真正意义上的端到端自动化——AI 自己打开浏览器、自己登录、自己填表、自己点提交整个过程我只负责最后验收。这个想法听起来像是给 AI 派了个跑腿的活儿但真正动手之后我才发现这里面涉及的坑远比想象中多。最终这次实战跑下来总共执行了227 次操作耗时4.3 小时踩了9 个比较典型的坑。这篇文章就是把整个过程完整复盘一遍包括技术选型、核心实现、参数计算、踩坑记录和排查技巧给同样想做浏览器自动化发布的朋友一份可以直接抄作业的参考。1.2 这个项目适合谁来参考先说清楚受众。如果你属于以下几类人这篇复盘对你会有直接帮助做内容运营的技术同学手上有多个平台需要同步发布想用自动化减少重复劳动。正在入门 AI Agent 的开发者想找一个真实、完整、有难度的浏览器自动化案例来练手而不是停留在让 AI 打开百度搜索这种玩具级别。对浏览器自动化感兴趣但一直没落地的人你可能听过 Playwright、Puppeteer、Selenium但不知道真实项目里会遇到什么。想了解 AI 与浏览器如何协作的人这里的AI 自己去发稿并不是纯脚本而是 AI 参与决策、脚本负责执行的混合模式。需要说明的是本文不会涉及任何账号密码的明文存储方案也不会教你绕过平台的风控机制。我们讨论的是在合规前提下用自动化工具替代人工重复操作所有操作都基于你自己拥有权限的账号遵守平台的服务条款。1.3 核心关键词与技术栈速览在正式展开之前先把这次项目涉及的核心概念和技术栈列清楚方便你建立整体认知类别具体内容作用自动化框架Playwright驱动浏览器执行操作语言Python 3.11主开发语言AI 决策层大模型 API处理页面理解、内容校验网络请求curl / requests接口层面的辅助操作运行环境Linux 服务器长期运行载体调试工具curl -v、浏览器 DevTools排查网络与页面问题这里特别提一下curl。虽然主体是浏览器自动化但在整个过程中curl 扮演了非常重要的侦察兵角色。很多接口层面的问题用 curl 单独测一下就能快速定位比在浏览器里反复点要高效得多。后面排查章节会详细讲。2. 整体方案设计为什么选浏览器自动化而不是纯接口2.1 两条技术路线的权衡让 AI 发一篇文章理论上至少有两条路可以走路线 A纯接口调用。直接分析发布接口构造 HTTP 请求用 curl 或 requests 把数据 POST 上去。优点是快、轻量、稳定。缺点是门槛高——你需要逆向分析接口签名、token 生成逻辑、加密参数而且平台一旦更新前端逻辑接口方案就可能失效。路线 B浏览器自动化。用 Playwright 这类工具驱动一个真实浏览器模拟人的点击、输入、滚动。优点是贴近真实用户行为不容易被识别为异常前端改版时通常只需要调整选择器。缺点是慢、资源占用高、稳定性受页面加载影响。我最终选了路线 B 为主、路线 A 为辅的混合方案。原因很实际发布文章涉及富文本编辑器、图片上传、分类选择等复杂交互纯接口方案要处理的加密和签名逻辑太多维护成本反而更高。而浏览器自动化虽然慢但胜在所见即所得调试起来直观。提示如果你的目标平台接口比较简单、没有复杂签名纯接口方案其实更优。选型的关键是看逆向成本和维护成本哪个更低。2.2 为什么让 AI 参与决策而不是写死脚本很多人会问既然流程固定为什么不直接写一个死脚本非要让 AI 参与这个问题问到点子上了。纯脚本的问题在于脆弱性。页面结构稍微一变、弹窗顺序一换、加载速度一慢脚本就崩了。而引入 AI 决策层之后可以处理一些非确定性的环节比如页面加载后判断当前处于哪个状态登录页创作页还是被弹窗挡住了富文本粘贴后检查内容是否完整有没有被截断、格式有没有丢失提交后判断是成功还是出现了错误提示这些判断如果用 if-else 硬编码规则会越写越多、越来越难维护。交给 AI 做状态识别和异常判断脚本只负责执行动作整体鲁棒性会好很多。2.3 整体架构拆解整个系统的架构可以拆成四层调度层负责任务排队、重试、日志记录。我用的是一个简单的任务队列每个发布任务是一个 job。决策层调用大模型 API输入当前页面截图或 DOM 摘要输出下一步该做什么。执行层Playwright 负责实际的浏览器操作把决策层的指令翻译成点击、输入、等待等动作。侦察层curl 和 requests 负责接口层面的探测、健康检查、辅助数据获取。这四层之间通过一个共享的上下文对象通信里面记录了当前 URL、页面状态、已执行步骤、错误信息等。这样设计的好处是每一层职责清晰出问题时能快速定位是哪一层的锅。2.4 关键参数的前置计算在动手之前有几个参数需要提前算清楚否则后面会反复返工。超时时间。浏览器自动化最怕的就是卡住。我给每个操作设置了分级超时页面导航 30 秒、元素等待 15 秒、单次点击 5 秒、AI 决策 20 秒。为什么这么分因为导航涉及网络请求慢一点正常元素等待是等 DOM 渲染15 秒足够点击是本地操作超过 5 秒基本就是出问题了AI 决策涉及 API 往返20 秒是留了余量的。重试次数。不是所有失败都值得重试。我的策略是网络类错误重试 3 次元素找不到重试 2 次AI 决策失败重试 1 次。重试间隔采用指数退避第一次等 2 秒第二次等 4 秒第三次等 8 秒。并发数。一开始我想开 3 个并发同时发不同文章后来发现浏览器实例太吃内存而且同一账号并发操作容易触发风控。最终改成单实例串行虽然慢但稳。3. 核心实现细节从打开浏览器到点击提交3.1 环境准备与依赖安装先把基础环境搭起来。我用的是 Ubuntu 22.04 的服务器Python 3.11。核心依赖就三个pip install playwright requests playwright install chromium这里有个细节playwright install chromium会下载一个独立的 Chromium不依赖系统自带的浏览器。这样做的好处是版本可控不会因为系统更新导致行为变化。坏处是占空间大概 300MB 左右。注意如果你在服务器上跑记得装一下 Chromium 运行需要的系统库否则会报缺少libnss3、libatk之类的错误。Ubuntu 下可以用playwright install-deps一键装齐。3.2 登录态的处理最容易被低估的环节整个流程里登录态是最麻烦的部分。原因有三第一登录通常有验证码或滑块纯自动化很难过。第二登录态有有效期过期后需要重新登录。第三直接存密码在脚本里是安全大忌。我的方案是复用已登录的浏览器上下文。具体做法是第一次手动登录一次然后把浏览器的storage_state包含 cookies 和 localStorage保存成 JSON 文件。后续每次启动时加载这个文件就相当于带着登录态启动。from playwright.sync_api import sync_playwright with sync_playwright() as p: browser p.chromium.launch(headlessTrue) context browser.new_context(storage_stateauth.json) page context.new_page() page.goto(https://cloud.tencent.com/developer)这个auth.json要妥善保管它等同于你的登录凭证。我把它放在服务器上一个权限为 600 的目录里并且定期检查有效期。提示登录态一般几天到几周会过期。我的做法是加一个健康检查任务每天用 curl 请求一个需要登录的接口如果返回未授权就发通知提醒我手动更新。3.3 富文本编辑器的处理粘贴比输入更靠谱发布文章的核心是往富文本编辑器里填内容。这里我踩了第一个大坑用type()逐字输入速度极慢且容易丢字。一篇 3000 字的文章逐字输入要花好几分钟而且富文本编辑器对输入事件的处理很敏感经常出现光标跳位、格式错乱。后来我改成剪贴板粘贴方案# 把内容写入剪贴板然后模拟 CtrlV page.evaluate(navigator.clipboard.writeText(arguments[0]), article_content) page.keyboard.press(ControlV)这个方案快得多而且格式保留得更好。但要注意剪贴板操作需要浏览器有相应权限headless 模式下可能需要额外配置。3.4 AI 决策层的接入方式决策层我用的是一套截图 结构化提示的方案。每次需要 AI 判断时把当前页面截图和一段描述当前任务的提示词一起发给模型让它返回一个 JSON 格式的指令比如{ action: click, target: 发布按钮, reason: 页面已填写完毕可以提交 }执行层解析这个 JSON找到对应元素并执行。这里的关键是提示词要足够具体告诉 AI 当前处于什么阶段、有哪些可选动作、返回格式是什么。提示词写得越清楚AI 的判断越稳定。3.5 提交后的状态确认点击提交之后不能想当然认为成功了。我的做法是双重确认等待页面出现成功提示比如发布成功的 toast。用 curl 请求文章列表接口确认新文章确实出现在列表里。这两步都通过才算真正成功。只靠页面提示是不够的因为有时候页面提示成功但实际没提交上去比如网络中断导致请求没发出去。4. 227 次操作全流程拆解4.1 操作次数的构成分析先解释一下这 227 次操作是怎么来的。这里的操作指的是每一次有意义的浏览器动作或 API 调用包括点击、输入、等待、截图、AI 决策、curl 请求等。拆解下来大概是操作类型次数占比页面导航与等待3816.7%元素点击5222.9%内容输入与粘贴2410.6%AI 决策调用4118.1%截图与状态检查3314.5%curl 辅助请求219.3%重试与异常处理187.9%可以看到点击和 AI 决策占了最大头。这也符合直觉——浏览器自动化的本质就是不断点击而 AI 决策是保证点对地方的关键。4.2 从启动到登录态加载流程的第一步是启动浏览器并加载登录态。这一步看起来简单但我在这里就遇到了第一个坑headless 模式下某些页面元素渲染不出来。原因是 headless 模式为了性能会跳过一些渲染步骤。解决办法是给启动参数加上一些伪装配置browser p.chromium.launch( headlessTrue, args[ --disable-blink-featuresAutomationControlled, --no-sandbox, --disable-dev-shm-usage ] )--disable-blink-featuresAutomationControlled是为了让浏览器不那么容易被识别为自动化工具。--no-sandbox和--disable-dev-shm-usage是服务器环境下的稳定性配置能避免一些内存相关的崩溃。4.3 内容填充的完整链路内容填充是整个流程里最耗时的部分大概占了总时间的 40%。完整链路是这样的打开创作页面等待编辑器加载完成。填写标题用fill()直接赋值比逐字输入快。粘贴正文用剪贴板方案。上传封面图用set_input_files()。选择分类和标签点击下拉框选择选项。检查所有字段是否填写完整。这里有个细节值得说标题用fill()而不是type()。因为标题是单行输入框fill()会直接设置值并触发 input 事件速度快且不会丢字。而正文是富文本fill()不适用只能用粘贴。4.4 提交与结果验证提交环节我做了三次尝试才成功。第一次点击提交后页面没反应第二次出现了内容不能为空的提示第三次才真正提交成功。事后分析第一次是因为编辑器内容还没完全同步到表单第二次是因为某个隐藏字段没填。这给我的教训是提交前一定要做一次完整的状态检查。我后来加了一个检查函数在点击提交前把所有必填字段的值读出来验证一遍确认无误再提交。5. 9 个坑的完整记录与排查过程5.1 坑一curl 连接超时导致健康检查误判现象健康检查脚本报curl: (28) timeout但实际服务是正常的。排查用curl -v单独测发现是 DNS 解析慢导致的。默认超时太短网络抖动一下就超时了。解决给 curl 加上--connect-timeout 10 --max-time 30并增加重试--retry 3。curl -v --connect-timeout 10 --max-time 30 --retry 3 https://api.example.com/health5.2 坑二curl 56 连接被重置现象curl 56 recv failure: connection reset by peer。排查这个错误通常是服务端主动断开了连接。可能是请求头不完整或者请求频率太高被限流。解决补全请求头User-Agent、Accept 等并在请求之间加延时。5.3 坑三curl 23 写入失败现象curl: (23) failure writing output to destination。排查这个错误是输出目标写不进去。我当时的场景是把 curl 输出重定向到一个磁盘已满的目录。解决清理磁盘空间或者把输出重定向到/dev/null如果不需要保存的话。5.4 坑四headless 模式元素找不到现象Timeout waiting for selector但同样的选择器在 headed 模式下能找到。排查headless 模式下页面渲染时机不同元素出现得晚。解决改用wait_for_selector并设置合理的超时或者用wait_for_load_state(networkidle)等页面完全加载。5.5 坑五富文本粘贴格式丢失现象粘贴后代码块变成了纯文本换行也乱了。排查剪贴板里的内容格式和编辑器期望的格式不一致。解决粘贴前先把内容转成 HTML 格式用text/html类型的剪贴板数据。5.6 坑六登录态过期无感知现象脚本跑了一半突然跳到登录页后续操作全部失败。排查登录态过期了但脚本没有检测机制。解决每次操作前检查当前 URL如果包含登录相关路径立即中止并报警。5.7 坑七AI 决策返回格式不稳定现象AI 有时返回 JSON有时返回带解释的自然语言解析失败。排查提示词里虽然要求了 JSON但模型不一定严格遵守。解决在提示词里加只返回 JSON不要任何其他文字并在解析时做容错处理用正则提取 JSON 部分。5.8 坑八并发导致风控现象开 3 个并发后账号被临时限制操作。排查同一账号短时间高频操作触发了风控。解决改成单实例串行并在操作之间加入随机延时1-3 秒。5.9 坑九提交成功但文章未出现现象页面提示发布成功但文章列表里找不到。排查请求发出去了但服务端处理失败页面提示是乐观更新。解决加二次确认用 curl 查列表接口验证。5.10 坑位速查表坑号现象关键词根因解决方向1curl 28 timeoutDNS 慢加超时和重试2curl 56 reset请求头不全/限流补请求头延时3curl 23 write fail磁盘满清理或改输出4selector timeout渲染时机改等待策略5格式丢失剪贴板类型用 HTML 格式6跳登录页登录态过期加检测机制7JSON 解析失败模型不守格式提示词容错8账号被限并发过高串行随机延时9假成功乐观更新二次确认6. 实操心得与避坑经验6.1 关于超时和重试的经验超时设置不能一刀切。我的经验是按操作类型分级并且重试要区分错误类型。网络类错误值得重试逻辑类错误比如元素真的不存在重试也没用反而浪费时间。6.2 关于 AI 决策层的经验AI 决策层不是万能的。它擅长处理模糊判断但不擅长处理精确操作。所以我的分工是AI 负责现在该干什么脚本负责具体怎么干。不要让 AI 去算坐标、去拼选择器那些交给代码。6.3 关于日志和可观测性227 次操作如果没有详细日志出问题根本没法排查。我的做法是每一步都记录时间戳、操作类型、目标、结果、耗时。日志用 JSON 格式方便后续分析。这次复盘能这么清楚全靠日志。6.4 关于成本控制4.3 小时里AI 决策调用占了 41 次。如果每次都发完整截图token 消耗会很大。我的优化是只在关键节点调用 AI常规操作直接用脚本判断。这样既保证了鲁棒性又控制了成本。7. 后续可以怎么扩展这套方案跑通之后其实可以扩展出很多玩法。比如把发布流程抽象成配置支持多个平台比如把 AI 决策层换成更轻量的本地模型降低成本比如加入内容质量检查发布前自动校对错别字和格式。我个人在实际操作中的体会是浏览器自动化的难点从来不在怎么点而在怎么知道点对了。把状态检测和异常处理做扎实比堆砌功能重要得多。最后再分享一个小技巧——每次改动脚本后先用 headed 模式跑一遍看效果确认没问题再切 headless能省下大量排查时间。
返回列表