告别Selenium痛点:这8款自动化工具让你省心不止一点
2026/9/5 1:46:12 网站建设 项目流程

先说一个我自己的真实体验:有段时间我维护的 Selenium 脚本比业务代码还多。每次跑回归,第一件事不是看测试结果,而是去改find_element的等待条件和switch_to逻辑。页面稍作改版,脚本就碎成一片。后来我陆续试了 8 款自动化工具,才意识到大部分痛点根本不是“脚本水平不够”,而是 Selenium 这套架构和心智模型已经跟不上现在网页的动态渲染节奏。如果你也写过 Selenium 脚本,用过 WebDriverWait,被 element not interactable 折磨过,这篇文章会很对你的胃口。

这里推荐的 8 款 Selenium 替代工具,覆盖了编程型、低代码型、以及图形识别型三条路线。你可能是测试工程师,想替团队找一个更好维护的自动化测试框架;也可能是爬虫开发者,想跳出 Selenium 的高脆性去采集动态页面;还可能是只是想把日常重复的网页操作变成脚本的普通用户。不同的人适合不同的工具,我会把每款工具的适用场景、实测感受、踩坑点都讲清楚,方便你直接用起来。

1. 先搞明白:Selenium 脚本到底“低效”在哪里

1.1 写测试脚本最心累的几个瞬间

Selenium 本身是一个很成熟的 WebDriver 协议实现,它最大的价值在于把浏览器操作标准化,让 Python、Java、C# 这些语言都能通过同一套 API 去驱动 Chrome、Firefox、Edge。但也正因为太“通用”,它对脚本编写者的要求相当高。最常见的低效是等待条件:动态页面里元素不是同时出现的,你往往需要在关键步骤前写WebDriverWait(driver, 10).until(EC.presence_of_element_located(...))。一次两次还好,脚本一多,几乎每一行核心操作前都要加等待,代码瞬间变成一堆模板嵌套。

另一个让人崩溃的地方是定位策略。Selenium 时代的经典写法是driver.find_element_by_xpath,为了精确定位,很多人直接复制浏览器里的完整 XPath。结果就是元素层级一变,脚本就死。加上 iframe、多标签页、shadow DOM 这些现代前端特性,每一步都是额外的switch_to和上下文切换成本。写脚本原本是为了省时间,结果大部分时间都花在了“让脚本能跑起来”上。

还有一点容易被忽略:Selenium 本身不自带浏览器,你必须自己维护 Chromedriver、Geckodriver 这类驱动。浏览器升级后驱动版本不匹配,CI 环境里裸奔的机器动不动就报 session not created。这个问题虽然可以用 WebDriverManager 缓解,但它只是把“手工下驱动”变成了“依赖拉驱动”,并没有真正消除驱动这层脆弱性。

1.2 新一代替代工具的共性:把“等浏览器”交给工具

我推荐的这 8 款工具,多多少少都在解决上面那几类问题。它们的共性是:默认自动等待、自带浏览器管理、调试体验更好。比如 Playwright 和 Cypress,元素操作之前会自动等待元素可见、可点击,不需要你再写一堆 expected condition;Puppeteer 通过 Chrome DevTools 协议直接跟浏览器内核通信,绕开了 WebDriver 的会话模型;TestCafe 甚至不需要浏览器驱动,启动时会自己读取本机浏览器并注入控制脚本。

更关键的是,这些工具把“用户操作意图”变成了一等公民。你不需要关心底层是 XPath 还是 CSS,只需要告诉工具“登录按钮,点一下”;也不需要自己处理页面跳转带来的导航等待,因为工具知道点击后可能发生导航,会内部自动等待。这种设计思路带来的直接收益就是:脚本更短,稳定性更高,阅读起来也更接近自然语言。这正是项目标题里说的“更省事”。

2. 先看清分类再选型,避免“为了替换而替换”

2.1 按代码量分为三大流派

不是所有场景都需要写一堆代码。从实战角度,我建议把 8 款工具分成三个流派。第一派是编程型工具,代表是 Playwright、Puppeteer、Cypress、WebdriverIO、TestCafe、Taiko,它们适合有编程基础的人和需要深度定制的场景。第二派是低代码/无代码工具,代表是 Automa,适合 Quick Task 和普通办公人员。第三派是图像识别工具,代表是 AirTest,它面向的是 Android、Windows、游戏这类不方便拿到 DOM 树的场景。

很多人一听到“Selenium 替代”就下意识在 Playwright 和 Cypress 之间二选一,其实没必要。如果公司已有的安全合规、发布流程深度绑定 Selenium Grid,你可以用 WebdriverIO 继续跑 WebDriver 协议,但换来更好的开发体验。如果你做的事情是“每天定时在网页上抓几张报表”,用 Automa 拖拽几下就行,不需要进入 Node.js/Python 的世界。选型前先把要解决的问题写清楚,否则容易从一个坑跳到另一个坑。

2.2 按落地场景确认优先级

我这里给出一张可以照抄的场景对照表,后面每个小节的细节都会围绕它展开。做 Web UI 自动化回归测试,首选 Playwright 或 Cypress;爬动态网页但页面交互复杂,首选 Playwright;只需要 Chrome 且想写尽量少的代码,Puppeteer 足够;已有 Selenium Grid 资产或团队以 Java 为主,WebdriverIO 比 Selenium 原生更友好;想完全不碰驱动配置,TestCafe 最无感;想要测试脚本像黑盒用户操作一样好读,Taiko 值得试;手机 App、游戏、设备老化测试这类非浏览器对象,AirTest 是更合适的答案;只想给自己省点重复点击,Automa 一个浏览器扩展就能搞定。

场景首选备选主要原因
Web 自动化测试PlaywrightCypress / TestCafe自动等待稳定,多浏览器覆盖
动态页面爬虫PlaywrightPuppeteer可拦截网络请求,等待机制强
前端快速回归CypressPlaywright实时刷新和调试体验极好
兼容现有 GridWebdriverIOSelenium 4保持 WebDriver,封装现代
无驱动开箱即用TestCafePlaywright不需要安装浏览器驱动
黑盒用户式测试TaikoCypressAPI 贴近自然语言
游戏/设备老化AirTest基于图像识别,拿不到 DOM
零代码日常自动化AutomaAirTest拖拽块即可,扩展轻量

3. 编程型首选:Playwright、Puppeteer、Cypress 详细拆解

3.1 Playwright:目前最接近“写完就能稳定跑”的工具

Playwright 是微软开源的工具,支持 Chromium、Firefox、WebKit 三种内核,Python 和 JavaScript/TypeScript 都有官方 SDK。它最大的卖点是“自动等待”。比如你用page.click(),它会先等元素出现在 DOM 里,再等元素可见、稳定、接收事件,一套流程内置完成,不再需要显式 sleep 或 WebDriverWait。这种等待不是简单轮询,而是基于浏览器内部的事件驱动,效率比 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/login") username = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "username")) ) username.send_keys("demo") password = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "password")) ) password.send_keys("123456") driver.find_element(By.ID, "submit").click() driver.quit()

同样的用例,用 Playwright 写出来会短一截:

from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=False) page = browser.new_page() page.goto("https://example.com/login") page.fill("#username", "demo") page.fill("#password", "123456") page.click("#submit") browser.close()

从上手体验看,Playwright 也更省心:安装后执行playwright install就能自动下载匹配的内核版本,不再需要担心 Chromedriver 和 Chrome 版本不一致。它在多标签页、iframe、下载文件、网络请求拦截这些场景下都提供了高级 API。比如拦截图片请求可以用page.route,这在网页爬虫里非常实用,能让脚本关掉无用的图片资源,大幅提升采集速度。我在实际项目里用 Playwright 重写了一套老 Selenium 回归用例,用例数量从 120 个减少到 90 个左右,因为原来的很多前置等待步骤都直接删掉了,而通过率反而从 85% 提到了 98% 左右。

如果非要说 Playwright 的缺点:它对测试报告的集成不像 Cypress 那么“开箱即美”,需要自己搭 HTML report 或接入 Allure。另外,它的 API 设计是 event-driven 风格,初次接触的人容易搞混sync_playwrightasync_playwright两种模式。不过这些都只是学习成本,不是硬伤。我遇到过最坑的是在企业内部网络环境下运行playwright install时,浏览器二进制包下载被网络策略挡掉,解决办法是把下载地址换成内网镜像,或者手动放置浏览器到指定缓存目录。

3.2 Puppeteer:只在 Chromium 生态里干活时最轻量

Puppeteer 是 Chrome DevTools 团队出品的 Node.js 库,通过 DevTools Protocol 控制浏览器。它并不像 Selenium 那样支持各厂商浏览器,主战场就是 Chromium 系。好处是协议非常底层,浏览器能力几乎全量暴露,性能开销也小。如果你要做批量截图、PDF 生成、预渲染、抓取 SPA 页面数据,Puppeteer 往往是比 Selenium 更刀刃向内的选择。

Puppeteer 的代码风格和 Playwright 有相似之处,但更依赖 Node.js 的事件循环。下面是登录示例:

const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); await page.goto('https://example.com/login'); await page.type('#username', 'demo'); await page.type('#password', '123456'); await Promise.all([ page.waitForNavigation(), page.click('#submit') ]); await page.screenshot({ path: 'after-login.png' }); await browser.close(); })();

这里有个小技巧:点击按钮触发页面跳转时,最好把waitForNavigationclick放在同一个Promise.all里,避免点击之后的竞态。Selenium 时代很多人会直接加 sleep,但在 Puppeteer 里用导航等待事件更优雅。Puppeteer 还提供了page.waitForSelectorpage.waitForResponse等细粒度等待,比固定 sleep 可靠得多。

Puppeteer 的局限是:如果你需要覆盖 Firefox、Safari,它并不合适。同时因为协议是 Deep Link 到 Chromium,某些企业定制浏览器的兼容性也需要额外验证。我自己的实践建议是:爬虫和截图任务优先上 Puppeteer,因为它生态里的puppeteer-cluster这类并发库很成熟,能轻松实现带并发控制的批量抓取;但如果是跨浏览器自动化测试,还是把重心放回 Playwright 或 Cypress。

3.3 Cypress:前端测试体验最惊喜,但适用边界要清楚

Cypress 跟前两者走的是不同路线。它把测试代码运行在浏览器内部,而不是像 Selenium 那样从外部进程用 WebDriver 连接浏览器。这样一来,Cypress 可以直接感知到页面里的异步加载、路由跳转和网络请求,也能在浏览器开发者工具里实时看到每一步操作前后的状态,俗称 time-travel 调试。对做前端页面回归的人来说,这种体验几乎是碾压级的:跑完测试可以直接点开每一步的截图,看看到底是哪一步出了问题。

一个典型写法如下:

describe('login spec', () => { it('登录后跳转首页', () => { cy.visit('https://example.com/login'); cy.get('#username').type('demo'); cy.get('#password').type('123456'); cy.get('#submit').click(); cy.url().should('include', '/home'); }); });

Cypress 的自动等待同样内置。cy.get('#submit')会等元素出现,.click()会等元素可交互,测试失败时默认自动截图和录视频。最关键的是,它不需要 WebDriver,也不需要 Selenium Grid 那种 node 注册机制,一条npm install就能跑。很多前端团队把 Cypress 当作“提测前的自测脚本”,因为它能直接在本地开发环境跑,还能和 GitHub Actions、Jenkins 集成。

但我要提醒你,Cypress 有一个频繁踩坑的边界:它历史上不支持多标签页和跨域 iframe 的天然操作,虽然新版逐步在改善,但一旦项目大量使用跨子域页面跳转或复杂 iframe,你的脚本仍然会绕不少弯路。另外,因为代码在浏览器内执行,它不太适合操作浏览器窗口之外的东西,比如原生系统弹窗、下载文件的系统级后续处理。所以我通常把 Cypress 定位成“前端测试专用”,如果目标是做爬虫或系统级自动化,不建议选它。实际用下来,Cypress 最大的痛点反而是安装时下载二进制文件慢,需要配置CYPRESS_DOWNLOAD_MIRROR或者在内网放置缓存,其他开发体验基本不让人失望。

4. 迁移友好派和自然语言派:WebdriverIO、TestCafe、Taiko

4.1 WebdriverIO:Selenium Grid 的老用户不必推倒重来

很多测试团队早就自建了 Selenium Grid,不是因为它好用,而是历史资产都在里面。这时候硬换 Playwright 会导致底层基建全部重写,风险大。更平滑的方案是继续用 WebDriver 协议,但把脚本框架从原生 Selenium 替换成 WebdriverIO。它本质上是基于 WebDriver 的 Node.js 测试框架,但封装度远高于 Selenium 的 Java/Python API,自带waitForClickablewaitForDisplayed这类语义化方法。

示例代码:

describe('login test', () => { it('应该能登录成功', async () => { await browser.url('https://example.com/login'); await $('#username').setValue('demo'); await $('#password').setValue('123456'); await $('#submit').click(); await expect($('.user-info')).toBeDisplayed(); }); });

WebdriverIO 在原有 Selenium Grid 上可以直接运行,只要把 npm 依赖和配置文件替换一下即可。它还有一大类插件体系,比如@wdio/allure-reporter@wdio/sauce-service,以及外部云测服务集成能力。对 Java 团队来说,虽然 WebdriverIO 是 JavaScript 技术栈,但它带来的收益是代码量显著减少。

这里有个选型上的心得:如果你所在团队的脚本是 Java + TestNG + Selenium,建议先不要无脑迁移到 WebdriverIO,除非团队已经准备把测试代码统一成 JavaScript/TypeScript。否则,你只会把原来 Java 的@Test换成 JS 的it,解决不了根本问题。更合理的路线是:保留现网 Grid,新用例用 Playwright 的官方connectOverCDP去连远程 Chrome,逐步把老用例替换掉。WebdriverIO 适合本来就愿意用 Node.js 的人。

4.2 TestCafe:一条命令就能跑,不用驱动也不用等环境

TestCafe 有一个非常吸引人的特点:不需要为浏览器安装驱动。它启动时会自动识别本机安装的 Chrome、Firefox、Edge、Safari,然后通过一个内置的代理服务把自动化脚本注入页面。对 CI 环境尤其友好,因为只要镜像里装了浏览器,TestCafe 就能跑,不用额外处理 WebDriver 版本问题。另一个优点是它原生支持并行测试,不用再自己写多线程或进程池。

TestCafe 的测试文件更适合业务人员阅读。用 JavaScript 写,核心 API 手感不错:

import { Selector } from 'testcafe'; fixture('登录测试') .page('https://example.com/login'); test('登录后显示用户信息', async t => { await t .typeText('#username', 'demo') .typeText('#password', '123456') .click('#submit') .expect(Selector('.user-info').visible).ok(); });

TestCafe 也内置了自动等待:Selector在找不到元素时会反复重试,但你可以设置timeout参数来控制最长时间。它还有一个亮点是测试完成后自动产出 HTML 报告,页面截图和视频也都能集成进去,对要交付测试报告的团队非常实用。

不过,TestCafe 的生态和社区活跃度不像 Cypress 和 Playwright 那么高,遇到复杂问题时不那么容易搜到答案。它早期版本的 iframe 处理也比较绕,需要iframe选择器和switchToIframe方法,不建议在非常依赖嵌套 iframe 的页面上使用。如果你只是想快速跑一个跨浏览器烟雾测试,TestCafe 的省事程度确实排得上前列。

4.3 Taiko:让脚本读起来像“用户操作说明书”

Taiko 是 ThoughtWorks 团队开源的一个 Node.js 自动化库,整体设计思路比较独特:你不需要写 CSS 或 XPath,而是用“写在这、点击那个”这样的层级来定位元素。比如登录页面既没有稳定 id 也没有>const { open, write, into, click, textBox, button, closeBrowser } = require('taiko'); (async () => { await open('https://example.com/login'); await write('demo', into(textBox({ placeholder: '用户名' }))); await write('123456', into(textBox({ placeholder: '密码' }))); await click(button('登录')); await closeBrowser(); })();

Taiko 也内置了等待和无头模式,并且有配套的录制器。你可以在终端启动taiko,操作浏览器后自动生成脚本,这比 Selenium IDE 生成的脚本要干净得多。Taiko 这个工具的定位很适合“从黑盒测试角度做用例维护的人”,它不关心页面内部结构,只关心角色和行为。

不过要注意,正因为不依赖传统选择器,Taiko 在页面变化频繁的情况下会面临定位不稳定。比如按钮文字从“登录”改成“立即登录”,脚本可能就识别不了。它的做法是检查可访问性文本,所以如果产品文案经常改,还是需要用带aria-label的元素提供稳定锚点。实际我用的体验是:Taiko 更适合中小型项目或验证类任务,不适合要做非常细粒度断言的平台级项目。

5. 零代码图形识别路线:AirTest 与 Automa

5.1 AirTest:Android、Windows 和游戏自动化中的一股清流

AirTest 是网易开源的一款基于图像识别的自动化工具,核心思路是“截屏找图”。在普通 Web 自动化里,我们很少用这种方案,因为 DOM 信息更准确;但当你面对游戏 App、设备老化测试、Windows 桌面软件时,元素树根本拿不到,就必须靠图像识别。AirTest 最大的价值是提供了一套 Python API 和配套 IDE,可以跨平台连接 Android、iOS、Windows 等设备进行点击、滑动、按键操作。

一个典型的设备老化测试脚本长这样:

from airtest.core.api import * auto_setup(__file__) connect_device("Android:///") start_app("com.example.app") # 等待首页出现,如果超过 120 秒则判定异常 if wait(Template("home_screen.png"), timeout=120): swipe((800, 1200), (800, 400)) touch(Template("start_task.png")) else: raise RuntimeError("设备老化测试启动异常")

这个思路解决了一个 Selenium 完全无能为力的场景:被测对象不是浏览器页面。你可以在设备上长时间挂机,循环执行点击、滑动、截图比对,记录设备是否存在卡死、ANR、掉线、画面残留等问题。热搜词里“设备老化测试全自动执行脚本”对应的就是这类需求。在写老化测试脚本时,最忌讳的是每个动作间隔固定写死,比如sleep(10)。设备性能波动时,固定 sleep 很容易误判。AirTest 的wait(Template(...), timeout=...)更适合用来判断某一画面是否在预期时间内出现。

使用 AirTest 的常见坑是图像模板的清晰度。模板图片分辨率跟设备实际截图不一致时匹配率会下降。建议制作模板时从目标设备实际分辨率和 DPI 下截图,不要拿网上随便找的图;同时可以使用threshold=0.8这类参数控制相似度阈值。它也不是万能药,如果页面是多字节字体、真彩色渐变背景,匹配率也会波动,这时就要考虑加 OCR 插件。总体而言,在非标准 UI 自动化这块,AirTest 是 Selenium 之外的一个重要补充。

5.2 Automa:日常工作流自动化的“积木”

如果你不是程序员,看到前面这么多 Python/JavaScript 代码可能已经想关页面了。没关系,Automa 就是为“不想写代码”的人准备的。它是一款浏览器扩展,通过拖拽不同的“块”来搭建自动化流程:打开网址、点击元素、填写输入框、循环列表、读取页面文本、下载文件等。整个工作流可以在浏览器里用可视化的方式编辑,最后还能导出成 JSON 文件分享给别人。

以“每天上班先打开数据后台,把昨日订单数保存到本地”为例,Automa 的流程大致是:新建工作流;添加“打开网页”块并填入后台地址;添加“点击元素”块,元素选择器可以用内置的拾取器点在登录按钮上;添加“输入文本”块填入账号密码;“延迟”块等待页面加载;再添加“获取文本”块抓取订单数字;最后用“写入文件”块保存到本地或通过“通知”块提醒自己。

Automa 的优势是快,适合临时性、低频率的个人任务。它也有定时触发、快捷键触发等能力,还能在多个标签页间做处理。我常用它处理数据导出的小活,不用下载一堆依赖。但它的限制同样明显:跨域限制和浏览器安全模型仍然存在,很多网站需要先人工登录一次,Automa 再利用你的登录态去操作,所以它不适合做完全无人值守的账号体系测试。在 Selenium 替代生态中,Automa 属于典型的高频小工具,能解决大量简单重复操作,但上不了复杂系统的自动化测试台面。

6. 从 Selenium 迁移到替代工具,我的经验和建议

6.1 迁移前先盘一盘“老脚本为什么难改”

很多团队觉得迁移工具难,其实难的不是 API,而是前期没有清理老脚本里的坏味道。我之前接手过一套 Selenium 测试,里面大量使用time.sleep(3),人员流动后没人知道为什么是 3 秒而不是 2 秒。这种脚本换成任何框架都还会出问题,因为等待策略本身就是错的。所以迁移工具前,我建议先把用例按三层分类:第一类是高频且完整登录走主流程的用例,优先迁移;第二类是需要读写文件、操作非浏览器资源的用例,后续再评估;第三类是已经烂到没人维护、历史原因不明的用例,直接删除或重写,不要浪费迁移成本。

同时要梳理公共操作,比如登录、翻页、关闭弹窗、文件下载约定。这些公共操作在新工具里应该封装成独立模块。这一步比学新 API 更重要,否则每个脚本还是各写各的,迁移后依然是一团散沙。在我实际做的一次大迁移中,花在整理旧用例上的时间大约是写新脚本时间的一半。这个准备阶段省不掉。

6.2 用 Playwright 为例,一步一步替换老脚本

我拿一次典型迁移说明操作过程。第一步,安装并初始化项目依赖,Python 用pip install playwright && playwright install chromium,Node.js 用npm init -y && npm i -D playwright。第二步,把 Selenium 脚本里的 WebDriver 等待全部删掉,开始写 Playwright 的page.gotopage.locator,通常元素定位优先使用get_by_role或 CSS,不要再复制长 XPath。第三步,用playwright codegen https://example.com打开录制器,手动走一遍业务路径,再把生成的脚本做简化。

这里要说一个容易犯的错误:有些人录完就开始跑,结果录制的选择器在下次页面加载时依然不稳定。原因是录制器默认会生成偏向可访问性的aria选择器,但某些框架生成的动态 id 会让选择器看起来很长。我更推荐在录制完以后,手动给关键元素加上稳定标记,比如>

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

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

立即咨询