1. 从两个真实场景说起:为什么"浏览器自动化"突然分成了两条路
去年下半年到现在,我陆续在三个不同类型的项目里用到了浏览器自动化:一个是帮运营团队做竞品价格监控,一个是给内部知识库做网页内容采集,还有一个是让大模型自己去填表单、点按钮完成一套审批流程。前两个项目我用的是 Playwright 那套传统思路,第三个项目我换成了 Browser-use。换完之后最大的感受不是"哪个更好",而是"这俩压根不是一回事"。
很多人第一次听到 Browser-use 和 Playwright-MCP 这两个词,会下意识觉得它们是竞品,是"新一代替代老一代"的关系。实际用下来你会发现,它们解决的是两个层次的问题。Playwright-MCP 本质上是把 Playwright 这个成熟的浏览器自动化库,通过 MCP(Model Context Protocol)协议暴露给大模型调用,让模型能"操作浏览器";而 Browser-use 是把"让大模型自主完成浏览器任务"这件事做成了一个完整的 Agent 框架,模型在里面不只是调用工具,还要自己规划步骤、看页面、做决策、纠错重试。
打个比方。Playwright-MCP 像是给大模型发了一套遥控器,每个按钮对应一个浏览器动作,模型按哪个键、按几下,得由外面的人(也就是你的代码逻辑或者上层 Agent)告诉它。Browser-use 则像是直接雇了一个会用浏览器的实习生,你只说"帮我把这个网站的商品价格整理成表格",他自己会打开页面、滚动、找元素、判断哪块是价格、遇到弹窗自己关掉,最后把结果交给你。
这个差别听起来抽象,但落到代码结构、调试方式、成本控制、稳定性处理上,差异非常具体。下面我按自己踩过的坑,一层层拆开讲。
2. 拆开看本质:一个是"工具协议层",一个是"任务执行层"
2.1 Playwright-MCP 到底做了什么
Playwright 本身是一个浏览器自动化库,支持 Chromium、Firefox、WebKit,能模拟点击、输入、截图、拦截网络请求等等。它的定位是"给开发者用的",你需要写代码明确告诉它每一步做什么。Playwright-MCP 做的事情,是在 Playwright 之上加了一层 MCP Server,把这些浏览器操作封装成一个个"工具"(tool),通过标准协议暴露出去。
大模型(或者任何支持 MCP 的客户端)连上这个 Server 之后,就能看到类似这样的工具列表:browser_navigate、browser_click、browser_type、browser_snapshot、browser_take_screenshot等等。模型决定调用哪个工具、传什么参数,Server 执行完把结果(通常是页面的可访问性树快照)返回给模型。
关键点在于:决策权在模型,但执行粒度非常细。模型要完成"登录并下单"这种任务,得自己拆成"打开登录页→找到用户名输入框→输入→找到密码框→输入→点登录→等待跳转→找到商品→点加入购物车→……"一长串工具调用。每一步它都要基于上一步返回的页面快照重新判断。
2.2 Browser-use 的定位完全不同
Browser-use 是一个 Python 库,核心是把"浏览器"包装成一个 Agent 可以操作的环境。你给它一个任务描述,它内部会用一个 LLM 做规划,配合一套专门设计的提示词和页面理解机制,让模型自己决定下一步动作。它内部其实也调用了 Playwright(底层还是那套浏览器控制),但它在上层做了大量封装:页面元素提取、可交互元素编号、历史动作记录、失败重试、多步规划。
换句话说,Browser-use 把"用大模型操作浏览器"这件事的最佳实践固化下来了。你不用自己设计提示词去教模型怎么读页面、怎么点元素,它已经帮你设计好了。你要做的是配置好模型、写好任务、必要时加一些自定义动作。
2.3 一张表看清两者的层次差异
| 维度 | Playwright-MCP | Browser-use |
|---|---|---|
| 本质 | 浏览器操作的 MCP 工具服务 | 浏览器任务 Agent 框架 |
| 决策主体 | 上层调用方(你的 Agent 或代码) | 框架内置的规划循环 |
| 执行粒度 | 单步操作(点击、输入、导航) | 任务级(给目标,自己拆步骤) |
| 页面理解 | 返回可访问性树,模型自己解析 | 内置元素提取与编号机制 |
| 适用场景 | 需要精确控制每一步的流程 | 目标明确但路径不确定的任务 |
| 调试方式 | 看工具调用日志 | 看 Agent 的思考与动作轨迹 |
| 底层依赖 | Playwright | Playwright(内部) |
这张表是我自己在选型时反复对照的。理解了这个层次差异,后面所有的取舍就顺了。
3. 页面理解机制:模型到底"看到"了什么
这是两者差别最容易被忽略、但实际影响最大的地方。大模型不能直接"看"网页,它只能读文本。所以浏览器自动化框架的核心难题之一,就是怎么把复杂的 DOM 树变成模型能理解、能定位的文本。
3.1 Playwright-MCP 的可访问性树快照
Playwright-MCP 默认返回的是页面的可访问性树(accessibility tree)快照。这个树是浏览器为辅助技术(比如屏幕阅读器)生成的结构化表示,包含了角色(role)、名称(name)、状态等信息。相比原始 HTML,它干净很多,去掉了大量样式和脚本噪音。
但问题也很明显。第一,可访问性树对某些动态组件、Canvas 渲染的内容、自定义组件支持不好,可能压根不出现。第二,快照可能非常长,一个复杂页面几千个节点,全塞给模型既费 token 又容易让模型迷失。第三,模型拿到快照后要自己推理"哪个节点是登录按钮",这个推理过程不稳定,同一个页面不同时候模型可能给出不同判断。
我实测过一个电商详情页,可访问性树快照大概有 8000 多 token。模型要在里面找到"加入购物车"按钮并点击,成功率大概七成,剩下三成会点错或者找不到。这个成功率在演示里够用,在生产里就是灾难。
3.2 Browser-use 的元素编号与视觉结合
Browser-use 的做法更工程化。它会提取页面上所有可交互元素(按钮、链接、输入框等),给每个元素编一个号,然后把"编号 + 元素描述"的列表给模型。模型要点击时,直接说"点击编号 12",框架再把这个编号映射回真实的 DOM 元素去执行。
这样做的好处是:模型不需要在几千个节点里找目标,只需要在一个精简的、带编号的列表里选。选择空间小了,准确率自然高。而且 Browser-use 支持结合截图做视觉理解,对于纯图标按钮、Canvas 内容这类可访问性树覆盖不到的场景,视觉信息能补上。
不过代价是元素提取本身可能出错。有些元素被遮挡、有些是动态生成的、有些点击区域和视觉区域不一致,提取逻辑需要不断调优。我在一个用了大量自定义下拉组件的后台系统里就遇到过,Browser-use 提取出来的元素编号和实际能点的位置对不上,得手动加自定义动作绕过。
3.3 这个差异对提示词设计的影响
用 Playwright-MCP 时,你往往需要在上层写比较复杂的提示词,教模型怎么读可访问性树、怎么定位元素、遇到歧义怎么办。这部分工作量和不确定性都不小。
用 Browser-use 时,提示词可以写得很"业务化",比如"去某网站搜索关键词 X,把前 10 条结果的标题和链接整理出来"。框架内部的提示词已经处理了页面理解的细节。你省下的精力可以放在任务描述和结果校验上。
我的经验是:如果你的任务页面结构稳定、元素有清晰的语义标签,Playwright-MCP 够用且可控;如果页面复杂、动态、或者你根本不想为每个网站写定位逻辑,Browser-use 的页面理解机制能省大量时间。
4. 控制流与错误恢复:谁来决定"下一步做什么"
4.1 Playwright-MCP 的控制流是外部的
用 Playwright-MCP 时,"下一步做什么"这个决策发生在模型侧,但整个循环是你自己搭的。典型结构是:你把工具列表给模型,模型返回一个工具调用,你执行,把结果喂回去,模型再返回下一个调用,如此循环直到模型说"完成了"。
这意味着错误恢复逻辑也得你自己写。比如点击失败了怎么办?页面加载超时怎么办?模型点错了元素怎么办?这些都需要你在循环里加判断。我一开始没做这层,结果模型点了一个不存在的按钮,工具返回错误,模型看到错误后又点了一次同样的按钮,死循环了。后来加了"连续两次相同动作就强制中断并重新截图"的逻辑才稳住。
4.2 Browser-use 内置了 Agent 循环
Browser-use 把整个"观察→思考→行动→再观察"的循环封装在框架里了。它内部维护了动作历史、当前页面状态、任务目标,每一轮让模型基于这些信息决定下一步。失败重试、动作去重、最大步数限制这些都有默认实现。
这带来的直接好处是开发速度快。我写第一个 Browser-use 任务时,从装库到跑通大概花了半小时。同样的任务用 Playwright-MCP 自己搭循环,我花了大半天,还得反复调提示词。
但内置循环也意味着可控性下降。框架怎么规划、怎么重试、什么时候放弃,你只能通过配置参数和自定义回调去影响,没法完全接管。遇到框架规划得不对的情况,调试起来比自己的循环要费劲,因为中间多了一层抽象。
4.3 错误恢复的实际对比
举个我真实遇到的场景:目标网站有个 cookie 同意弹窗,会遮挡页面。
用 Playwright-MCP 时,模型第一次截图看到了弹窗,但它没意识到那是个需要先关掉的障碍,直接去点后面的按钮,点不到。工具返回"元素不可点击",模型又试了一次,还是不行。我后来在提示词里加了一句"如果页面有弹窗或遮罩,先处理它们",情况才好转。这个"先处理障碍"的常识,得靠提示词补。
用 Browser-use 时,框架的规划提示词里已经包含了类似"注意页面上的弹窗、对话框、遮罩层,它们可能阻碍操作"的引导,模型第一轮就尝试关闭了弹窗。这个细节让我意识到,Browser-use 的价值很大一部分在于它把大量这类"操作浏览器的常识"沉淀进了提示词和流程里。
5. 选型决策:什么任务该用哪个
5.1 优先选 Playwright-MCP 的情况
- 流程高度确定:比如每天定时登录后台导出报表,步骤固定,不需要模型做太多判断。这时候用 Playwright-MCP 甚至直接用 Playwright 写死脚本更稳。
- 需要精确控制:涉及金额、权限、不可逆操作时,你希望每一步都在掌控中,不希望模型"自作主张"。
- 已有 Agent 框架:你已经在用某个支持 MCP 的 Agent 平台,加一个浏览器工具就能用,没必要再引入一套 Agent 框架。
- 调试要求高:出问题时你想精确知道是哪一步、哪个工具调用出的错。
5.2 优先选 Browser-use 的情况
- 任务目标明确但路径不确定:比如"帮我在这个网站找到最便宜的某商品并加购",路径取决于网站结构,写死脚本不现实。
- 要覆盖多个结构不同的网站:为每个网站写定位逻辑成本太高,让模型自己适应更划算。
- 快速验证想法:想快速试一个"让 AI 自己上网办事"的点子,Browser-use 上手最快。
- 页面动态复杂:大量 JS 渲染、自定义组件、频繁变化的页面,Browser-use 的页面理解机制更有优势。
5.3 一个容易被忽略的混合思路
其实这两者不是非此即彼。我后来在一个项目里就混用了:用 Browser-use 做整体的任务规划和页面理解,但在几个关键的高风险步骤(比如最终提交订单)上,注册了自定义动作,内部用 Playwright 精确执行。这样既享受了 Agent 的灵活性,又在关键节点保住了可控性。
Browser-use 支持自定义工具和动作,Playwright-MCP 也可以被更上层的 Agent 调用。理解它们的层次差异后,组合使用是很自然的选择。
6. 实操中踩过的坑与调优心得
6.1 Token 消耗:比想象中烧得快
浏览器自动化的 token 消耗主要来自页面快照。一个中等复杂度的页面,快照动辄几千 token,一个任务跑十几步,加上历史记录,很容易上万 token。如果用 GPT-4 级别的模型,一个任务几毛到几块钱很正常。
我的优化做法:第一,尽量用支持长上下文但单价低的模型做页面理解,关键决策再用强模型;第二,Browser-use 里可以配置只提取可交互元素而不是全页面,能显著减少 token;第三,Playwright-MCP 场景下,可以在返回快照前做裁剪,只保留视口内或相关区域的元素。
6.2 等待与超时:别用固定 sleep
新手最容易犯的错是到处写sleep(3)。页面加载速度受网络、服务器、渲染复杂度影响,固定等待要么不够要么浪费。Playwright 提供了wait_for_selector、wait_for_load_state这类基于条件的等待,Browser-use 内部也做了智能等待。能用条件等待就别用固定 sleep,这是稳定性的基础。
6.3 元素定位的脆弱性
不管用哪个方案,元素定位都是最脆的一环。网站改个 class 名、调个布局,定位就可能失效。我的经验是:优先用语义化的定位方式(role、label、文本内容),少依赖 CSS 路径和 XPath 索引。Browser-use 的元素编号机制在这方面天然有优势,因为它每次都是重新提取的,对布局变化容忍度更高。
6.4 反自动化检测
很多网站会检测自动化行为,比如检查navigator.webdriver、鼠标移动轨迹、点击间隔等。这不是本文重点,但要知道这个现实:你跑得好好的脚本,可能某天突然就被拦了。应对方式包括使用更真实的浏览器上下文配置、模拟人类操作节奏等。这块水很深,建议先确认目标网站的政策再动手。
6.5 结果校验不能省
让模型自己跑任务,最怕的是它"以为"自己完成了,实际结果不对。我现在的习惯是,任务结束后一定要有独立的校验步骤:要么用代码检查关键结果(比如表格行数、金额范围),要么让另一个模型做结果审查。别完全信任 Agent 的"我完成了"。
7. 写在最后:我现在的默认选择
如果非要给一个默认建议:做产品、要稳定、流程确定,从 Playwright-MCP 或直接用 Playwright 起步;做探索、要灵活、任务开放,从 Browser-use 起步。但更重要的是理解它们所处的层次不同,别把它们当成互斥的竞品。
我自己现在的做法是,先用 Browser-use 快速把任务跑通,观察模型实际是怎么完成任务的,把它的动作轨迹记录下来。如果发现某几步特别稳定、特别关键,就把这几步抽出来用 Playwright 固化。这样既保留了灵活性,又逐步把稳定性提上来。这个"先跑通再固化"的路径,比一上来就纠结选哪个框架要务实得多。
浏览器自动化加了大模型之后,能力边界确实被推开了,但工程上的坑一个没少。工具选对了只是开始,真正决定成败的还是对页面、对模型行为、对错误处理的理解。这些只能靠一个个任务跑出来。