目录

  1. 概述
  2. Puppeteer
  3. Playwright
  4. Selenium
  5. 对比总览
  6. 选型建议

概述

特性 Puppeteer Playwright Selenium
开发者 Google 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>

参考链接