☰
Playwright与Selenium全面对比:自动化测试框架选型指南
2026/10/21 8:35:10 网站建设 项目流程

做自动化测试这么多年,几乎每隔一段时间就会有人问我同一个问题:"你用的是 Playwright 还是 Selenium?"这个问题背后,往往是正在做技术选型的测试负责人,或者准备从老框架迁移到新方案的团队。Playwright 和 Selenium 确实是当前自动化测试领域两个绕不开的主流工具,一个是过去十几年的事实标准,一个是近几年热度飙升的后起之秀,各有各的忠实用户,也各有各的适用场景。这篇内容不打算站队,只想从实际使用的角度,把两者的架构思路、编码体验、高频场景实操和典型坑位都拉出来晒一晒,给正在纠结的朋友一个尽量客观的参考。

1. 为什么自动化测试选型总绕不开这两个工具

1.1 Selenium 的江湖地位如何确立

Selenium 可以说是浏览器自动化领域的老前辈了。它早期通过 JavaScript 注入的方式控制浏览器,后来随着 WebDriver 项目逐渐成熟,形成了我们现在熟悉的这套客户端通信协议。这套协议后来还被 W3C 制定为技术标准,也就是说,Selenium 的架构思路直接影响了一整代自动化测试工具的设计。很多浏览器原生支持这套协议,这是它能够持续流行这么多年的底层原因。

在我的实际工作中,Selenium 最让我服气的一点是它的"全面"。它支持 Java、Python、C#、Ruby、JavaScript 等多种主流语言,测试用例写起来几乎没有语言门槛;浏览器覆盖面也广,不管你是用哪家浏览器,基本都能找到对应的驱动方案。很多企业级测试平台、自动化框架,底层跑的依然是 Selenium,这套生态沉淀了十几年,案例和踩坑记录多到你看不完。

1.2 Playwright 凭什么后来居上

Playwright 是近几年才火起来的后起之秀,但它不是简单地"重新写一个 Selenium",而是基于浏览器调试协议直接和浏览器内核通信。这个设计上的先天优势,让它从一开始就拥有了网络拦截、设备模拟、视频录制等 WebDriver 协议很难表达的能力。加上它默认自带浏览器内核管理机制,不需要单独维护驱动版本,很多团队从 Selenium 迁移到 Playwright 之后,第一感受就是"环境搭建原来可以这么省心"。

我自己第一次用 Playwright 的时候,体验上的反差非常大。之前写 Selenium 用例,光是把驱动和浏览器版本对齐就要折腾半天,而 Playwright 只需要执行一条安装命令,测试浏览器内核全部下载好,连路径都不用管。尤其是跑 CI 的时候,新环境从零到能执行第一条用例的时间,Playwright 比 Selenium 快了一倍不止。

1.3 选型纠结的本质

真正让团队纠结的,其实不是"哪个工具更强",而是"哪个更适合自己的现状"。如果你维护的是一套跑了很多年的 Selenium 测试资产,里面有几千条用例,那迁移成本就是实打实的门槛;如果你是从零搭建一套自动化测试体系,那选哪个更多取决于团队技术栈、被测系统的浏览器矩阵,以及你们最看重的测试能力方向。社区里经常把两者的对比做成特性表格,但表格之外还有两个容易被忽略的因素:团队长期维护这套框架的能力,以及被测系统本身的真实复杂度。

2. 从底层架构看方案差异:WebDriver 协议与调试协议谁更适合你

2.1 Selenium 的通信链路

理解 Selenium 的工作方式,关键要看它的通信链路。你的测试脚本和浏览器之间,其实隔着一个 WebDriver 服务。客户端库通过 HTTP 请求把操作指令发给这个服务,服务再把指令转译给浏览器,这样一个三层结构意味着每次操作都要走一次额外通信。本地执行时延迟几乎可以忽略,但跑大规模用例,或者在分布式环境的执行节点上调度时,这个通信开销就会慢慢累积出来。

早期用 Selenium 跑用例时,我最头疼的问题就是驱动版本和浏览器版本严格绑定。浏览器只要一升级,对应驱动匹配不上,整个测试环境可能瞬间瘫痪。虽然现在很多工具链都实现了驱动下载自动化,但"要单独维护一个驱动文件"这件事,始终是 Selenium 使用体验里绕不开的一个门槛。

2.2 Playwright 的直连机制

Playwright 走的是另一条技术路线。它基于浏览器自身的调试协议,通过 WebSocket 和浏览器建立双向连接,相当于把开发者工具的能力直接暴露给了测试脚本。这意味着它可以调用浏览器内部更底层的能力,比如拦截网络请求、执行 JavaScript、模拟设备环境等。很多操作对 Selenium 来说要么做不到,要么做起来非常别扭,但在 Playwright 里就是内置的基础能力。

另外一个体验上的巨大差异是浏览器上下文的隔离机制。Playwright 默认给每个测试启动一个独立的浏览器上下文,相当于一个轻量的独立浏览器实例,测试用例之间几乎不会互相污染。这让用例并行执行变得非常简单,不需要像 Selenium 那样反复处理 session 和浏览器窗口的共享状态问题。我在一个项目里用 Playwright 并行跑了 20 条用例,稳定性比之前 Selenium 顺序执行还高。

2.3 架构差异落到实际体验上

架构差异最终体现在三个可感知的方面。第一是速度,Playwright 的指令链路更短,操作执行更紧凑,在长流程用例里体感更快;第二是能力边界,能用调试协议直连,网络 Mock、trace 录制、关键帧截图这些功能才得以实现,Selenium 在这些场景下基本要靠外部工具补位;第三是调试体验,Playwright 的 trace 文件可以完整回放执行过程,哪一步元素状态不对一目了然,而 Selenium 通常只能依靠截图和日志去反推问题。

不过这里我必须替 Selenium 说句公道话:WebDriver 协议是标准化产物,兼容性认证体系更成熟,对一些特殊浏览器、旧版本浏览器、甚至企业内定制浏览器的适配,Selenium 的积累明显更深厚。选择方案不能只看谁的技术更新,而是要看你被测系统的浏览器矩阵到底长什么样。如果你的系统必须要兼容某些老旧的浏览器版本,Playwright 的新架构反而可能帮不上忙。

3. 实际体验硬碰硬:从环境搭建到元素定位,差距到底在哪

3.1 环境搭建:一个要手动驱动,一个自带内核管理

先看最常见的第一步。Selenium 的传统搭建流程是:安装浏览器、安装客户端库、单独下载驱动、配置环境变量。我第一次走这套流程的时候大概折腾了小半天,大量的时间都花在"找驱动版本和浏览器版本的对应关系"上。后来我依赖自动化驱动管理工具,体验才稍微好一些,但对新手来说,这个心智负担依然是第一道门槛。

Playwright 在这一点上做得相当干脆。安装库之后执行一条命令,测试用浏览器内核自动下载完毕,不需要关心驱动版本、不需要配置 PATH、不需要手动管理任何文件。而且它管理的是经过测试验证的固定内核版本,不会因为本地浏览器升级而导致用例突然崩溃。对于团队协作场景,这意味着新同事拉下代码后,基本上十分钟内就能把本地自动化环境跑起来。

这里我把两个工具的环境搭建步骤做个对比,方便你直接参考:

  • Selenium 流程:安装浏览器、安装语言库、下载驱动、配置环境变量、启动 WebDriver 服务
  • Playwright 流程:安装语言库、执行浏览器安装命令、运行脚本

单从这个流程对比就能看出设计思路的差别:Selenium 把环境控制权留给用户,Playwright 则把环境标准化包办到位。对于不想在环境维护上花太多精力的团队,Playwright 体验显然更省心。

3.2 元素定位与等待策略:代码噪声的差距

元素定位是所有 UI 自动化新手的第一道关卡。Selenium 提供了经典的八种定位方式,包括 ID、Name、Class、标签名、链接文本、部分链接文本、XPath、CSS 选择器,灵活度上限很高,但很多定位表达式要靠经验去调整。尤其是 XPath,如果写得太依赖页面结构,前端一调整用例就跟着崩。

Playwright 引入了"定位器"(Locator)的概念,它会自动等待元素出现、可见、可交互,不需要在操作前手动塞各种等待逻辑。很多从 Selenium 转过来的同事都有一个共同感受:代码里的等待语法噪声几乎消失了,脚本读起来清爽很多。实现同样一个"等待按钮出现再点击"的操作,两个工具的代码风格差异非常直观。

比如下面这段经典的 Selenium 写法:

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() driver.get("https://example.com") wait = WebDriverWait(driver, 10) element = wait.until(EC.element_to_be_clickable((By.ID, "submit"))) element.click()

而 Playwright 的等价代码是:

from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch() page = browser.new_page() page.goto("https://example.com") page.locator("#submit").click()

从代码量上就能看出来,Selenium 的大部分工作不是在描述"测试动作",而是在处理"等待元素可用"这件事。Playwright 把自动等待内置到定位机制里,表面上是语法简化,本质上是对测试稳定性的一种重新思考。

3.3 定位器的生命周期设计差异

除了等待策略,定位器的生命周期设计也是个关键差异。Selenium 里获取到的 WebElement 类似一个"实时快照",页面一旦刷新,之前的元素引用就失效了,再操作会直接抛出异常。这在写长流程用例时特别烦人,往往要频繁重新获取元素引用,一不小心就让整个用例变得很脆。

Playwright 的定位器则更像一个"查询条件",每次操作时都会重新执行查询逻辑,所以不存在"元素引用过期"的概念。这意味着你可以先定义一个定位器,经过若干步骤后依然可以直接使用,代码写起来更稳定,也更符合人的直觉。这一点在实际项目里的价值非常大,尤其是那种需要登录、跳转、返回的复杂业务流程测试。

3.4 多语言与生态支持现状

两个工具在语言支持上有一个明显差别:Selenium 支持的官方语言更全,Java、Python、C#、Ruby、JavaScript 都有一视同仁的维护力度;Playwright 目前官方提供 TypeScript、JavaScript、Python、Java 和 .NET 版本,其中 TypeScript 和 JavaScript 的体验最原生,Java 和 .NET 的功能更新会稍微慢半拍,但核心能力都是完整的。

如果你的测试工程栈主要用 Java 和 TestNG,Selenium 的资料和经验参考会明显更多;如果你的团队是前端背景,擅长 TypeScript,那 Playwright 的设计思维会更亲切,因为定位器、断言、选择器这些概念和前端开发的心智模型几乎没有冲突。选型时可以把这个维度纳入考量,不要只看单条命令的写法,要看团队日常写代码的顺手程度。

4. 高频场景实操对照:多标签页、网络 Mock、移动端模拟与调试追踪

4.1 多标签页与多窗口处理

多标签页操作是我实际工作中碰到频率最高的需求之一,尤其是电商、金融、后台管理这类系统,经常出现"点击按钮跳出新页面,填写完再回到原页面继续"的流程。Selenium 的标准做法是通过窗口句柄切换,需要先拿到window_handles列表,再用switch_to.window切过去。逻辑不复杂,但句柄的顺序有时候并不稳定,尤其是多个窗口陆续打开时,你得自己处理轮询等待,代码很容易变得冗长。

Playwright 的思路完全是另一套:每一个新页面都是一个独立的 Page 对象,通过监听popup事件就能拿到新页面的引用,然后直接在这个页面上操作,不需要句柄、不需要来回切换,几个页面之间的状态互不干扰。我做"新页面下单再回到原页面核对订单号"这类用例时,Playwright 的代码顺滑程度真的让人舒服,省掉了大量窗口切换的样板代码。

4.2 网络请求拦截与 Mock

对绝大多数测试团队来说,UI 自动化的稳定性瓶颈往往不在前端,而在外部接口的波动。原来的依赖方接口不稳定,你的用例毫无办法地跟着失败。Selenium 在网络层基本没有内置能力,常规做法是借助抓包代理工具或者在自己被测系统里加测试开关注入 Mock 数据,侵入性强,配置也复杂。

Playwright 则原生支持page.route()方法拦截网络请求。你可以 mock 接口返回、人为制造请求延迟、模拟异常状态码,甚至替换静态资源。举个例子,你想验证"当积分系统返回 500 时,页面是否展示降级文案",在 Playwright 里只需要拦截对应的接口并返回 500 状态码即可,整个测试完全不需要依赖任何外部服务。这种能力对于异常场景和边界情况的自动化覆盖,是一次质的提升。

4.3 移动端模拟

移动端适配测试以前要么依赖模拟器,要么依赖真机,环境成本一直不低。Selenium 可以通过修改浏览器标识来模拟移动端 UA,但触摸手势、视口尺寸、设备像素比这些参数的覆盖力度有限,模拟效果比较粗糙。用它做基础冒烟还可以,做精细化适配验证就力不从心了。

Playwright 把设备模拟直接做成了内置能力,你只需要指定设备描述符,比如某个主流手机型号,系统会自动把所有相关参数设置好,包括用户代理、视口、触摸能力、定位、时区等。我负责过一个内嵌页适配项目,用一个 Playwright 脚本在多个设备描述符之间轮换跑布局验证,覆盖率比之前用 Selenium 加真机配合的方案高了不少,执行时间反而缩短了。

可以看一下大概的写法:

from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch() context = browser.new_context( viewport={"width": 390, "height": 844}, user_agent="Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X)", device_scale_factor=3, is_mobile=True, has_touch=True, ) page = context.new_page() page.goto("https://example.com")

虽然 Selenium 也能通过参数设置实现部分效果,但 Playwright 把这些参数集中封装成设备描述符,直接省去了手工拼参数的麻烦,也更不容易漏项。

4.4 截图、录制与视觉回归

截图功能两个工具都有,但细节落差相当大。Selenium 的原生截图只支持当前可视区域,想要完整长截图就得自己写拼接逻辑,或者依赖第三方库。Playwright 原生支持整页截图、元素级截图、自动视频录制,甚至能生成包含完整执行步骤的 trace 文件,排查问题时像在看一段操作回放。

有一次我排查 CI 上的偶发失败,Selenium 时代只能靠最后一张截图硬猜,效率很低。换成 Playwright 之后,直接把 trace 文件拖进查看器,每个操作步骤的前后状态都清晰可见,几步之内就定位到了问题所在。可以说,调试工具链的成熟度,已经成了衡量一个自动化测试框架好不好用的重要维度,而 Playwright 在这个方面确实是碾压性的优势。

4.5 并行执行与资源效率

最后再聊一个容易被忽略但直接影响工程效率的点:用例并行执行。Selenium 的浏览器会话之间隔离性弱,并行跑用例时要么自己写多进程管理,要么依赖发布系统对多 session 的支持,稍不注意就会互相干扰。Playwright 的浏览器上下文机制自带隔离能力,并行跑用例几乎不用写额外代码,直接把测试拆分到多个 worker 里执行就行。

不过并行带来的代价是内存占用。Playwright 每个浏览器上下文都会占用不少资源,并行数量拉满时,对 CI 机器的内存要求比 Selenium 高不少。我自己的经验是,不要一味追求最高并行度,先根据单条用例的内存峰值估算好 worker 数量,否则很容易把 CI 节点压爆。这个参数需要结合你的测试体量去调,并不存在一个放之四海皆准的固定值。

5. 踩坑实录:这两个工具各自的问题与排查方案

5.1 Selenium 的经典坑位

第一个经典坑是元素引用过期。页面一旦刷新或者跳转,之前拿到的 WebElement 对象就失效了,再操作时直接抛StaleElementReferenceException,你只能重新定位元素。这个坑在长流程用例里特别常见,几乎每几步都要注意重新获取引用,代码写起来很啰嗦。

第二个坑是点击被遮挡。页面上如果存在弹窗、悬浮层或者 Loading 遮罩,元素明明已经存在,但点击时会报元素不可交互。Selenium 没有默认的兜底处理机制,你只能自己写等待、判断、重试的逻辑,这块代码很容易成为整个测试套件里最脆弱的部分。

第三个坑就是之前反复提到的驱动兼容问题。社区里流传着一种说法:浏览器自动升级了,周一上班用例全红,第一件事不是修代码而是重新下载驱动。这种事只要经历过一次,就会理解为什么现在很多团队会对"自动管理浏览器内核"的能力这么看重。

5.2 Playwright 的典型坑位

Playwright 虽然现代,但坑也没少踩。第一个典型问题是定位器匹配到多个元素时报strict mode violation。这个设计是为了防止你对错误节点执行操作,但当你面对的页面有大量动态渲染节点时,选择器就必须写得非常精确。写了几百条用例之后你会发现,Playwright 对定位表达式的严谨度要求比 Selenium 高很多,前期定位策略没想清楚,后期改选择的成本不低。

第二个坑是内存占用偏高。刚才提到过,浏览器上下文的隔离设计虽然带来了并行优势,但内存消耗确实大,尤其是多 worker 并行时对 CI 节点的压力相当明显。我见过有团队在 4 核 8G 的机器上直接跑 16 个 worker,结果 OOM 崩掉。后来我们把 worker 数降到 8 并复用上下文,才稳定下来。这里一定要结合自己的机器配置做好压测,再定并行参数。

第三个坑是生态相对年轻。虽然它这几年增长飞快,但如果你的问题足够冷门,搜到的现成方案可能没有 Selenium 那么丰富。好在这几年官方文档已经做得非常完善,GitHub issue 的响应速度也快,大多数问题都能在讨论区找到线索,不至于卡死。

5.3 问题速查对照表

把两个工具在实际使用中容易遇到的问题放在一起对看,会更清楚一些:

问题类型Selenium 表现Playwright 表现
元素引用过期刷新后抛异常,需重新定位定位器每次重新查询,基本不会出现
点击被遮挡需要手动编写等待重试自动等待可交互状态,少数拦截可加重试
浏览器升级驱动不匹配导致环境损坏自带内核管理,版本可控
多标签页切换句柄繁琐且顺序不稳直接操作 Page 对象,简洁直观
网络 Mock依赖外部代理或系统改造原生 route 拦截
调试追踪只有截图和日志trace 回放加视频录制
并行资源占用相对较低并行能力强但内存偏高
社区问答资源案例积累深厚增长快,冷门问题资料略少

5.4 面向不同团队的选型建议

如果你是一个历史包袱比较重的团队,现有测试资产全跑在 Selenium 上,被测系统的浏览器矩阵里又有不少旧版本浏览器,那么迁移的驱动力其实不强。与其冒着迁移风险,不如把精力放在规范现有的等待策略和定位表达式上,让用例更稳定,这套方案依然可以长期支撑业务。

如果你是从零开始搭建测试体系,团队主要用 TypeScript,或者特别看重网络 Mock、多标签页、视频追溯这类现代测试能力,那 Playwright 值得认真评估。还有一个常被忽略的维度是团队招聘:Selenium 毕竟积累多年,招人容易得多;Playwright 人才相对稀缺,但一旦招到了有实战经验的人,框架维护和用例编写效率提升会非常明显。我的建议是别把选型当成一锤子买卖,先找一个中等复杂度的核心业务模块做两周试跑,让团队成员都实际动手写一写,用真实数据说话。

最后再说点个人感受。我在两个工具上都踩过不少坑,也见过一些团队因为选型反复横跳浪费了大量时间。说到底,工具之争的本质不是谁更先进,而是哪个更适合你的被测系统、你的团队技能和你的长期维护成本。Selenium 用得好,照样能稳定支撑大型复杂项目;Playwright 上手快,遇到特别诡异的动态页面也一样要花精力调。如果你时间有限,我的建议很朴素:拿一条真实的核心业务用例,在两个工具里各写一遍,连续跑二十次,看谁更稳、谁更快、谁更好维护。代码自己会说话,数据永远比争论更有说服力。

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

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

立即咨询