大家好,我是jobleap.cn的小九。
Playwright 是微软推出的新一代自动化测试/爬虫框架,支持 Chromium、Firefox、WebKit 三大浏览器,提供同步/异步 API,具备自动等待、强大的元素定位、网络拦截等核心能力。本文将从环境搭建到综合实战,全面串联 Playwright 的常用 API,帮助你快速掌握其核心用法。

一、环境搭建

1. 安装 Playwright 核心库

pip install playwright

2. 安装浏览器驱动

Playwright 需要对应浏览器的驱动文件,执行以下命令自动安装 Chromium、Firefox、WebKit(也可指定单一浏览器):

# 安装所有浏览器
playwright install

# 仅安装 Chromium(常用)
playwright install chromium

3. 验证安装

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://www.baidu.com")
    print(page.title())  # 输出:百度一下,你就知道
    browser.close()

二、核心概念(必懂)

Playwright 的核心层级关系:PlaywrightBrowserBrowserContextPage

  • Browser:浏览器实例(对应真实浏览器进程),支持多浏览器(Chromium/Firefox/WebKit)。
  • BrowserContext:浏览器上下文(类似隐身窗口),隔离的环境,一个 Browser 可创建多个 Context。
  • Page:页面(对应浏览器标签页),一个 Context 可创建多个 Page。

三、常用 API 详解与实战

1. 浏览器启动与配置(Browser API)

核心方法:playwright.chromium.launch()(Firefox/webkit 同理),常用参数:

  • headless:是否无头模式(默认 True,无界面)。
  • slow_mo:慢动作执行(单位 ms,便于调试)。
  • args:浏览器启动参数(如窗口大小、禁用图片加载)。
  • timeout:启动超时时间(默认 30000 ms)。
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    # 启动 Chromium 有头模式,窗口大小 1920x1080,慢动作 500ms
    browser = p.chromium.launch(
        headless=False,
        slow_mo=500,
        args=["--window-size=1920,1080", "--disable-images"]  # 禁用图片加载
    )
    
    # 创建上下文(可配置视口、超时、代理等)
    context = browser.new_context(
        viewport={"width": 1920, "height": 1080},
        timeout=10000,  # 上下文级别超时
        user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0 Safari/537.36"
    )
    
    # 创建页面
    page = context.new_page()
    page.goto("https://www.baidu.com")
    
    # 关闭资源(建议用 with 上下文自动关闭,此处手动演示)
    page.close()
    context.close()
    browser.close()

2. 页面基础操作(Page API)

(1)导航与刷新
  • goto(url, wait_until):导航到指定 URL,wait_until 可选 load(页面加载完成)、domcontentloaded(DOM 加载完成)、networkidle(网络空闲)。
  • reload():刷新页面。
  • go_back()/go_forward():前进/后退。
# 导航到百度,等待网络空闲(适合异步加载页面)
page.goto("https://www.baidu.com", wait_until="networkidle")

# 刷新页面
page.reload()

# 后退/前进
page.go_back()
page.go_forward()

# 获取页面信息
print("页面标题:", page.title())
print("页面URL:", page.url)
print("页面内容:", page.content())  # 获取整个页面 HTML
(2)窗口控制
# 设置页面大小
page.set_viewport_size({"width": 1200, "height": 800})

# 最大化窗口
page.set_viewport_size(page.viewport_size())  # 或通过浏览器 args 设置

# 截图(整页/元素)
page.screenshot(path="full_page.png", full_page=True)  # 整页截图
page.locator("#su").screenshot(path="button.png")  # 元素截图

3. 元素定位(核心)

Playwright 推荐语义化定位(优先)+ CSS/XPath 定位,支持 8 种定位方式,优先级从高到低:

定位方式API 示例适用场景
按角色(Role)page.get_by_role("button", name="百度一下")按钮、输入框等可访问性元素
按文本page.get_by_text("百度一下")固定文本的元素
按标签(Label)page.get_by_label("搜索")输入框的标签
按占位符page.get_by_placeholder("请输入搜索内容")输入框占位符
按 Alt 文本page.get_by_alt_text("百度logo")图片元素
按 Title 属性page.get_by_title("百度首页")带 title 的元素
按测试 IDpage.get_by_test_id("search-btn")自定义 data-testid 属性
CSS/XPathpage.locator("#kw")/page.locator('//*[@id="kw"]')通用定位

示例:百度搜索框定位

# 语义化定位(推荐)
search_input = page.get_by_placeholder("请输入搜索内容")  # 按占位符
search_btn = page.get_by_role("button", name="百度一下")   # 按角色+名称

# CSS 定位(兼容传统方式)
search_input = page.locator("#kw")  # ID 选择器
search_btn = page.locator(".btn-self")  # 类选择器

# XPath 定位
search_input = page.locator('//input[@id="kw"]')

4. 元素交互(Page/Locator API)

(1)基础交互
  • fill(text):输入文本(清空原有内容)。
  • type(text, delay):模拟键盘逐字符输入(带延迟)。
  • click():点击元素(自动等待元素可点击)。
  • hover():悬停。
  • dblclick():双击。
# 输入搜索内容(清空原有内容)
search_input.fill("Playwright Python 教程")

# 模拟键盘输入(逐字符,延迟 100ms)
search_input.type("Playwright Python 教程", delay=100)

# 点击搜索按钮
search_btn.click()

# 悬停到导航栏
page.locator("#nav-top").hover()
(2)表单操作
  • check()/uncheck():勾选/取消复选框。
  • select_option():选择下拉框。
  • press(key):按键操作(如 Enter、Ctrl+A)。
# 复选框
page.locator("#agree").check()  # 勾选
page.locator("#agree").uncheck()  # 取消

# 下拉框(按值/标签/索引)
page.locator("#city").select_option(value="beijing")  # 按值
page.locator("#city").select_option(label="北京")     # 按标签
page.locator("#city").select_option(index=0)         # 按索引

# 按键操作
search_input.press("Enter")  # 按回车搜索
page.press("Ctrl+A")         # 全选页面内容
page.press("Backspace")      # 删除选中内容

5. 等待机制(避免硬等待)

Playwright 自带自动等待(操作元素时等待元素可见、可操作),也支持手动等待:

(1)显式等待
# 等待元素可见(超时 5 秒)
page.locator("#kw").wait_for(state="visible", timeout=5000)

# 等待元素可点击
page.locator("#su").wait_for(state="enabled")

# 等待页面加载状态
page.wait_for_load_state("networkidle")

# 等待自定义条件(如标题包含指定内容)
page.wait_for_function("document.title.includes('Playwright')")
(2)超时配置
# 页面级别默认超时(所有操作生效)
page.set_default_timeout(5000)

# 单个操作超时(覆盖全局)
page.locator("#kw").click(timeout=3000)

6. 数据提取

(1)元素数据提取
# 获取元素文本(含隐藏文本)
text = page.locator("h3").first.text_content()

# 获取可见文本
visible_text = page.locator("h3").first.inner_text()

# 获取属性值
href = page.locator("a").first.get_attribute("href")

# 获取所有匹配元素的文本列表
all_titles = page.locator("h3").all_text_contents()
print("所有标题:", all_titles)
(2)录屏(需上下文配置)
# 创建上下文时指定录屏目录
context = browser.new_context(record_video_dir="./videos/")
page.goto("https://www.baidu.com")
context.close()  # 关闭后自动生成视频文件

7. 网络拦截与请求处理

Playwright 可拦截、修改、模拟网络请求/响应,适用于爬虫反爬、接口测试。

# 拦截所有图片请求(中止加载,提升速度)
def handle_image_route(route):
    route.abort()  # 中止请求
    # 也可模拟响应:route.fulfill(status=200, body="mock image")

page.route("**/*.{png,jpg,jpeg}", handle_image_route)

# 等待特定请求并获取参数
request = page.wait_for_request("https://www.baidu.com/s")
print("请求方法:", request.method)
print("请求参数:", request.post_data)

# 等待特定响应并解析内容
response = page.wait_for_response("https://www.baidu.com/s")
print("响应状态码:", response.status)
print("响应JSON:", response.json())  # 接口返回JSON时解析

8. 多标签页/多上下文操作

(1)多标签页
# 打开新标签页
page1 = context.new_page()
page1.goto("https://www.baidu.com")

page2 = context.new_page()
page2.goto("https://www.github.com")

# 切换标签页
page2.bring_to_front()

# 获取所有标签页
pages = context.pages
print("标签页数量:", len(pages))
(2)多上下文(隔离环境)
# 上下文1:模拟用户A
context1 = browser.new_context()
page1 = context1.new_page()
page1.goto("https://www.taobao.com")

# 上下文2:模拟用户B(隔离Cookie)
context2 = browser.new_context()
page2 = context2.new_page()
page2.goto("https://www.taobao.com")

9. 弹窗处理(Alert/Confirm/Prompt)

Playwright 可监听并处理浏览器原生弹窗:

# 监听 Alert 弹窗(自动接受)
page.on("dialog", lambda dialog: dialog.accept())

# 监听 Confirm 弹窗(根据消息决定接受/取消)
page.on("dialog", lambda dialog: dialog.accept() if "确认" in dialog.message() else dialog.dismiss())

# 监听 Prompt 弹窗(输入内容并接受)
page.on("dialog", lambda dialog: dialog.accept(prompt_text="测试内容"))

# 触发弹窗(演示用)
page.evaluate("alert('这是一个Alert弹窗')")
page.evaluate("confirm('确认删除?')")
page.evaluate("prompt('请输入姓名:')")

四、综合实战:电商商品信息爬取

需求:爬取京东“Python编程书籍”第一个商品的名称、价格、评价数,并截图保存。

from playwright.sync_api import sync_playwright

def crawl_jd_goods():
    with sync_playwright() as p:
        # 启动浏览器
        browser = p.chromium.launch(headless=False, slow_mo=300)
        context = browser.new_context(viewport={"width": 1920, "height": 1080})
        page = context.new_page()
        
        try:
            # 1. 导航到京东首页
            page.goto("https://www.jd.com", wait_until="networkidle")
            
            # 2. 搜索商品
            search_input = page.get_by_placeholder("家用电器,手机数码,电脑办公")
            search_input.fill("Python编程从入门到实践")
            search_input.press("Enter")
            
            # 3. 等待搜索结果加载,点击第一个商品
            page.wait_for_load_state("networkidle")
            first_goods = page.locator(".gl-item .p-name a").first
            first_goods.click()
            
            # 4. 切换到商品详情页(新标签页)
            page.wait_for_event("popup")
            goods_page = context.pages[-1]  # 最后一个标签页为详情页
            goods_page.bring_to_front()
            goods_page.wait_for_load_state("networkidle")
            
            # 5. 提取商品信息(京东标签可能更新,需按需调整)
            goods_name = goods_page.locator(".sku-name").inner_text().strip()
            goods_price = goods_page.locator(".price").first.inner_text().strip()
            comment_count = goods_page.locator("#comment-count").inner_text().strip()
            
            # 6. 输出并截图
            print("="*50)
            print("商品名称:", goods_name)
            print("商品价格:", goods_price)
            print("评价数:", comment_count)
            print("="*50)
            goods_page.screenshot(path="jd_goods.png", full_page=True)
            
        except Exception as e:
            print("爬取出错:", e)
        finally:
            browser.close()

if __name__ == "__main__":
    crawl_jd_goods()

五、高级技巧与注意事项

1. 异步 API(适合高并发)

Playwright 支持异步编程,核心替换 sync_playwrightasync_playwright

import asyncio
from playwright.async_api import async_playwright

async def async_demo():
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=False)
        page = await browser.new_page()
        await page.goto("https://www.baidu.com")
        print(await page.title())
        await browser.close()

asyncio.run(async_demo())

2. 反爬规避

  • 设置真实 user_agent(上下文配置)。
  • 添加随机延迟(slow_motime.sleep,慎用)。
  • 使用代理 IP(上下文配置 proxy={"server": "http://ip:port"})。
  • 避免高频操作,模拟真人行为(悬停、滚动)。

3. 测试框架集成

Playwright 可与 pytest 集成(pytest-playwright),实现自动化测试:

pip install pytest-playwright

4. 注意事项

  • 避免使用 time.sleep,优先用 Playwright 内置等待。
  • 元素定位优先语义化方式(get_by_role),减少 CSS/XPath 维护成本。
  • 无头模式下部分页面渲染可能不同,调试时用有头模式。
  • 浏览器驱动版本需与 Playwright 版本匹配(playwright install 自动适配)。

六、总结

Playwright 凭借自动等待、跨浏览器、强大的定位与网络拦截能力,成为 Python 自动化/爬虫领域的主流工具。本文串联了浏览器启动、页面操作、元素定位、交互、数据提取、网络拦截等核心 API,并通过实战案例验证了用法。掌握这些 API 后,可高效完成网页自动化测试、数据爬取、表单自动提交等场景的开发。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐