Skip to content

第 2 章 · 第一个脚本与同步 API

本章目标:吃透同步 API 的对象模型(Playwright → Browser → Context → Page),掌握 goto/click/fill 等基础操作与截图,理解 headless、slow_mo 两个调试开关。

2.1 同步 API 的对象模型

sync_playwright() 返回的入口对象下挂着三层核心对象,理解它们的职责是写出正确脚本的前提:

python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:                 # p: Playwright 入口
    browser = p.chromium.launch()            # Browser: 一个浏览器进程
    context = browser.new_context()          # Context: 隔离的"浏览器档案"
    page = context.new_page()                # Page: 一个标签页
    page.goto("https://example.com")
    browser.close()
  • Browser:一次 launch() 对应一个真实进程,启动成本高;
  • BrowserContext:相当于一份全新的无痕浏览档案(独立 Cookie/缓存/storage),创建成本极低。这是官方测试隔离方案的基石——第 6 章 pytest 插件就是"每个测试发一个新 context";
  • Page:context 里的一个标签页,日常操作的主要入口。

能开多少个 context?

几十上百个都没问题:context 只是同一进程内的轻量隔离单元。需要模拟"多用户同时在线"时,开多个 context 即可,而不是开多个 browser。

2.2 基础操作三部曲

python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()

    # 1) 导航:默认等待到 load 状态
    page.goto("https://playwright.dev/python")

    # 2) 填写搜索框(fill 会先清空再输入)
    search = page.get_by_role("button", name="Search")
    search.click()
    page.get_by_placeholder("Search docs").fill("locators")

    # 3) 回车触发搜索并等待结果页
    page.get_by_placeholder("Search docs").press("Enter")
    page.wait_for_load_state()

    print(page.title())
    browser.close()

常用交互方法速查:

方法用途
page.goto(url)导航,默认等到 load
locator.click()点击
locator.fill(text)清空并填入文本(input/textarea)
locator.press(key)按键,如 "Enter""Control+a"
locator.check() / uncheck()勾选/取消复选框
locator.select_option("value")下拉选择

2.3 截图:全页、元素与视口

python
page.goto("https://playwright.dev/python")

# 视口截图(默认)
page.screenshot(path="viewport.png")

# 整页滚动截图
page.screenshot(path="full.png", full_page=True)

# 只截某个元素
page.locator("header").screenshot(path="header.png")

截图是排查失败的第一手证据,第 16 章会把它接入 CI 失败工件。

2.4 headless 与 headed

python
# 无头:没有窗口,速度快,CI 标配
browser = p.chromium.launch()

# 有头:弹出真实窗口,本地调试直观
browser = p.chromium.launch(headless=False)

调试利器 slow_mo:给每个操作强制加延迟(毫秒),人眼能跟上页面发生了什么:

python
browser = p.chromium.launch(headless=False, slow_mo=1000)

另一个常被混淆的选项是 launch_persistent_context——它把 user-data-dir 和浏览器启动合并成一步,Cookie 会跨运行持久保存,适合爬虫登录态复用;而普通 new_context() 每次都是干净的无痕档案:

python
# 持久化上下文:数据写入本地目录,重启不丢
context = p.chromium.launch_persistent_context(
    user_data_dir="./my-profile",
    headless=False,
)

测试里不要用 persistent context

持久化上下文会让测试之间互相污染(上个测试的登录态泄漏到下个测试)。E2E 测试永远用干净的 new_context()

2.5 本章小结

  • 对象层级:Playwright → Browser(进程)→ Context(隔离档案)→ Page(标签页);
  • Context 轻量且完全隔离,是多用户模拟与测试隔离的基础;
  • fill 先清空再输入;press 用于回车等按键;
  • 截图三形态:视口 / full_page=True / 元素级;
  • headless=False + slow_mo 是本地调试黄金组合;持久化上下文别用在测试里。

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. 想模拟"两个用户同时各自登录自己的账号",正确的做法是?

2. page.screenshot(path="a.png") 与 full_page=True 的区别是?

3. 为什么 E2E 测试中不推荐 launch_persistent_context?

4. slow_mo=1000 参数的作用是?

🛠️ 动手实践

  1. 写脚本访问 https://playwright.dev/python,对 header 元素和整页分别截图,比较两张图。
  2. 用两个 context 同时分别打开不同网站,交替打印两边的标题,体会"并行会话"。
  3. 分别用 new_context()launch_persistent_context(user_data_dir="./t") 访问任意站点并设置 localStorage,关闭重开后读取该值,观察持久化差异。

掌握了对象模型后,进入第 3 章:定位器 Locator 与严格模式