Midscene.js与Playwright融合实践:AI自然语言驱动的浏览器自动化方案
做UI自动化的朋友应该都有过这种体验一个稳定跑了几个月的用例某天突然红了查半天发现只是前端把一个按钮的文案从“确认”改成了“提交”或者某个接口返回多了一个字段整个页面结构全乱了。我最早用纯脚本方式写自动化时每天都陷在修选择器、调等待时间、补断言的泥潭里。后来接触了Midscene.js发现原来可以用自然语言让浏览器自己“看”页面、“做”操作再把Playwright这类传统框架的稳定执行能力接进来就能形成一套真正能落地的智能浏览器自动化方案。这篇文章就把我自己的融合实践完整拆开讲为什么这么设计、核心代码怎么组织、踩过哪些坑、遇到问题怎么排查。1. 为什么要把AI带进浏览器自动化1.1 传统自动化工具的瓶颈越来越明显先说说我过去用Playwright这类工具写自动化时最头疼的几个点。最根本的问题是选择器太脆弱。前端项目只要用上动态class、样式哈希、虚拟DOM重新渲染之前辛辛苦苦写好的CSS选择器、XPath或者基于文本的定位方式就可能失效。尤其是现在很多中后台页面喜欢用结构化的组件库同一个按钮在不同状态下会渲染出完全不同的DOM分支selector写得再精准也扛不住设计稿的频繁调整。我印象最深的是一次重构某个后台表格的排序图标从“箭头”换成了“三角”我所有基于图标的点击操作全部报废光修这些用例就花了一个下午。其次是等待条件的判断很难写到通用。页面渲染、接口返回、懒加载、组件动画这些因素的顺序和时长在不同环境下会有差异。Playwright虽然提供了自动等待和轮询机制但遇到复杂的异步流程比如“先请求列表再校验权限最后跳转路由”还是得手动设计waitForResponse、waitForSelector这些逻辑。写多了就会发现自动化脚本的事实复杂度不亚于被测试的业务代码本身。再有就是复杂业务路径的维护成本。比如一个供应链系统的下单流程涉及多个页面、多个弹窗、多次表单校验每一步都需要精确控制。一旦中间某个条件分支变了——比如新增了一个“是否加急”的开关——整条链路的选择器和等待逻辑就要跟着改。传统工具是“规则驱动”的它只能按照预设路径执行页面稍微偏离计划就不会变通。这些问题不是框架不够好而是思路的问题规则驱动的方式天然适合确定性的步骤可真正实际业务里大量操作是模糊的、需要“看情况”的单靠写死的选择器和固定步骤很难覆盖。1.2 Midscene.js能带来什么Midscene.js是这两年很受关注的AI浏览器自动化工具核心思路是把视觉理解能力接入浏览器让自动化过程不再完全依赖DOM结构。它通过多模态模型理解页面截图然后根据自然语言指令完成点击、输入、拖拽、提取数据等操作。用它的基本工作方式举例agent.navigate(请输入账号密码点击登录等待页面跳转到控制台);这一句天然语言描述对应到传统Playwright代码里可能是十几行selector和wait的组合。Midscene.js会在执行过程中截取页面视图AI模型负责理解“登录按钮在哪里”“账号输入框处于什么状态”再生成对应的动作序列。它的优势在于不再依赖“结构”而是依赖“看”页面重构了、样式变了只要语义还能看明白指令就可以继续复用。写用例的门槛低不用记忆一堆选择器语法描述意图就可以。对动态渲染、ifame、弹窗等复杂场景的适应能力更强因为模型是直接看图。还能做数据提取比如“把表格中所有订单号和金额提取成JSON”这种需求用传统方式要写很长一串遍历逻辑。但Midscene.js也有很明显的短板AI推理有延迟每一步操作都要等模型返回结果纯AI驱动在速度上赶不上原生选择器。推理结果有概率性同一个指令偶发会“自信地”给出错误动作。持续调用大模型会产生费用也不适合做高频、大批量的压测性操作。在非常要求确定性的场景里比如财务对账、支付流程光靠AI“自觉”是不够的。所以结论很直接AI好但不能什么都交给AI。1.3 Playwright的价值不能丢Playwright是现代浏览器自动化绕不开的框架支持Chromium、Firefox、WebKit三种内核API设计完整等待机制、网络拦截、多标签页控制、录制回放、Trace查看器这些能力都是成熟的工程级方案。它在确定性和执行效率上是AI方案暂时比不了的。一个按钮如果有一个稳定的data-testid属性Playwright点击它只需要几毫秒定位不会有任何歧义断言时机、网络状态校验、请求拦截返回mock数据这些能力在工程化测试里属于刚需。它的局限是“听不懂人话”页面变了就得跟着改。但也正是这个特性让它执行时足够可靠不会自己发挥。于是融合的逻辑就出来了用Midscene.js解决“复杂性”和“多变性”让AI看页面、做决策、处理异常的视觉和语义判断。用Playwright解决“稳定执行”和“精确校验”把AI产出的意图落成可信赖的浏览器操作。2. 融合方案的整体设计思路2.1 双引擎协作链路我落地这套方案时没有简单地把两个工具拼在一起调用而是先定了一条清晰的协作链路自然语言指令 → AI理解页面 → 生成动作规划 → Playwright执行操作 → 状态校验与反馈 → 进入下一步这套链路里Midscene.js负责从截图和文本里提取信息判断“现在该干什么”Playwright负责真正去点击、输入、等待、断言。它不是替代关系而是上下游关系。执行过程中两个引擎的角色可以互换但彼此的边界很清晰。实际项目中我定义了三种协作模式AI主导Playwright兜底。适用于页面结构不稳定、无法写出可靠选择器的复杂交互场景。AI负责完成动作Playwright在关键步骤后做状态断言确认动作生效。Playwright主导AI补盲。适用于大部分常规稳定操作比如点击固定导航、填写标准表单。这些操作直接用selector完成只有遇到异常分支“找不到元素”“出现意外弹窗”时才让AI介入判断。混合流水线。AI先全局扫描页面状态并提取关键信息把这些信息传给Playwright逻辑由后者按数据处理规则走完整条业务链路。我用得最多的是第一种因为真正让自动化用例跑不起来的往往是那些结构每天都在变的页面区域。但对登录、导航这种基本稳定又对结果要求极高的操作我会坚持用Playwright原生方案不交给AI。2.2 适合融合的典型场景不是所有自动化需求都适合上融合方案我自己的经验是下面四类场景收益最大。第一类是营销活动页和运营后台。这类页面改版频率高设计自由度高同一个“领取优惠券”按钮在不同活动里可能有完全不同的样式和位置传统选择器根本追不上。用AI视觉来定位操作基本可以无视页面改版。第二类是复杂数据提取。比如要从供应商管理系统里抓取一批表格数据传统方式要写各种分页遍历、行列解析逻辑遇到表格合并单元格就头疼。AI可以直接说“提取当前页面所有订单号、金额、状态按JSON数组返回”提取逻辑和页面结构完全解耦。第三类是探索式自动化测试。先让AI自然语言走通一条新业务路径验证可行性后再把稳定路径固化成标准Playwright用例。这套路可以在需求初期快速生成自动化用例雏形比对着需求文档一行行写selector高效得多。第四类是“数字员工”类的无人值守流程。比如每天定时登录某个平台、导出报表、核对数据、处理站内信这些流程通常不会频繁变化但偶尔有异常分支融合方案能更好地应对分支情况。我接手过一个模拟项目X是某公司内部的供应链数据核对系统页面几乎每两周调整一次布局。之前纯Playwright脚本每周要修一次选择器融合后平均一个月才需要更新一次而且改的多半是AI指令描述不是底层执行逻辑。2.3 方案对比纯脚本、纯AI与融合方案对比维度纯Playwright规则脚本纯Midscene.jsAI全流程融合方案稳定性高但前提是元素结构不变化中存在推理不稳定性高AI决策可靠执行配合维护成本高selector变更频繁时要大量修改低改指令成本低中低只维护关键路径与指令执行速度极快较慢每次操作需AI推理中常规操作走原生异常操作走AI对页面改版的适应差强强资源消耗CPU/内存消耗小需要调用模型成本高可控AI只在需要时触发适用场景需求稳定、结构固定的系统探索性、短期任务长期运行、页面多变的生产级自动化从表格可以看出来融合方案不是“每个操作都走AI”而是“必要时才让AI介入”。这一点我觉得是整套方案能否落地的核心思路。3. 核心实操环境搭建与代码实现3.1 环境准备与依赖安装先准备一套能跑的最小环境。我这里用Node.js环境因为Midscene.js和Playwright在JavaScript/TypeScript生态里配合最顺畅调试工具链也齐全。mkdir ai-automation-demo cd ai-automation-demo npm init -y npm install midscene playwright npx playwright install chromium如果网络条件不理想npm安装可能会比较慢建议配置镜像源后重试。有一个经常被忽略的点Playwright安装浏览器内核时有些环境会因为没有系统依赖导致内核启动失败Linux环境尤其常见。运行npx playwright install --with-deps chromium可以自动安装缺失的系统库能省很多事。版本管理上我建议把midscene和playwright的版本锁定精确版本号不要直接用默认的^范围。因为这两个库迭代都很快API调整频繁偶尔一个主版本升级就会导致内部兼容逻辑变化。我踩过一次某个小版本升级后两者内部对页面上下文的处理方式变了自动化任务频繁报错最后排查到是升级引起的问题花了不少时间。环境装好之后确认Node版本至少在18以上。Midscene.js对运行时有一定要求太老的版本容易出现各种兼容性错误。3.2 基础实现先跑通一次AI驱动的用例这一段我直接展示最简可运行案例代码注释里会说明哪些变量需要按你自己的环境替换。import { chromium } from playwright; import { Agent } from midscene; async function main() { // 1. 启动浏览器创建页面 const browser await chromium.launch({ headless: false }); const page await browser.newPage(); // 2. 通过page实例初始化Agent const agent new Agent({ page, // 模型相关的密钥通过环境变量提供不要写死在代码里 }); // 3. 打开目标站点 await page.goto(https://example.com/login); // 4. 用自然语言让AI执行登录流程 await agent.navigate(请输入账号和密码点击登录按钮等待页面跳转完成); // 5. 简单验证登录结果 await page.waitForURL(**/console/**, { timeout: 15000 }); console.log(登录成功已进入控制台); await browser.close(); } main().catch((err) { console.error(自动化执行失败:, err); process.exit(1); });这里的核心是Agent接收了Playwright的page实例。因为这个page实例同时被两个引擎持有所以AI执行完动作后Playwright可以立刻接手做等待和断言。这也是融合方案的基本前提一个浏览器页面两个工具共用。首次运行时建议把headless设为false也就是有头模式。原因是AI的视觉判断依赖页面截图如果无头模式下页面渲染效果和本地有差异AI可能会看错元素。等整个流程稳定后再切换到headless: true跑无人值守任务。运行完这个示例后你会发现Midscene.js会自动保存执行过程中的截图和日志信息。这个默认行为非常有用后面排查看AI“当时看到了什么”基本靠它。3.3 深度融合AI执行与Playwright断言配合下面这个例子更接近生产场景。需求是打开商品列表页用AI提取列表里所有商品名称和价格用Playwright对提取结果做断言校验如果断言失败自动重试AI提取一次最终输出一个可校验的数据结果。import { chromium } from playwright; import { Agent } from midscene; import { expect } from playwright/test; async function extractAndVerify() { const browser await chromium.launch({ headless: true }); const page await browser.newPage(); const agent new Agent({ page }); try { await page.goto(https://example.com/products?page1); // AI提取数据返回JSON结构 const result await agent.evaluate( 提取当前页面所有商品名称和价格返回JSON数组字段为name和price ); console.log(AI提取结果:, JSON.stringify(result)); // Playwright做确定性断言 expect(Array.isArray(result.data)).toBeTruthy(); expect(result.data.length).toBeGreaterThan(0); expect(result.data[0]).toHaveProperty(name); expect(result.data[0]).toHaveProperty(price); // 二次校验断言模式下检查页面DOM是否包含对应商品名称文本 const firstName result.data[0].name; await expect(page.locator(text${firstName}).first()).toBeVisible({ timeout: 5000, }); console.log(校验通过共提取, result.data.length, 条商品数据); } finally { await browser.close(); } }这段代码展示了一个清晰的分工逻辑提取任务交给AI因为它能灵活应对表格、卡片、列表等不同布局。结果校验交给Playwright因为断言逻辑必须稳定、确定、可复现。二次校验本质上是用DOM文本搜索去反查AI的提取结果防止AI“一本正经地胡说八道”。我自己在类似数据提取场景里是会把这两种校验都加上的。一次好的融合不是只用一种工具的能力而是让两种工具互相卡对方的错误。3.4 关键配置与运行参数说明这套方案真正跑起来之前有几个配置参数需要特别关注。timeout的设置要分两层。Playwright这边常规操作timeout按习惯设就好比如5秒或10秒。Midscene/Agent这边AI推理本身耗时可能达到几秒甚至几十秒所以要给AI操作留足时间。我会单独给AI流程设置60秒级别的超时确保复杂页面的识别不会中途被切断。很多第一次使用AI自动化的人都会在超时问题上栽跟头。headless模式的选择要看场景。运行在CI服务器上、无人值守的定时任务当然要用无头模式但首次调试、处理对无头检测敏感的站点时建议用有头模式观察。有些站点会通过UA、浏览器指纹等方式检测自动化环境这种情况下用有头模式再加一些常规规避手段通常更稳。不过要注意规避检测本身是灰色操作用在前端自动化测试自己控制的测试环境里没问题一定不要拿去做任何不合规的事情。截图与录屏设置也值得调整。Midscene.js默认会保存关键步骤截图我会把这些输出目录统一配置到项目下的ai-debug/文件夹并和历史记录按日期归档。出问题时这些截图配合日志一起看定位效率翻倍。录屏功能在排查“页面频繁跳转”“元素一闪而过”这类问题时特别有用但一直开录屏会拖慢执行速度我一般只在回归失败时开启。模型服务的密钥配置是我反复提醒自己的一件事。千万不要把API密钥写在代码里尤其是项目会同步到git仓库时。正确做法是使用环境变量比如启动脚本里用export MIDSCENE_API_KEYxxx或者放在.env文件里并确保它被.gitignore忽略。我还额外给AI操作加了一层审计逻辑——所有发送给模型的截图和文本都会记录到本地日志方便追溯“AI到底看到了什么”。4. 融合方案中的实战经验与避坑技巧4.1 我踩过的几个坑第一个坑是AI太“自信”。某一次自动化任务里我让AI“点击表格最后一行的编辑按钮”结果它识别错了行点击了另一条记录的编辑入口然后后面的流程全部跑偏。AI会非常流畅地遵循指令即使页面元素看错了它也不会自己停下来反省。从那以后我在所有关键操作后面都加了Playwright断言确保动作真的作用在正确的元素上。比如点击编辑按钮后立刻断言“页面出现了对应记录ID的标题文本”确认无误再继续下一步。第二个坑是选择器优先原则。一开始为了体验AI的便利性我把很多明明有稳定选择器的操作也交给了AI。后果是执行速度变慢而且偶尔会出现推理偏差。后来我定了一条规矩只要能稳定拿到selector的元素一定用Playwright原生方式操作只有那些没有稳定特征、结构时常变化的区域才交给AI。这条规矩执行后整个自动化任务的执行时间缩短了一半以上稳定性反而更好了。第三个坑是任务指令太长。某次我把一整条业务流程写成了一段很长的自然语言指令包括打开页面、筛选条件、导出Excel、校验数据等。结果AI在执行到中间某一步时漏掉了后续几步——它认为任务已经完成了。后来我把长流程拆成多个短指令每个短指令仅描述“一个明确的页面状态转换动作”并且在每条指令里加上“做完后等待页面加载完成”之类的收尾条件。AI的上下文负担减轻了执行完整性提高了很多。第四个坑是“动态弹窗”这种特殊元素。很多站点的弹窗不是原生alert或dialog而是DOM层的自定义组件。AI基于截图能“看到”弹窗但一些弹窗出现时会改变页面结构AI的视觉判断可能因此错乱。我现在遇到弹窗逻辑统一在Playwright层用page.on(dialog)监听或者DOM监听处理不让AI去跟这类场景硬碰。4.2 稳定性策略与兜底机制融合方案要真正用于生产级自动化光有基础流程不够还得搭一套稳定性策略。失败重试机制是我最看重的。AI操作失败后先自动截图记录现场然后将指令简化重试一次。比如原指令是“提取当前表格中所有订单信息并按金额从高到低排序”失败的简化版本是“提取当前表格的所有行内容”。简化指令通常能让AI更容易聚焦当前页面状态减少混淆。如果简化版本还是失败就直接切换回Playwright原生方式用DOM解析做数据提取。这个三级降级策略让我在好几条核心用例上避免了“全红”的窘境。熔断机制很实用。我有一个计数器如果同一页面连续失败超过三次就不会再继续调用AI而是直接把任务标记为失败并告警。因为连续失败大概率说明当前页面或指令本身有问题继续调用AI只会产生更多费用不会带来更好的结果。告警之后人工介入把现场截图和日志拉出来分析比让机器人反复撞墙高效得多。权限白名单也要注意。AI一旦在无人值守模式下操作它是有能力点击“删除”“清空”“提交支付”这类危险操作的。我会在指令执行前做一轮关键词校验如果指令中包含策略中标记为高危的动作词就必须经过额外的人工确认环节才能执行。这个设计虽然多了一道流程但从业务安全角度看值得。4.3 调试与日志规范调试融合方案时最怕的就是“AI觉得自己操作成功了但实际页面状态不对”。这种问题靠肉眼盯控制台输出基本看不出来一定要借助工具。Midscene.js的调试模式会输出AI内部“看到”了什么、生成了什么动作、动作是否执行成功。打开方式是在Agent初始化时把日志级别设为debug然后执行过程中所有推理细节都会打印出来。这些信息配合它自动保存的截图可以看到AI每一步的“真实视野”。Playwright的Trace Viewer同样关键。它能记录页面所有交互、网络请求、DOM变化回放时可以看到完整的操作序列。我的习惯做法是先用Trace Viewer回放整个流程确定哪一步开始页面状态和预期不符然后再打开Midscene的调试日志对照AI当时的判断依据两者结合基本能在十分钟内定位问题出在执行端还是理解端。日志规范方面我统一的输出格式是时间戳 指令类型 操作对象描述 执行结果 耗时比如2025-05-18 10:23:11 | AI行动 | 点击“导出报表”按钮 | 成功 | 3421ms 2025-05-18 10:23:14 | Playwright断言 | URL包含 /export/success | 失败 | 120ms这种格式化日志在对接监控系统时会非常舒服。我后来还加了一个小功能把AI每次发送给模型的截图做了匿名化处理比如给非目标区域做模糊既减少敏感信息暴露又让模型更聚焦核心元素。5. 常见问题与排查思路5.1 AI识别不到元素或识别错误这类问题在我刚开始用Midscene.js时频繁出现大概率不是模型能力不行而是使用方式有问题。首先检查页面状态。AI依赖的是截图不是DOM如果元素在截图里被遮挡、被折叠、还没有渲染完成它当然看不到。我会在指令前加一句“确保页面加载完成”或者先用Playwright的waitForLoadState显式等待再开始AI操作。其次检查指令描述。不要把指令写成“点那个蓝色的东西”要具体一些“点击页面右上角的下载按钮”“下拉筛选框选择类别为已完成”。描述越清晰AI定位越准。如果AI仍然识别错可以把目标区域用文字补充进指令比如“单击表格第三行中的详情链接”。实在不行的情况下可以绕过AI视觉直接用Playwright获取DOM坐标再模拟点击。这个兜底方案在我的项目里出现过一次某个元素是Canvas绘制的AI截图能看到形状但无法准确定位最后我直接算坐标点去点击反而更稳定。5.2 线上环境和本地环境差异自动化脚本最怕的就是本地跑得好好的部署到服务器上就罢工。融合方案里这类问题主要来自两个层面。一是浏览器渲染差异。本地有完整字体、GPU加速服务器上可能是精简环境页面渲染结果会和截图时有差别。解决方式是尽量在禁用动画、固定视口大小、统一字体渲染的条件下执行。我自己的经验是把viewport统一设置成1920x1080并且固定deviceScaleFactor这样AI截图的一致性会好很多。二是账号登录态差异。我强烈建议登录流程永远放在Playwright层处理不要交给AI。因为登录通常是标准的表单流程有确定的选择器Playwright可以用很短时间完成而且登录态的管理、Cookie注入、权限控制这些功能Playwright支持得更好。AI在这个环节介入反而容易出错尤其是涉及多因素认证时AI面对动态交互会变得不可控。数据脱敏问题容易忽略。AI视觉方案会把页面截图发送给模型服务这意味着页面上的用户手机号、身份证号、营收数据等敏感信息也会一起被发送。我在生产部署前做了一轮全面检查把所有涉及敏感数据的页面做了脱敏处理比如用遮蔽组件在自动化模式下隐藏真实数据。这个设计不只是合规问题更是工程责任。5.3 与CI系统集成的问题与解决CI环境通常是linux容器或虚拟机上跑自动化资源限制和本地差别很大。虚拟显示的问题最常见。无头模式下Chromium可以不依赖显示器直接跑但AI截图在某些情况下需要完整的渲染管线。如果遇到截图白屏、黑屏、元素缺失建议用xvfb-run包装命令跑或者直接在Docker镜像里安装虚拟显示服务。很多同学看过这个坑后秒懂页面渲染需要显卡资源虚拟显示就是给浏览器一个假的屏幕输出。资源消耗也需要提前评估。AI推理对带宽、内存的要求都不低在CI里同时跑多条用例时并发数需要调低。我这里有一个实践数据在2核4G的容器里同时跑3条融合方案的用例内存已经接近上限CPU持续满载。后来把并发数降到2并且用一条共享的浏览器会话串行执行AI相关用例资源占用才稳定下来。CI里跑全量用例时我会把“纯Playwright用例”和“AI参与用例”分成两个任务后者单独分配一个更大的执行器。失败定位方面CI环境比本地更难受因为现场不可视。我给的方案是把每轮执行的关键截图和日志作为制品上传到对象存储失败时自动拉取最近一次截图拼接到告警消息里。这样做虽然不能100%复现现场但通常能快速判断是“AI看清了但点错位置”还是“页面渲染根本不完整”方向对了排查就快了。最后再分享一点体会实际用了这套融合方案小半年我最深的体会其实是“让AI做它擅长的事让框架做它擅长的事”。AI擅长的是处理模糊和多变框架擅长的是稳定和精确把两者接好自动化项目才能真正摆脱“天天修脚本”的被动状态。给做这方向的朋友一个实用建议刚开始落地时不要追求所有环节都智能化挑两条最痛的业务路径先跑通验证融合的价值再逐步铺开。另外写AI指令时给每个动作加一个编号执行日志里就能看到“它做到了第几步”排查问题的效率会明显提升。我在几个内部项目里都是用这个思路目前已经稳定跑了两个季度希望这套经验能帮你在自动化方案选型时少走些弯路。