Playwright

Playwright Python


Playwright 浏览器自动化

Playwright 是微软推出的 web 自动化工具,相较于目前最常用的 Selenium,它仅用一个API即可自动执行Chromium、Firefox、WebKit等主流浏览器自动化操作。 https://playwright.dev/ https://github.com/microsoft/playwright

Playwright 是一个强大的自动化库,用于Web浏览器的自动化测试和爬虫。它支持 Chromium、Firefox 和 WebKit,并提供同步和异步API。 主要特点:

  • 跨浏览器:在 Chromium、Firefox 和 WebKit 上运行测试。
  • 跨平台:在 Windows、Linux 和 macOS 上运行。
  • 支持无头(headless)和有头(headed)模式。
  • 自动等待:自动等待元素出现、可操作等,减少人工等待代码。
  • 强大的网络能力:可以拦截和修改网络请求。
  • 模拟移动设备、地理位置等。
  • 执行速度比 Selenium 快

playwright-python

microsoft / playwright-python https://github.com/microsoft/playwright-python

安装 playwright 及浏览器驱动

pip 安装 playwright

pip install playwright
playwright --version

首次使用需要安装浏览器驱动 (1)安装全部浏览器驱动:

playwright install

(2)或者安装特定浏览器驱动:

playwright install chromium
playwright install firefox
playwright install webkit

Docker 中使用 playwright 创建浏览器驱动缓存层

在 docker 容器内使用时,为避免每次重新构建镜像后都需要重新下载浏览器驱动,可以在 Dockerfile 中提前下载浏览器驱动,创建 docker 缓存层:

# 先单独安装 playwright 并下载 chromium,建立 playwright+chromium 的缓存层,避免每次 requirements.txt 变化都要重新下载 chromium
RUN pip install playwright && python -m playwright install --with-deps chromium

# 先单独 COPY requirements.txt 和安装依赖,这样 requirements.txt 不变时能缓存依赖层。
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

基本概念


context 浏览器上下文

​Playwright 中的 ​浏览器上下文(Browser Context) 用于 cookies、本地存储、缓存 等数据的隔离。 每个浏览器上下文(Browser Context)都是独立的会话环境,相互之间不会共享 cookies、本地存储等信息。

直接 browser.new_page() 使用 默认上下文

browser = await playwright.chromium.launch()
page = await browser.new_page()  # 使用默认上下文

系统自动创建并管理一个默认的浏览器上下文,所有通过 browser.new_page() 创建的页面共享​​同一个上下文​​。 Cookies、本地存储、缓存等数据在页面间共享。 ​​资源占用​​:轻量级,适合简单场景。 但页面间可能相互污染(例如一个页面修改 Cookie 会影响其他页面)。

显式创建上下文 browser.new_context()

browser = await playwright.chromium.launch()
context = await browser.new_context()  # 创建独立上下文
page = await context.new_page()         # 页面绑定到该上下文

每个上下文是独立的“隐身会话”。 上下文间完全隔离:Cookie、本地存储、缓存相互独立。 资源成本​​:每个上下文独立进程,占用更多资源。 可为不同上下文配置不同参数:

context = await browser.new_context(
    user_agent="自定义UA",
    viewport={"width": 1024, "height": 768},
    proxy={"server": "http://proxy.example.com:8080"},
    locale="zh-CN"
)

使用场景建议: ​​使用 browser.new_page()​​ 默认上下文

  • 简单脚本或单用户任务(无需环境隔离,例如,所有页面都在同一个用户会话下操作,共享相同的登录状态)
  • 资源有限,希望节省内存和启动时间。

​​使用 browser.new_context()​​ 独立上下文

  • 当需要多个独立的会话,例如模拟多个用户同时操作,或者需要完全隔离的环境(如一个测试用例需要干净的上下文,避免相互影响)。
  • 需要为不同的页面设置不同的上下文配置(例如不同的设备模拟、不同的权限设置、不同的代理等)。
  • 需要模拟不同的用户登录状态(例如一个管理员和一个普通用户)。
  • 在自动化测试中,通常每个测试用例都会创建一个新的上下文,以确保测试之间的隔离,避免状态泄漏。

page.goto() 打开页面

page.goto() 是 Playwright 中最核心的导航方法,用于将浏览器页面导航到指定 URL await page.goto("https://example.com") 页面将导航到指定 URL 并等待页面加载完成

页面等待策略 page.goto() 会等待页面达到特定加载状态后才返回,可通过 wait_until 参数控制。 page.goto 默认使用 load 等待策略 page.goto("https://example.com", wait_until="load")

超时时间 使用 timeout 参数设置导航最大等待时间(毫秒) await page.goto("https://example.com", timeout=30000) 设置 30 秒超时 或者全局设置默认超时时间 page.set_default_timeout(60000) 设置所有操作默认超时为 60 秒

自定义 HTTTP 头 可在导航时发送自定义 HTTP 头

await page.goto(
    "https://example.com",
    headers={
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
        "X-Custom-Header": "value"
    }
)

自动重定向 page.goto() 会自动处理重定向链,可获取最终响应:

response = await page.goto("https://short.url/xyz")
print(f"实际导航到的 URL: {response.url}")

Referer 控制 使用 referer 参数设置来源页面:

await page.goto("https://secured-site.com", referer="https://referring-site.com")

POST 提交表单 使用 POST 方法提交表单数据:

await page.goto(
    "https://example.com/login",
    method="POST",
    post_data={"username": "admin", "password": "123456"}
)

返回响应对象 page.goto() 返回一个响应对象,可获取响应信息:

response = await page.goto("https://example.com")
print(f"状态码: {response.status}")
print(f"标题: {response.headers['content-type']}")
print(f"响应文本: {await response.text()}")

page.route() 请求和响应拦截

page.route() 允许​拦截并修改浏览器的网络请求和响应​​

阻止所有图片加载

# 阻止所有图片加载
await page.route("**/*.{png,jpg,jpeg,gif,svg,ico,woff,woff2,ttf}", lambda route: route.abort())

Playwright 页面等待策略

Playwright 中 gotowait_for_load_state 函数中 wait_until 参数指定等待策略。

load(dom及静态资源)

load 默认策略 - 页面资源加载完成 load 等待策略只加载静态资源​​(HTML, CSS, JS),不包括:AJAX 请求、动态生成的内容、Lazy loading 图片 触发时机​​: 当页面的 load 事件触发时 ​​等待内容​​:

  • DOM解析完成
  • 所有同步资源加载完成(图片、样式表)

不等待​​:

  • AJAX/XHR 异步请求
  • 动态生成的内容
  • Lazy loading 图片
  • setTimeout/setInterval 回调

适用场景:

  • 传统网页(非SPA)
  • 静态内容页面
  • 截图基础布局

domcontentloaded(仅dom)

domcontentloaded 触发时机​​: 当页面的 DOMContentLoaded 事件触发时 等待内容​​:

  • HTML 文档解析完成
  • 同步脚本执行完成
  • 构建DOM树完成

不等待​​:

  • 样式表加载
  • 图片加载
  • 异步脚本执行

适用场景:

  • 表单操作
  • 数据提取(只需DOM结构)
  • 测试脚本执行

networkidle(无新网络请求)

networkidle 触发时机​​: 500ms内没有新的网络请求 等待内容​​:

  • 所有资源加载完成
  • 包含动态获取的资源
  • 页面进入稳定状态

适用场景:

  • 单页应用(React/Vue)
  • 内容动态加载页面
  • 需完整渲染的截图

commit(有HTTP相应即返回)

commit 触发时机​​: 收到HTTP响应头时 是最早完成的等待策略,此时页面内容可能尚未开始加载 适用场景:

  • 性能基准测试
  • 导航状态验证
  • 极速爬虫场景(配合自定义等待)

Playwright Python 操作示例

Playwright 打开网页并截图

p.chromium.launch(headless=True) 启动 chrome 浏览器 参数 headless

  • headless=True 默认值,无头模式,不显示浏览器界面。
  • headless=False 可视化模式,弹出浏览器界面
from playwright.sync_api import sync_playwright

def open_browser_and_screenshot():
    with sync_playwright() as p:
        # 启动浏览器 headless=False 可视化模式,弹出浏览器界面。默认值 true:无头模式,不显示浏览器界面。
        browser = p.chromium.launch(headless=True)
        # 打开新页面
        page = browser.new_page()
        # 导航到页面
        page.goto("http://masikkk.com/")
        # 截图保存
        page.screenshot(path="masikkk_screenshot.png")
        # 获取页面标题
        print(page.title())
        browser.close()

if __name__ == "__main__":
    open_browser_and_screenshot()

Playwright 打开网页并截图(异步)

import asyncio
from playwright.async_api import async_playwright

async def open_browser_and_screenshot_async():
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page()
        await page.goto("http://devgou.com/tools/crawler")
        await page.screenshot(path="devgou_screenshot.png")
        await browser.close()

if __name__ == "__main__":
    asyncio.run(open_browser_and_screenshot_async())

playwright-java

microsoft / playwright-java https://github.com/microsoft/playwright-java

Playwright for Java https://playwright.dev/java/