首页
/ Playwright 入口对象(class: Playwright)完全指南:统一驱动 Chromium、Firefox 与 WebKit

Playwright 入口对象(class: Playwright)完全指南:统一驱动 Chromium、Firefox 与 WebKit

2026-09-06 18:55:47作者:廉彬冶Miranda

Playwright 是 Playwright 自动化框架的模块级入口类,为开发者提供了启动浏览器、创建页面、执行自动化与 Web API 测试的统一入口。无论你使用 JavaScript、Java、Python(同步/异步)还是 C#,都可以通过 playwright.chromiumplaywright.firefoxplaywright.webkit 三个浏览器类型句柄及 deviceserrorsrequestselectors 等附属能力完成端到端测试。本文以 class-playwright.md 为骨架,结合仓库源码深入讲解该入口对象的设计、用法与生命周期管理。

Playwright 入口对象到底是什么

从 API 文档的定义看,class: Playwright(自 v1.8 引入)提供“启动浏览器实例的方法”,它本身并不直接启动浏览器,而是充当一套门面(Facade)

  • 通过 chromium / firefox / webkit 三个 BrowserType 属性间接完成浏览器的 launch、launchPersistentContext、connect 等操作;
  • 通过 devices 提供移动设备描述符字典,配合 Browser.newContext / Browser.newPage 做移动端仿真;
  • 通过 errors 暴露可辨识的错误类型(如 TimeoutError),便于精确捕获异常;
  • 通过 request 提供独立的 Web API 测试能力;
  • 通过 selectors 注册自定义选择器引擎,扩展定位语法。

从仓库实现看,这一设计在源码中有清晰的对应:客户端侧的 playwright.ts 定义了 class Playwright extends ChannelOwner,其构造函数会把 chromiumfirefoxwebkit 三个 BrowserType 分别通过 BrowserType.from(...) 从协议通道初始化出来,并装配好 devicesselectorsrequesterrors 等成员。也就是说,语言绑定层的 Playwright 对象是驱动进程(driver process)通道之上的客户端封装,真正干活的是服务端 playwright.ts 中的 Playwright 类——它分别实例化 Chromium(内部再封装 BidiChromium)、Firefox(封装 BidiFirefox)、WebKitElectronAndroid 等浏览器后端。

快速上手:四种语言的入门流程

原文档给出了一套高度对称的入门示例,核心流程都是:获取浏览器类型 → launch()newPage() → 执行动作 → close()

JavaScript(CommonJS 语法)

const { chromium, firefox, webkit } = require('playwright');

(async () => {
  const browser = await chromium.launch();  // Or 'firefox' or 'webkit'.
  const page = await browser.newPage();
  await page.goto('http://example.com');
  // other actions...
  await browser.close();
})();

Java

import com.microsoft.playwright.*;

public class Example {
  public static void main(String[] args) {
    try (Playwright playwright = Playwright.create()) {
      BrowserType chromium = playwright.chromium();
      Browser browser = chromium.launch();
      Page page = browser.newPage();
      page.navigate("http://example.com");
      // other actions...
      browser.close();
    }
  }
}

Python(asyncio 异步 API)

import asyncio
from playwright.async_api import async_playwright, Playwright

async def run(playwright: Playwright):
    chromium = playwright.chromium # or "firefox" or "webkit".
    browser = await chromium.launch()
    page = await browser.new_page()
    await page.goto("http://example.com")
    # other actions...
    await browser.close()

async def main():
    async with async_playwright() as playwright:
        await run(playwright)
asyncio.run(main())

Python(同步 API)

from playwright.sync_api import sync_playwright, Playwright

def run(playwright: Playwright):
    chromium = playwright.chromium # or "firefox" or "webkit".
    browser = chromium.launch()
    page = browser.new_page()
    page.goto("http://example.com")
    # other actions...
    browser.close()

with sync_playwright() as playwright:
    run(playwright)

C#

using Microsoft.Playwright;
using System.Threading.Tasks;

class PlaywrightExample
{
    public static async Task Main()
    {
        using var playwright = await Playwright.CreateAsync();
        await using var browser = await playwright.Chromium.LaunchAsync();
        var page = await browser.NewPageAsync();

        await page.GotoAsync("https://www.microsoft.com");
        // other actions...
    }
}

上述示例中 browser.newPage()(JS)/ NewPageAsync()(C#)/ new_page()(Python)/ newPage()(Java)都会默认创建一个全新的 BrowserContext,保证每个测试用例的隔离性。若要拿到更精细的控制,可改用 playwright.chromium.launch() 后通过 browser.newContext(...) 自定义视口、语言、代理等上下文参数。

property: Playwright.chromium / firefox / webkit —— 三个浏览器类型句柄

自 v1.8 起,Playwright 暴露了三个同构属性,类型均为 BrowserType

  • chromium:用于 launch 或 connect Chromium(含 headless Chrome / 新 headless 模式),返回 Browser 实例;
  • firefox:用于 launch 或 connect Firefox;
  • webkit:用于 launch 或 connect WebKit。

以源码为证,playwright.ts 中三者使用完全一致的初始化方式,只是各自 from 的通道对象不同;而服务端 playwright.ts 进一步说明 Firefox/Chromium 在现代版本中通过 BiDi 协议适配层(BidiFirefox / BidiChromium)连接,WebKit 则保持独立实现。三者签名统一,意味着切换浏览器引擎几乎不需要改动测试代码,只需换掉入口对象。

BrowserType 本身还承载了更多能力,可阅读 class-browsertype.md:如 launch()launchPersistentContext(userDataDir)(持久化上下文)、connect(wsEndpoint)(连接已启动的浏览器)与 connectOverCDP()。对应实现位于 browserType.ts,其中 launchPersistentContext 适合需要保留用户数据目录的“真实浏览器”场景,connect/connectOverCDP 适合连接远程或已存在的浏览器实例进行调试与分布式执行。

property: Playwright.devices —— 移动设备仿真描述符字典

devices 返回一个设备描述符字典,可配合 Browser.newContextBrowser.newPage 一键复现 iPhone、Pixel、Galaxy 等真实设备的 UA、视口、DPR、触摸能力与移动标识。

在 JS / Python 中其类型为 Object(Python 为字典);在 C# 中类型为 IReadOnlyDictionary<string, BrowserNewContextOptions>,可以直接作为 NewContextAsync 的参数。

JavaScript / Python 用法(以文档中的 “iPhone 6” 为例)

const { webkit, devices } = require('playwright');
const iPhone = devices['iPhone 6'];

(async () => {
  const browser = await webkit.launch();
  const context = await browser.newContext({
    ...iPhone
  });
  const page = await context.newPage();
  await page.goto('http://example.com');
  // other actions...
  await browser.close();
})();
from playwright.sync_api import sync_playwright

with sync_playwright() as playwright:
    webkit = playwright.webkit
    iphone = playwright.devices["iPhone 6"]
    browser = webkit.launch()
    context = browser.new_context(**iphone)
    page = context.new_page()
    page.goto("http://example.com")
    browser.close()

C# 用法

using Microsoft.Playwright;
using System.Threading.Tasks;

class PlaywrightExample
{
    public static async Task Main()
    {
        using var playwright = await Playwright.CreateAsync();
        await using var browser = await playwright.Webkit.LaunchAsync();
        await using var context = await browser.NewContextAsync(playwright.Devices["iPhone 6"]);

        var page = await context.NewPageAsync();
        await page.GotoAsync("https://www.theverge.com");
        // other actions...
    }
}

从源码理解描述符结构。 设备数据的真实来源是 deviceDescriptorsSource.json,由 deviceDescriptors.ts 直接加载导出;客户端 playwright.ts 通过 this.devices = this._connection.localUtils()?.devices ?? {} 把同一份字典暴露给用户。当前仓库这份 JSON 中收录了 207 个条目(包含大量 landscape 横屏变体,如 “iPhone 13” 与 “iPhone 13 landscape”),每个描述符的典型结构(以 “iPhone 13” 为例)如下:

{
  "userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Mobile/15E148 Safari/604.1",
  "screen": { "width": 390, "height": 844 },
  "viewport": { "width": 390, "height": 664 },
  "deviceScaleFactor": 3,
  "isMobile": true,
  "hasTouch": true,
  "defaultBrowserType": "webkit"
}

注意 defaultBrowserType 字段只是建议使用的浏览器内核,你仍可自由选择 chromiumfirefoxwebkit 去加载同一个设备描述符。上述所有字段会展开成 Browser.newContext 的选项(userAgentviewportdeviceScaleFactorisMobilehasTouch 等),从而让页面以接近真实设备的特征渲染。若内置描述符不足,也可以复制一份设备项并自行覆写部分字段——它本质就是一份上下文选项字典。相关上下文参数细节可参见 class-browsercontext.mdnewContext 的选项说明。

property: Playwright.errors —— 可辨识的错误类型(JS/Python)

并非所有失败都需要靠字符串匹配错误消息。Playwright 为特定场景定义了专属错误类,可通过 playwright.errors 访问;其中公开可用的为 TimeoutError 类。

errors.ts 源码可见完整的类继承关系:TimeoutError extends PlaywrightError extends Error,且 TimeoutErrorname 被设为 'TimeoutError',这样在协议传输层 parseError 反序列化远端错误时,可以通过 name === 'TimeoutError' 精确还原出同构的 TimeoutError 实例。

典型场景:Locator.waitFor 在给定时间内没有匹配到任何节点就会抛出超时错误,而 Playwright 方法在无法完成请求时都可能会抛出错误。示例(JS):

try {
  await page.locator('.foo').waitFor();
} catch (e) {
  if (e instanceof playwright.errors.TimeoutError) {
    // Do something if this is a timeout.
  }
}

Python 用户则直接捕获内建 TimeoutError(异步/同步 API 一致):

try:
  page.wait_for_selector(".foo")
except TimeoutError as e:
  pass
  # do something if this is a timeout.

property: Playwright.request —— Web API 测试入口

自 v1.16 起,Playwright 提供 request 属性(C# 中别名为 APIRequest),类型为 APIRequest,用于纯 Web API 测试——即使完全不启动浏览器,也能发起请求、断言响应。详见 class-apirequest.md

源码侧,playwright.ts 在构造入口对象时同步创建 this.request = new APIRequest(this),与浏览器自动化共享同一连接通道。这带来的实际收益是:在同一测试进程中,request 创建的 APIRequestContext 默认会携带浏览器上下文中的 Cookie,从而可以无缝衔接“先 API 登录、再浏览器操作”的经典混合模式;它也支持 global fetch 独立会话,相关示例可参考 global-fetch.spec.ts 等测试。

property: Playwright.selectors —— 自定义选择器引擎注册

selectors 属性类型为 Selectors,用于安装自定义选择器引擎。要编写自定义引擎需要实现查找元素、查询全部匹配、判定命中三件套,详细介绍见 extensibility.mdclass-selectors.md

核心 API 在客户端 selectors.ts 中实现,包括:

  • selectors.register(name, script, options?):注册一个命名选择器引擎(options.contentScript 决定该引擎是否只对内容脚本可见),重复注册同名引擎会抛错(见 selectors.ts);
  • selectors.setTestIdAttribute(attributeName):配置 data-testid 的替代属性名,如 setTestIdAttribute('data-pw') 后,page.getByTestId() 就会匹配新属性。

注册后即可在定位符中使用自定义前缀,例如 page.locator('myengine=...'),扩展内置 CSS / XPath / text 之外的定位能力。

生命周期管理:Java 的 create/close 与 Python 的 stop

在 Java 与 Python 中,Playwright 对象需要显式创建与回收,原文档给出了三组生命周期方法。

Java:Playwright.create() 与 close()

自 v1.10 起,Java 通过静态方法 Playwright.create() 启动一个新的 Playwright 驱动进程并与之建立连接,返回 Playwright 实例;当实例不再使用时应当调用 close() 终止。close() 同时会关闭所有仍由该实例启动、尚未关闭的浏览器。

Playwright playwright = Playwright.create();
Browser browser = playwright.webkit().launch();
Page page = browser.newPage();
page.navigate("https://www.w3.org/");
playwright.close();

create()env 选项(自 v1.13 起):类型为 Map<String, String>,用于向驱动进程传入额外的环境变量。默认情况下,驱动进程会继承 Playwright 宿主进程的环境变量;当需要为驱动子进程注入自定义变量(如代理、语言区域、专有调试开关)时即可使用该选项。

Python:stop()

自 v1.8 起,Python 语境下若绕过上下文管理器(context manager)直接调用 sync_playwright().start() 创建实例,则必须显式调用 stop() 终止实例。这在 REPL / Jupyter 等交互式脚本中特别有用——因为无法依赖 with 块自动清理:

from playwright.sync_api import sync_playwright

playwright = sync_playwright().start()

browser = playwright.chromium.launch()
page = browser.new_page()
page.goto("https://playwright.dev/")
page.screenshot(path="example.png")
browser.close()

playwright.stop()

需要说明的是:在常规的 with sync_playwright() as playwright:(同步)或 async with async_playwright() as playwright:(异步)写法中,退出代码块时会自动完成启停,无需也不应手动调用 stop()。JS 的 playwright 包则通过模块顶层导出的 chromium/firefox/webkit 常量直接使用,进程生命周期由运行时自行管理,无需类似方法。

从源码看入口对象的装配与扩展边界

汇总一下仓库中与本主题强相关的实现文件,便于读者按图索骥:

关注点 仓库位置 说明
客户端入口对象 packages/playwright-core/src/client/playwright.ts Playwright 客户端类:装配三个 BrowserTypedevicesselectorsrequesterrors
服务端入口对象 packages/playwright-core/src/server/playwright.ts 服务端创建 Chromium/Firefox/WebKit/Electron/Android 后端并跟踪所有 Page/Browser
浏览器类型句柄 packages/playwright-core/src/client/browserType.ts launch / launchPersistentContext / connect / connectOverCDP 实现
设备描述符数据 packages/isomorphic/deviceDescriptorsSource.json 207 个内置设备项;deviceDescriptors.ts 负责加载
错误类体系 packages/playwright-core/src/client/errors.ts TimeoutError 等错误类及远端错误反序列化逻辑
选择器注册 packages/playwright-core/src/client/selectors.ts registersetTestIdAttribute

一个值得注意的扩展边界:客户端 Playwright 虽然面向用户只暴露了 chromium/firefox/webkit,但其内部还持有 _android(对应 Android 设备测试)与 _electron(对应 electron 桌面应用测试)句柄,只是出于 API 收敛考虑未在文档化的公开属性中体现。这也是从源码结构可以推断出的设计取舍:文档化的公开 API 刻意保持精简,非核心能力则通过各自独立的文档模块(如 mobile-api、Electron API)管理。

小结

class: Playwright 是全框架的统一入口,理解它就等于掌握了 Playwright 的骨架:

  1. 同构三浏览器chromium / firefox / webkit 提供一致 API,一行切换引擎;
  2. 设备仿真即配置devices 字典(207 项)本质是可直接展开的上下文选项,配合 newContext/newPage 使用;
  3. 错误可编程捕获errors.TimeoutError 让超时等失败可控、可分类;
  4. API 测试与自动化同源request 与浏览器共享连接通道,Cookie 天然打通;
  5. 选择器可扩展selectors.register 让自定义定位引擎成为一等公民;
  6. 生命周期需管理:Java 的 create()/close() 与 Python 的 stop() 用于非托管场景。

class-browser.md(浏览器实例)、class-browsercontext.md(上下文隔离)到 class-locator.md(精确定位),Playwright 的后续能力都建立在这个入口对象之上——先掌握它,再向页面与元素层深入,是最稳妥的学习路径。

登录后查看全文
热门项目推荐
相关项目推荐