自动化测试工具对比:Puppeteer vs Playwright vs Selenium
目录
概述
| 特性 | Puppeteer | Playwright | Selenium |
|---|---|---|---|
| 开发者 | Microsoft | 社区(OpenQA / SeleniumHQ) | |
| 首次发布 | 2017 | 2020 | 2004 |
| 底层协议 | Chrome DevTools Protocol (CDP) | CDP + 自定义协议 | WebDriver (W3C 标准) |
| 支持的浏览器 | Chromium(Chrome/Edge) | Chromium + Firefox + WebKit (Safari) | Chrome, Firefox, Safari, Edge, IE 等 |
| 主要语言 | JavaScript/TypeScript | JavaScript/TypeScript, Python, Java, .NET | Java, Python, C#, Ruby, JavaScript, Kotlin 等 |
| 核心定位 | 浏览器控制库 | 跨浏览器自动化(现代 Web) | 跨浏览器自动化(标准化) |
Puppeteer
Puppeteer 是 Google 开发的一个 Node.js 库,通过 Chrome DevTools Protocol (CDP) 直接控制 Chromium 浏览器。它的 API 设计简洁直观,在 Chrome/Chromium 生态中表现最佳。
特点
- ✅ 专为 Chromium 优化,性能极高
- ✅ 内置截图、PDF 生成功能
- ✅ 支持无头模式与 UI 模式
- ✅ 优秀的网络请求拦截能力
- ✅ 与 Chrome DevTools 深度集成
- ❌ 仅支持 Chromium(不支持 Firefox / Safari)
- ❌ 仅限 JavaScript/TypeScript
使用示例
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', { waitUntil: 'networkidle2' });
// 截图
await page.screenshot({ path: 'screenshot.png', fullPage: true });
// 获取页面标题
const title = await page.title();
console.log('页面标题:', title);
// 点击元素
await page.click('button#submit');
// 在输入框中输入文本
await page.type('input#search', 'Puppeteer');
// 获取元素文本
const text = await page.$eval('h1', el => el.textContent);
console.log('h1 文本:', text);
// 关闭浏览器
await browser.close();
})();
TypeScript
import puppeteer from 'puppeteer';
async function run(): Promise<void> {
const browser = await puppeteer.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com');
await page.setViewport({ width: 1920, height: 1080 });
// 等待元素出现
await page.waitForSelector('.content');
const title = await page.title();
console.log(`Title: ${title}`);
// 获取元素属性
const href = await page.$eval('a', el => el.getAttribute('href'));
await browser.close();
}
run();
高级用法 — 拦截网络请求
// 拦截并修改网络请求
await page.setRequestInterception(true);
page.on('request', request => {
if (request.url().includes('analytics')) {
request.abort(); // 阻止分析脚本加载
} else {
request.continue();
}
});
// 监听响应
page.on('response', response => {
console.log(`${response.status()}: ${response.url()}`);
});
注意:Puppeteer 没有官方的 Python/Java 版本,社区维护的
pyppeteer是其 Python 移植。
Playwright
Playwright 是 Microsoft 开发的新一代端到端测试框架。它的 API 跨语言高度一致,同时支持 Chromium、Firefox 和 WebKit,是目前最活跃的自动化工具之一。
特点
- ✅ 真正的跨浏览器:一套 API 覆盖 Chrome、Firefox、Safari
- ✅ 自动等待元素就绪,减少
waitFor调用 - ✅ 内置浏览器上下文(Context)隔离,适合多用户场景
- ✅ 支持移动端设备模拟
- ✅ 网络拦截与 Mock API
- ✅ 官方支持 JS/TS、Python、Java、.NET
- ✅ 自动追踪(Trace Viewer)用于调试
- ❌ 不支持 IE 等老旧浏览器
使用示例
Node.js
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com');
// 自动等待 —— Playwright 会自动等待元素可操作
await page.click('button#submit');
await page.fill('input#search', 'Playwright');
// 截图
await page.screenshot({ path: 'screenshot.png', fullPage: true });
// 获取页面标题
const title = await page.title();
console.log('页面标题:', title);
// 获取文本
const text = await page.textContent('h1');
// 切换浏览器 —— 只需将 chromium 替换为 firefox 或 webkit
await browser.close();
})();
Python
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
# 启动浏览器(可切换 firefox / chromium / webkit)
browser = await p.chromium.launch(headless=False)
page = await browser.new_page()
await page.goto("https://example.com")
# 截图
await page.screenshot(path="screenshot.png", full_page=True)
# 点击与输入 —— 自动等待
await page.click("button#submit")
await page.fill("input#search", "Playwright")
# 获取内容
title = await page.title()
print(f"页面标题: {title}")
h1_text = await page.text_content("h1")
print(f"h1 文本: {h1_text}")
# 浏览器上下文 —— 模拟移动设备
iphone = p.devices["iPhone 13"]
context = await browser.new_context(**iphone)
mobile_page = await context.new_page()
await mobile_page.goto("https://example.com")
await browser.close()
asyncio.run(main())
Python(同步模式)
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")
page.screenshot(path="example.png")
page.fill("input#search", "Playwright")
page.click("button#submit")
print(page.title())
browser.close()
Java
import com.microsoft.playwright.*;
import java.util.*;
public class PlaywrightExample {
public static void main(String[] args) {
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.chromium().launch(
new BrowserType.LaunchOptions().setHeadless(false)
);
Page page = browser.newPage();
page.navigate("https://example.com");
page.screenshot(new Page.ScreenshotOptions()
.setPath(Paths.get("screenshot.png"))
.setFullPage(true));
page.fill("input#search", "Playwright");
page.click("button#submit");
String title = page.title();
System.out.println("页面标题: " + title);
String h1 = page.textContent("h1");
System.out.println("h1: " + h1);
browser.close();
}
}
}
.NET (C#)
using Microsoft.Playwright;
var playwright = await Playwright.CreateAsync();
var browser = await playwright.Chromium.LaunchAsync(new()
{
Headless = false
});
var page = await browser.NewPageAsync();
await page.GotoAsync("https://example.com");
await page.ScreenshotAsync(new() { Path = "screenshot.png", FullPage = true });
await page.FillAsync("input#search", "Playwright");
await page.ClickAsync("button#submit");
var title = await page.TitleAsync();
Console.WriteLine($"页面标题: {title}");
await browser.CloseAsync();
高级用法 — API Mock
// 拦截 API 并返回 Mock 数据
await page.route('**/api/users', route => {
route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify([{ id: 1, name: 'Mock User' }])
});
});
// 多浏览器并行测试
const browsers = ['chromium', 'firefox', 'webkit'];
for (const browserType of browsers) {
const browser = await playwright[browserType].launch();
// ... 测试代码
}
Selenium
Selenium 是最老牌、最成熟的浏览器自动化工具。它采用 WebDriver 协议(现为 W3C 标准),支持几乎所有浏览器,生态极为丰富。
特点
- ✅ 浏览器支持最广:Chrome、Firefox、Safari、Edge、IE 等
- ✅ 语言支持最全:Java、Python、C#、Ruby、JavaScript、Kotlin 等
- ✅ 社区庞大、资料丰富、问题容易找到解答
- ✅ Selenium Grid 支持分布式测试
- ❌ API 相对底层,需要手动等待(显式/隐式等待)
- ❌ 速度相对较慢(标准化协议带来额外开销)
- ❌ 设置复杂(需要 WebDriver 驱动)
使用示例
Python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 设置 Chrome 驱动(自动管理)
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
# 启动浏览器
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
try:
# 导航
driver.get("https://example.com")
# 显式等待
wait = WebDriverWait(driver, 10)
element = wait.until(EC.presence_of_element_located((By.TAG_NAME, "h1")))
# 截图
driver.save_screenshot("screenshot.png")
# 查找元素
title = driver.title
print(f"页面标题: {title}")
# 输入文本
search_box = driver.find_element(By.ID, "search")
search_box.send_keys("Selenium")
search_box.send_keys(Keys.RETURN)
# 点击元素
driver.find_element(By.ID, "submit").click()
# 获取元素文本
h1 = driver.find_element(By.TAG_NAME, "h1").text
print(f"h1: {h1}")
finally:
driver.quit()
Java
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.By;
import io.github.bonigarcia.wdm.WebDriverManager;
import java.time.Duration;
public class SeleniumExample {
public static void main(String[] args) {
// 自动管理 ChromeDriver
WebDriverManager.chromedriver().setup();
ChromeOptions options = new ChromeOptions();
// options.addArguments("--headless");
WebDriver driver = new ChromeDriver(options);
try {
driver.get("https://example.com");
// 显式等待
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(ExpectedConditions.presenceOfElementLocated(By.tagName("h1")));
// 截图
File screenshot = ((TakesScreenshot) driver)
.getScreenshotAs(OutputType.FILE);
// FileUtils.copyFile(screenshot, new File("screenshot.png"));
// 获取标题
String title = driver.getTitle();
System.out.println("页面标题: " + title);
// 输入文本
WebElement searchBox = driver.findElement(By.id("search"));
searchBox.sendKeys("Selenium");
searchBox.sendKeys(Keys.RETURN);
// 点击
driver.findElement(By.id("submit")).click();
// 获取文本
String h1 = driver.findElement(By.tagName("h1")).getText();
System.out.println("h1: " + h1);
} finally {
driver.quit();
}
}
}
Node.js
const { Builder, By, until } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
(async () => {
const driver = await new Builder()
.forBrowser('chrome')
.setChromeOptions(new chrome.Options()) // .headless() 可开启无头模式
.build();
try {
await driver.get('https://example.com');
// 显式等待
await driver.wait(until.elementLocated(By.tagName('h1')), 10000);
// 截图
await driver.takeScreenshot().then(data => {
require('fs').writeFileSync('screenshot.png', data, 'base64');
});
// 标题
const title = await driver.getTitle();
console.log('页面标题:', title);
// 输入文本
await driver.findElement(By.id('search')).sendKeys('Selenium');
await driver.findElement(By.id('submit')).click();
// 获取文本
const h1 = await driver.findElement(By.tagName('h1')).getText();
console.log('h1:', h1);
} finally {
await driver.quit();
}
})();
高级用法 — Selenium Grid(分布式测试)
from selenium import webdriver
from selenium.webdriver.common.by import By
# 连接到 Selenium Grid Hub
chrome_options = webdriver.ChromeOptions()
driver = webdriver.Remote(
command_executor="http://localhost:4444/wd/hub",
options=chrome_options
)
driver.get("https://example.com")
print(driver.title)
driver.quit()
对比总览
| 维度 | Puppeteer | Playwright | Selenium |
|---|---|---|---|
| 浏览器数量 | 1(Chromium) | 3(Chromium + Firefox + WebKit) | 几乎所有(含 IE) |
| 语言覆盖 | JS/TS(仅官方) | JS/TS, Python, Java, .NET | Java, Python, C#, Ruby, JS, Kotlin 等 |
| 安装复杂度 | 低(npm install) | 低(npm/pip install + 自动下载浏览器) | 中(需安装 WebDriver 驱动) |
| API 现代化程度 | ★★★★★ | ★★★★★ | ★★★☆☆ |
| 自动等待机制 | 需手动 waitFor | 内置自动等待 | 需显式/隐式等待 |
| 执行速度 | 快 | 快 | 中等 |
| 移动端模拟 | 手动设置 | 内置设备列表 | 需手动设置 |
| 网络 Mock | 支持 | 支持(更强大) | 不直接支持 |
| Trace/Debug | CDP DevTools | Trace Viewer | DevTools 需额外配置 |
| 社区生态 | 成熟 | 快速增长 | 最成熟 |
| CI/CD 集成 | 容易 | 容易 | 中等 |
选型建议
🏆 什么时候选 Puppeteer?
- 你只需要测试 Chrome/Chromium(大多数 Web 应用如此)
- 你需要 截图、PDF 生成功能(原生支持)
- 你的项目全栈 JavaScript/TypeScript
- 你需要精细控制网络请求
- 典型案例:Chrome 扩展测试、性能监控、爬虫
🏆 什么时候选 Playwright?
- 你需要跨浏览器测试(Chrome + Firefox + Safari)
- 你在 Python / Java / .NET / JS 项目中工作
- 你希望 测试稳定性更高(自动等待减少 flaky 测试)
- 你刚开始新项目 —— Playwright 是当前最推荐的测试框架
- 你需要 API Mock 或 移动端模拟
- 典型案例:端到端测试、跨浏览器兼容性测试
🏆 什么时候选 Selenium?
- 你需要在 老旧浏览器(IE) 上测试
- 你的项目已使用 Selenium,迁移成本高
- 你需要 Selenium Grid 大规模分布式测试
- 你的团队对 Selenium 生态最熟悉
- 你需要支持 多种编程语言,尤其是 Java
- 典型案例:企业级回归测试、多浏览器兼容性矩阵
总结
graph TD
A[选择自动化工具] --> B{需要跨浏览器?}
B -->|仅 Chrome| C[Puppeteer]
B -->|Modern 浏览器| D[Playwright]
B -->|含 IE/旧浏览器| E[Selenium]
C --> F{语言需求}
D --> F
E --> F
F -->|JS/TS| G[三者均可]
F -->|Python| H[Playwright / Selenium]
F -->|Java| I[Selenium / Playwright]
F -->|.NET| J[Playwright / Selenium]
一句话建议:
- 如果是 新项目且面向现代浏览器 → Playwright
- 如果是 Chrome-only + JS/TS 项目 → Puppeteer
- 如果是 企业已有项目或兼容老旧浏览器 → Selenium
安装速查
Puppeteer
# npm
npm install puppeteer
# yarn
yarn add puppeteer
Playwright
# Node.js
npm init playwright@latest
# 或
npm install playwright
npx playwright install
# Python
pip install playwright
playwright install
# Java(Maven)
# pom.xml 中添加依赖
# <dependency>
# <groupId>com.microsoft.playwright</groupId>
# <artifactId>playwright</artifactId>
# <version>1.49.0</version>
# </dependency>
# .NET
dotnet add package Microsoft.Playwright
Selenium
# Python
pip install selenium
pip install webdriver-manager # 自动管理驱动
# Node.js
npm install selenium-webdriver
# Java(Maven)
# <dependency>
# <groupId>org.seleniumhq.selenium</groupId>
# <artifactId>selenium-java</artifactId>
# <version>4.28.0</version>
# </dependency>