☰
Midscene.js实战:自然语言驱动浏览器自动化,告别脆弱CSS选择器
2026/10/20 22:22:59 网站建设 项目流程

先聊个真实场景。我维护过一套基于传统自动化框架的回归脚本,页面一改版,几十个选择器集体失效,光修定位就花了一天。这种痛苦做过浏览器自动化的人都懂:元素ID漂移、动态渲染打乱时序、跨域弹窗干扰、验证码偶尔冒出来……后来我接触到Midscene.js,第一次用自然语言让AI去操作浏览器,说实话那感觉挺奇妙的。它不预设你写选择器,而是由多模态模型直接理解页面内容,听懂任务描述,然后自己决定点哪个按钮、填哪个输入框。

这篇文章不谈概念包装,就实打实拆一下Midscene.js是怎么工作的、怎么跑通第一个Demo、遇到问题时怎么排查,以及什么时候该用它、什么时候不该用。目标是让有兴趣尝试的人少走弯路,几个小时之内就能上手写自己的AI浏览器操作员。

1. 为什么需要“AI浏览器操作员”:传统自动化的问题出在哪

1.1 选择器很脆,页面一变就崩

传统浏览器自动化的主力工具,核心都是“选择器+固定步骤”。哪怕写得再优雅,本质都是:定位到某个元素,执行某个动作,等待某个结果。

这套模式对付稳定的管理系统还行,换成互联网产品、电商页面、动态后台,痛点就很明显了。比如页面从class名切换到data属性、按钮文字从“提交”变成“保存并提交”、弹窗从iframe改成shadow DOM,只要结构变了,脚本就得跟着改。我统计过,一个中大型后台的自动化测试,维护时间常常占整体投入的六成以上,剩下四成才是真正写用例的时间。这个比例很反直觉——自动化本来是为了省人力,结果变成了运维成本黑洞。

Midscene.js解决的就是这个“定位”环节。它不再靠选择器,而是靠视觉理解加DOM结构分析。你只需要说“找到那个价格最高的商品,把它的名称记下来”,模型自己会去识别页面里哪里是价格、哪里是商品名。页面改版后,只要视觉表达没变,AI通常还能认出来。这个特性在实际项目里意味着:维护成本从“改代码”变成了“偶尔看看AI认错没”,省力不止一个量级。

1.2 传统脚本是“按步骤执行”,AI操作员是“按意图执行”

传统脚本执行的是“plan”的执行器:计划早就写死了,脚本只是一步步照做。如果中间出现意外——按钮没加载出来、页面多弹了一个遮罩层——脚本基本就卡死或者误点。

AI操作员的思路是:把任务描述给模型,模型根据当前页面实际情况动态规划步骤。它看到的不是“第3个元素”,而是“页面左上角的‘搜索’按钮”。它不需要预设每一步怎么走,而是每一步都基于当时的页面截图和DOM信息重新判断。这个差异看起来不起眼,实际用起来差别巨大:

对比项传统自动化脚本Midscene.js AI操作
元素定位方式CSS选择器/XPath视觉识别+DOM语义
步骤来源写死脚本模型动态规划
页面改版影响结构一变化就崩,需要改代码视觉表达没变通常还能跑
异常处理靠程序员写分支模型能自己尝试其他路径
开发门槛需要掌握框架API和调试技能会写自然语言描述任务就行

我接触过不少做RPA和自动化的同事,他们问得最多的一个问题就是“AI定位到底可不可靠”。我的经验是:可靠性的关键在于怎么描述目标场景。给模型足够清晰的页面语境,它的成功率比写得粗糙的选择器高得多;反过来,如果任务本身表述模糊,比如只说“提取数据”,不说提取哪些字段、输出什么格式,AI也会给你一个看似合理但实际没用的结果。

所以这里要提前打个预防针:Midscene.js不是把“写脚本”变成“不用写”,而是把“写脚本”变成“写任务说明”。说明写得越好,操作员就越聪明。

2. Midscene.js的核心机制:AI是怎么“看懂”页面的

2.1 双通道感知:视觉截图和DOM结构一起喂给模型

Midscene.js跟早期那种“截个图,丢给多模态模型,让它猜”的方案不一样。它同时走两条路。

第一条是视觉通道:浏览器把当前页面截成图片,交给视觉语言模型,模型看的是“人眼视角”的页面构图,自然能理解按钮在哪儿、输入框长什么样、表格哪一列是价格。

第二条是DOM通道:Midscene.js会把页面的DOM结构、ARIA标签、可见文本、元素区域坐标等信息做抽取和压缩,转成结构化的“页面状态描述”一起发给模型。这个细节很关键——纯视觉方案容易产生幻觉,模型可能看错了按钮位置,或者不认识某种字体;有了DOM结构做辅助,模型在决定“点击”“输入”这些动作时,就有了准确坐标和元素语义,定位精度会高很多。

打个比方:视觉通道是人的眼睛,DOM通道是人的“空间常识”。单靠眼睛看东西有时会看走眼,但配合常识判断,比如“门把手一般在门旁边”“按钮一般长在对齐的位置”,出错率就低得多。

这一套设计解释了Midscene.js名字里的“mid”——它不是一个从零造的浏览器,而是在现有浏览器控制层之上,接一层“意图理解引擎”。

2.2 任务规划与工具调用:从一句话到一串操作

当用户输入自然语言指令后,Midscene.js的流程大概是这样:

  1. 把任务说明、当前页面截图和DOM结构信息组装成一个结构化请求发送给模型。
  2. 模型输出一个操作计划,比如“先定位搜索框,输入关键词,再按回车”。
  3. Midscene.js解析计划,调用浏览器控制API真正执行这些动作,模拟用户输入、点击、滚动。
  4. 执行完一步之后,重新感知页面状态(截图+DOM),再继续规划下一步。
  5. 直到模型认为任务完成,或者达到预设的终止条件,才会停下来并输出结构化结果。

这个“感知-规划-执行-再感知”的循环,是AI操作员跟传统脚本最本质的区别。传统脚本是线性执行,AI操作员是闭环控制。也正因为有闭环,它对页面变化的容忍度高很多——有时页面布局变了,AI会在执行过程中重新判断“原来的输入框现在跑到哪里了”,而不是死守坐标。

任务说明通常通过YAML配置来组织。Midscene.js支持把一连串操作写成可读性很强的脚本,既可以本地跑,也可以嵌入测试流程或数据处理管线。YAML的好处是直观,不熟悉代码的人也能看懂每一步做了什么;同时它又天然支持版本管理,改动历史清清楚楚。

2.3 为什么选择“循环判断”而不是“一次性推理”

有个问题我最初也很疑惑:为什么不把整个任务一次性丢给模型,让它生成完整点击坐标列表,然后一口气执行?

原因很简单,浏览器的页面状态不是静态的。一个按钮点击之后,页面可能跳转、弹窗、局部刷新、加载延迟,这些变化不是模型在给出计划那一刻能预见的。如果一次性推理出所有坐标,第二步可能已经因为页面变化失效了。Midscene.js选择“边做边看”,每一步都从真实页面状态出发,这样哪怕某一步出了问题,它也能基于新状态重新规划,而不是拿着一份过期的计划硬冲到底。

这种设计也带来一个新的调试习惯。以前脚本出问题,我们查的是“哪一步的选择器失效了”;现在出问题,我们查的是“模型在哪个节点误判了页面状态”。排查思路不同,工具也不同——这点我放到第四节细说。

3. 实操:从零跑通一个Midscene.js任务

3.1 环境准备:Node项目搭起来

Midscene.js运行在Node环境,本质上靠浏览器调试协议连接和控制浏览器。安装步骤很简单,只要你的机器有Node和Python基础环境之一就可以,前端和后端背景都能上手。

mkdir midscene-demo cd midscene-demo npm init -y npm install @midscene/web @midscene/core playwright

装完之后,要确认一下浏览器环境。如果你本机已有Chrome或Edge,可以直接让它复用;如果想完全独立,就用Playwright自带的浏览器包:

npx playwright install chromium

这步建议顺手做了,因为Playwright自带的Chromium跟脚本的兼容性最好,不会受你本机浏览器版本影响。

然后是模型配置。Midscene.js的核心是调用多模态大模型,所以需要配置模型接入信息。这里用的方式是通过环境变量指定API端点、模型名称和密钥:

export MIDSCENE_MODEL=你选用的模型名称 export MIDSCENE_API_KEY=你的API密钥

没有自己的密钥也没关系,社区很多玩法是接本地推理服务,或者用各家云服务的免费额度。选型的时候主要看三点:模型能不能传图片、上下文窗口够不够大、响应速度能不能忍。后面我单独讲模型选择。

3.2 第一个Demo:让AI去搜索商品并提取价格

环境准备好之后,写一个最简单的YAML任务文件。我建议第一次不要搞复杂任务,就拿一个购物或资讯网站练手,让AI完成“搜索关键词—提取列表结果”这两个动作就够了。

# demo.yaml tasks: - name: search and extract flow: - ai: 打开搜索页,在搜索框中输入“机械键盘”,然后按回车 - ai: 等待搜索结果加载完成 - ai: 提取前五个商品的名称和价格,输出为JSON数组 assert: - "页面标题包含机械键盘"

然后跑起来:

npx midscene run demo.yaml --browser chromium --headed

第一次运行我强烈建议加--headed带走界面模式。你能直接看到浏览器被AI“遥控”,光标跳动、页面滚动、输入文字,这个过程既直观又有助于理解“模型到底在干嘛”。等以后脚本稳定了,再改成--headless无头模式跑。

跑完之后,Midscene.js会在输出目录生成一份结果文件,包含每一步的执行记录、截图、模型输出的结构化数据。第一次看到这个输出的时候,你会明显感受到“写自动化脚本”这个事情的形态变了——你不太像是在调程序,更像是在给一个实习生下指令,然后检查他的作业。

3.3 关键配置和参数怎么选

几个我实测中影响很大的配置项,值得单独拎出来说。

模型选择。Midscene.js支持多种主流多模态模型,也包括一些本地部署的模型。选型逻辑我建议按任务复杂度来:

  • 简单任务,比如“点击某个明确按钮、读取固定表格”,用轻量模型就够,速度快、成本低。
  • 中等任务,比如“理解页面区域、识别商品卡片”,需要视觉能力较稳的模型。
  • 复杂任务,比如“多页面跳转、登录后提取数据、判断各种异常弹窗”,尽量用上下文窗口大、推理能力强的模型。

初始调试阶段,我建议先用能力强的模型把流程跑通,确认逻辑没问题后再逐步降级换成轻量模型,平衡成本。这个思路跟做传统自动化先保证功能再优化性能是一样的。

等待策略。页面加载快慢直接影响AI操作的成功率。Midscene.js提供了waitForNetworkIdle之类的等待参数,也可以直接在流程里插入sleep,比如:

- ai: 点击登录按钮 - sleep: 2000 - ai: 检查页面是否出现“用户中心”

我在实际项目里的习惯是:关键动作之后加一个sleep或者waitForNetworkIdle,但不要滥用——等待太久会拖慢整个链路,等待太短又容易在页面还没渲染完的时候让AI误判。一般像列表页、详情页这种动态加载较多的场景,等待2到3秒比较合适。

验收断言。这是我觉得整个工具里最被低估的功能。光让AI“做”还不够,还得让它“检查有没有做好”。Midscene.js支持在任务里写断言,例如:

assert: - "页面标题包含机械键盘" - "商品列表不为空"

如果断言失败,任务会直接标记为失败,方便接入CI或者定时任务。这个习惯我强烈建议从第一个Demo就养成——AI操作型脚本最后一定要有可验证的结果,否则它出错你都不知道。

3.4 进阶:登录、翻页、导出数据一气呵成

仅体验搜索太浅了,我实际用得比较多的场景是“登录—翻页—提取—导出”。下面是一个完整示例,我加了环境变量来避免敏感信息写死在脚本里:

# report.yaml tasks: - name: login and collect report flow: - ai: 打开系统首页,找到登录入口并点击 - ai: 在用户名输入框填入{{env.USERNAME}},在密码输入框填入{{env.PASSWORD}} - ai: 点击登录按钮 - sleep: 3000 - ai: 检查页面是否出现“工作台”字样,如果没有则重试登录 - ai: 进入“报表中心”菜单,选择“每日销售报表” - ai: 在报表页面中,找到“导出”按钮并点击 - sleep: 5000 - ai: 确认文件下载完成,提取页面提示信息 assert: - "页面包含导出的文件名"

执行时通过环境变量传入账号密码:

export USERNAME=demo_user export PASSWORD=demo_password npx midscene run report.yaml --browser chromium --headed

这个小案例里,最有价值的部分是“检查页面是否出现工作台”这步。登录类流程最怕的情况是登录失败但页面看着没报错,脚本还在傻傻地往后操作。加了一个语义检查后,AI如果发现状态不对,它会停下来或者重新尝试,而不是一条路走到黑。

登录成功后的操作也一样,模型会自己理解“报表中心”在菜单位置、“导出”按钮在哪个区域,不用你写选择器。这也是复用性最强的地方:换一个界面布局相似的后台系统,这个脚本稍作修改就能用,这在传统自动化里是难以想象的。

4. 跑AI操作浏览器,常见的坑和排查办法

4.1 模型输出的JSON格式不稳定,解析报错

实际跑任务时,最常遇到的异常就是“模型返回内容无法解析”。这多半不是Midscene.js的问题,而是模型在输出结构化数据时,偶尔会带多余的解释文字、或者JSON括号不完整、甚至截断在中间。

排查思路很直接:打开调试输出,看看模型到底返回了什么内容。如果发现是输出长度被截断,就把上下文窗口参数调大,或者把任务拆小一点,让单次请求的内容量降下来。Midscene.js会尽量做解析容错,但模型本身输出越规范,成功率越高。

我的习惯是:不在同一个任务里塞太多“提取”要求。比如要提取“名称、价格、销量、评论数、店铺名、发货地”,分两次任务做就比一次稳定得多。别把上下文撑得太满,留点余量给模型发挥。

4.2 AI定位不准,点错元素

这个坑也遇到过。视觉模型偶尔会把“登录”按钮旁边的“注册”按钮当成目标,或者把页面底部的推荐位当成真正的搜索结果。

遇到这种情况,首先看页面是不是太密集。如果页面上同时有几十个类似按钮,模型确实容易看花眼。解决办法是在指令里加限定条件,比如“点击右上角的登录按钮,而不是页面中的其他登录字样”。这种限定词在Midscene.js里特别好用,模型会结合DOM结构里的位置信息来区分。

另一个土办法是给关键元素制造“锚点”,比如在测试环境里给目标按钮加一个醒目的文案或用遮罩标出来,操作完成后去掉。这在传统自动化里还要改代码结构,在AI方案里只需要改一句描述词,省事很多。

4.3 页面加载慢,AI误以为没有内容

动态页面最坑的一点是,AI在页面还没完全加载的时候先截了图,模型判断“这个页面没有搜索框”,然后自作主张做了别的操作。

我的排查经验是两步走:第一,把等待时间调长,或者在关键步骤之前加waitForNetworkIdle;第二,在指令里明确告诉它“等待页面加载完成再操作”。比如:

- ai: 等待搜索结果区域出现商品卡片,再执行提取

这句话看着简单,但它能大幅减少因加载时序产生的误判。AI操作员的“眼睛”跟人一样,页面还在转圈的时候就跟它说“你看到什么”,它当然只能看到loading。

4.4 常见问题速查表

现象常见原因建议排查与解决
模型输出无法解析上下文过长、输出截断调大上下文限制,拆小任务范围
点击/输入位置不准页面元素密集、提示词不具体增加方位限定,用“右上角”“列表第一行”等描述
页面加载未完成导致误判等待策略不够增加waitForNetworkIdle或sleep
长任务跑到一半失败上下文累积太长、模型注意力偏移拆分成多个子任务顺序执行
登录步骤反复失败登录后页面状态判断缺失增加登录后的状态断言
浏览器卡死但屏幕显示正常页面有大量定时器或弹窗用--headless模式重试,或固定viewport尺寸

4.5 我实测下来最管用的几个稳定性技巧

第一,固定浏览器视口尺寸。不同分辨率下页面布局差异很大,AI视觉识别受布局影响明显。固定视口后,至少能保证自己机器上跑的成功率是可复现的。第二,把页面语言保持稳定,不要在脚本中途切换语言环境,否则按钮文案千变万化,视觉模型容易糊涂。第三,任务结尾一定要加“兜底断言”。我写AI操作型脚本,最后几乎总有一句:检查页面是否出现某个预期的成功标志,没有的话截图并标记失败。这句话看着微不足道,但实际能把失败率降低一大截,因为模型有明确目标去自查,而不是默默做完了事。

5. 选型与扩展:Midscene.js适合在什么场景用

5.1 它不是要取代传统框架,而是补上传统框架最弱的一环

很多人一看到AI自动化,就问“那Playwright、Puppeteer是不是要凉了”。我的看法完全不是这样。Midscene.js本身还是跑在浏览器控制协议之上的,它只是把“定位与操作决定”交给了模型,而底层依然要依赖成熟的浏览器自动化能力。

实际项目里更优的配合方式,是让传统脚本负责“确定性高”的部分,让AI负责“需要理解”的部分。比如批量数据入库、数据格式转换、固定接口调用,这些用传统脚本又快又稳;但页面结构频繁变化、需要视觉判断的UI自动化、动态数据的筛选提取,就交给Midscene.js。两者可以穿插:传统脚本跑常规流程,遇到需要临场判断的环节,调起Midscene.js处理。

5.2 目前我实际验证过的几类落地场景

回归测试:UI自动化回归测试最适合尝鲜。传统测试脚本维护成本高,AI操作员能够容忍页面小改动,而且测试用例用自然语言写,产品同学也能看懂。我试过把十几条回归用例翻译成YAML任务,跑了两周,大部分用例都没因为样式调整挂掉。

数据采集:遇到目标站点改DOM结构、增删class名这种常规爬虫“末日”,Midscene.js因为走视觉理解,影响往往很小。尤其适合采集需要登录、需要交互、内容动态加载的站点。当然,任何采集行为都要遵守目标站点的使用规范,这个边界自己把握好。

流程性RPA:如果日常工作里有大量“打开系统-填表-提交-导出”这类固定流程,而且系统界面常年不统一,AI操作员比传统RPA更省心。它的优势在于,哪怕系统的某个按钮位置变了,只要功能语义没变,AI还能找到。这在老旧的业务系统上特别有价值,那些系统里的样式和结构长期没人维护,传统选择器过两周就失效。

页面监控:让AI定时去看某个页面是否出现异常提示、价格变化、内容更新,并且直接把变化结构化输出。这种场景不需要高频轮询,做低频巡检反而更适合用AI驱动,因为成本可控、识别准确。

5.3 成本和性能怎么评估

用AI操作浏览器是有代价的,主要是模型调用成本。单次简单操作消耗的token量不大,复杂流程会成倍增长。我粗略算过一个中等复杂度的任务,跑一次可能要消耗几千到几万token不等,换算成费用大概在几分钱到几毛钱之间,取决于模型定价。这个成本结构跟传统脚本“免费执行”完全不同,但传统脚本的编写与维护成本是人力成本,两者要放在一起比才有意义。

性能方面,AI操作员肯定比传统脚本慢,因为它每一步都要“看图-思考-决策-执行”。一个传统脚本跑完只要几秒的流程,AI可能要花几十秒甚至几分钟。所以高频、简单、重复性操作,还是传统脚本合适;低频、复杂、需要理解的任务,才值得用AI。这不是谁替代谁的问题,是用在哪个环节的问题。

写在最后的一点体会

跑Midscene.js这段时间,我感受最深的一件事是,自动化的核心正在从“写代码”变成“写清楚需求”。以前我们调脚本、调选择器,本质上是在跟浏览器的DOM结构较劲;现在跟AI配合,反而更像是在训练一种表达方式——怎么说任务,它才能一次听懂。

有个小技巧我一直保留着:不管多复杂的流程,我都会在最后加一句“检查页面是否出现某某内容,如果没有,截图并标记失败”。这个兜底行为帮我省了大量排错时间。AI操作员绝不是永不犯错的神器,但它的出错方式和传统脚本完全不同——传统脚本错了是因为代码写得不对,AI错了往往是因为指令描述不够完整。把指令写清楚,它的稳定性会远超你的预期。

如果你想体验一下“让AI接管浏览器”的感觉,从今天写的第一个搜索Demo开始就行。先跑通,再慢慢加复杂流程,最后你会发现,浏览器自动化这件曾经很折腾的事,现在多了不少新的可能性。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询