一、开头痛点:驱动、等待、玄学报错
做过网页自动化的同学,大概率被这三件事折磨过:
- 装驱动:
chromedriver的版本必须和本机 chrome 严丝合缝,浏览器一自动升级,脚本第二天就sessionnotcreatedexception。 - 等元素:页面还没渲染完就
find_element,报nosuchelementexception;于是满屏time.sleep(3),慢且不稳。 - 换浏览器:selenium 要分别配 chrome、firefox、edge 的驱动,环境一换全得重来。
playwright 把这三点一次性解决了:自带浏览器(一条命令下载,版本永远匹配)、操作自带自动等待(不用手写 sleep)、一套 api 通吃 chromium / firefox / webkit。它由微软团队维护,python 版 api 设计得很干净,写起来比 selenium 顺手不少。
二、环境准备:两条命令
playwright 支持 python 3.8+。同样建议用虚拟环境隔离:
python -m venv .venv source .venv/bin/activate # windows 用 .venv\scripts\activate # 第一步:装 python 包 pip install playwright # 第二步:下载浏览器内核(约 100~300mb,只需执行一次) playwright install chromium
第二步是很多新手卡住的地方——它下载的是 playwright 自带的浏览器,不是你桌面上那个 chrome,所以不存在版本对不上的问题。国内下载慢可以走镜像:
# 使用国内镜像加速下载 playwright_download_host=https://cdn.npmmirror.com/binaries/playwright playwright install chromium
验证安装:
# check_env.py
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=true)
page = browser.new_page()
page.goto("https://example.com")
print("页面标题:", page.title())
browser.close()
能打印出 example domain 就说明环境没问题。
三、最小可运行示例:打开页面并截图
playwright 有同步和异步两套 api,日常脚本用同步版最省心:
# shot.py
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
# headless=true 表示无界面运行;调试时改成 false 能看到真实浏览器
browser = p.chromium.launch(headless=true)
page = browser.new_page(viewport={"width": 1280, "height": 800})
page.goto("https://www.python.org/")
# full_page=true 会截取整页长图,不只是可视区域
page.screenshot(path="python_org.png", full_page=true)
browser.close()
对比 selenium,同样的功能少了驱动配置、少了显式等待,代码块从十几行压到十行以内。
四、核心概念:locator、自动等待、上下文
4.1 locator:定位元素的新写法
playwright 推荐用 locator() 拿到元素句柄,所有操作都基于它:
# 下面几种写法等价,选你顺手的
page.locator("button#submit").click()
page.locator("text=登录").click()
page.get_by_role("button", name="登录").click() # 按语义角色,最稳
page.get_by_placeholder("请输入用户名").fill("admin")
page.get_by_text("下一步").click()
locator 是惰性的:写 page.locator(...) 时不会真的去查 dom,只有执行 .click()、.fill() 时才查找,并且会自动等到元素可见、可点击、不被遮挡。这就是「自动等待」。
4.2 自动等待:和 time.sleep 说再见
from playwright.sync_api import expect
# 断言元素可见(默认超时 5 秒,期间反复重试)
expect(page.get_by_text("提交成功")).to_be_visible(timeout=10000)
# 断言 url 变化
expect(page).to_have_url("https://example.com/dashboard")
expect 是 playwright 官方的断言工具,比 assert page.title() == ... 更可靠,因为它会轮询等待而不是一次性判断。需要改全局超时可以这样:
page.set_default_timeout(15000) # 所有操作默认最多等 15 秒
4.3 上下文:多开互不干扰的会话
context 相当于一个独立的浏览器会话(独立的 cookie、缓存),比开多个 browser 省资源:
with sync_playwright() as p:
browser = p.chromium.launch()
# 模拟移动端 + 中文环境
ctx = browser.new_context(
viewport={"width": 390, "height": 844},
user_agent="mozilla/5.0 (iphone; cpu iphone os 17_0 like mac os x) applewebkit/605.1.15",
locale="zh-cn",
)
page = ctx.new_page()
page.goto("https://example.com")
ctx.close() # 关上下文,cookie 一起清掉
browser.close()
五、进阶用法:表单、上传、拦截
5.1 填表单与键盘鼠标
page.get_by_label("用户名").fill("zhangsan")
page.get_by_label("密码").fill("secret123")
page.get_by_label("记住我").check()
page.get_by_role("combobox").select_option("beijing")
page.keyboard.press("enter")
5.2 文件上传与下载
# 上传:直接给本地路径,不用再找系统文件框
page.set_input_files("input[type=file]", "report.xlsx")
# 下载:必须用 expect_download 包住触发动作
with page.expect_download() as dl:
page.get_by_text("导出报表").click()
download = dl.value
download.save_as("data/export.xlsx")
5.3 拦截请求:屏蔽图片提速
抓数据时图片、字体往往没用,直接拦掉能明显加速:
def block_images(route):
if route.request.resource_type in ("image", "font", "media"):
route.abort()
else:
route.continue_()
page.route("**/*", block_images)
page.goto("https://news.example.com")
六、实战场景:自动登录并抓取列表(完整代码)
下面这个例子把上面几点串起来,带登录态抓取分页数据,并保存截图:
# crawl_demo.py
from playwright.sync_api import sync_playwright, expect
base = "https://example.com"
def main():
with sync_playwright() as p:
browser = p.chromium.launch(headless=true)
ctx = browser.new_context(locale="zh-cn")
page = ctx.new_page()
page.set_default_timeout(15000)
# 1. 登录
page.goto(f"{base}/login")
page.get_by_label("账号").fill("your_account")
page.get_by_label("密码").fill("your_password")
page.get_by_role("button", name="登录").click()
# 等到跳转完成,不要用 sleep
expect(page).to_have_url(f"{base}/dashboard")
# 2. 抓多页列表
rows = []
for page_no in range(1, 4):
page.goto(f"{base}/items?page={page_no}")
expect(page.locator(".item-row").first).to_be_visible()
items = page.locator(".item-row").all()
for it in items:
rows.append({
"title": it.locator(".title").inner_text(),
"price": it.locator(".price").inner_text(),
})
print(f"第 {page_no} 页抓到 {len(items)} 条")
# 3. 保存登录态,下次直接复用,省掉重复登录
ctx.storage_state(path="auth.json")
print("共抓取", len(rows), "条")
browser.close()
if __name__ == "__main__":
main()
下次运行时直接加载已保存的登录态:
ctx = browser.new_context(storage_state="auth.json")
七、和 selenium 怎么选
| 维度 | playwright | selenium |
|---|---|---|
| 浏览器驱动 | 自带,一条命令安装 | 需手动下载、版本必须匹配 |
| 等待机制 | 操作自带自动等待 | 需自己写 webdriverwait 或 sleep |
| 多浏览器 | 一套 api 支持 chromium/firefox/webkit | 每个浏览器各自适配 |
| 录制脚本 | playwright codegen 官方支持 | 依赖第三方插件 |
| 网络拦截 | 原生 page.route | 需借助代理 |
| 生态与资料 | 较新,中文资料相对少 | 十年积累,资料最多、岗位要求常见 |
结论:新项目优先 playwright,效率和稳定性都更好;老项目或需要兼容既有 selenium 资产的继续用 selenium,两者并不互斥。
八、常见坑与解决办法
1)playwright install 卡住或超时 换国内镜像,见第二节。公司网络有代理时设置 https_proxy 环境变量再执行。
2)locator.click() 超时 先确认是不是在 iframe 里。跨框架要先切进去:
frame = page.frame_locator("iframe#login-frame")
frame.get_by_role("button", name="登录").click()
3)被网站识别为自动化 默认 headless 会带自动化特征,可以加启动参数缓解:
browser = p.chromium.launch(
headless=true,
args=["--disable-blink-features=automationcontrolled"],
)
4)抓到的中文乱码 确认 new_context(locale="zh-cn"),并且写入文件时指定编码 encoding="utf-8",windows 上尤其容易踩。
5)调试时看不到过程 打开录制,事后回看每一步:
ctx.tracing.start(screenshots=true, snapshots=true) # ... 你的操作 ... ctx.tracing.stop(path="trace.zip")
用 playwright show-trace trace.zip 可以在浏览器里逐步回放。
九、总结与下一步
playwright 的三个核心优势:自带浏览器(告别驱动地狱)、自动等待(告别满屏 sleep)、统一 api(一套代码跑三种内核)。如果你之前被 selenium 的驱动和等待折腾过,换过来基本是纯收益。
下一步建议:
- 用
playwright codegen https://你的目标站点录一遍,看看官方推荐的选择器怎么写; - 把现有脚本里的
time.sleep逐步替换为expect(...)断言; - 需要并发时改用异步 api(
from playwright.async_api import async_playwright)配合asyncio.gather。
以上就是python playwright入门指南之网页自动化操作详解的详细内容,更多关于python playwright自动化的资料请关注代码网其它相关文章!
发表评论