找回密码
 立即注册
搜索
查看: 3|回复: 0

playwright教程

[复制链接]

4

主题

0

回帖

20

积分

管理员

积分
20
发表于 3 小时前 | 显示全部楼层 |阅读模式
一、安装
  1. uv add playwright
  2. uv add pytest-playwright
  3. playwright install
  4. #只安装指定浏览器示例
  5. playwright install chromium
复制代码


二、最小示例(同步 API)
sync_api适合简单脚本;项目推荐异步API性能更好。
  1. from playwright.sync_api import sync_playwright

  2. def run():
  3.     with sync_playwright() as p:
  4.         # 启动浏览器,headless=False显示浏览器窗口
  5.         browser = p.chromium.launch(headless=False)
  6.         page = browser.new_page()
  7.         page.goto("https://www.baidu.com")

  8.         print(page.title())
  9.         page.screenshot(path="baidu.png")

  10.         browser.close()

  11. if __name__ == "__main__":
  12.     run()
复制代码

   
三、异步API(推荐生产使用)
  1. import asyncio
  2. from playwright.async_api import async_playwright

  3. async def main():
  4.     async with async_playwright() as p:
  5.         browser = await p.chromium.launch(headless=False)
  6.         page = await browser.new_page()
  7.         await page.goto("https://www.baidu.com")
  8.         print(await page.title())
  9.         await page.screenshot(path="baidu_async.png")
  10.         await browser.close()

  11. asyncio.run(main())
复制代码


四、浏览器启动常用参数
  1. browser = p.chromium.launch(
  2.     headless=False,               # True无头模式不弹出窗口
  3.     slow_mo=500,                  # 每个动作延迟ms,方便调试
  4.     args=[
  5.         "--no-sandbox",
  6.         "--disable-setuid-sandbox",
  7.         "--user-agent=Mozilla/5.0 xxx"
  8.     ],
  9.     channel="chrome",             # 使用本机安装的Chrome,不用内置chromium
  10. )
复制代码


五、页面Page对象核心API
访问页面
  1. await page.goto(
  2.     url,
  3.     timeout=30000,        # 超时毫秒
  4.     wait_until="networkidle" # load|domcontentloaded|networkidle
  5. )
复制代码

networkidle:网络空闲,适合等待 js 渲染完毕。
等待机制(非常重要,不要写 time.sleep)
playwright 自带自动等待,元素操作前自动等待元素可交互。
手动等待:
  1. # 等待选择器出现
  2. await page.wait_for_selector("#search-input", timeout=10000)
  3. # 等待页面跳转完成
  4. await page.wait_for_url("**/result*")
  5. # 等待函数条件返回True
  6. await page.wait_for_function("() => document.title.length > 0")
复制代码


定位元素 Locator(官方推荐,代替旧的 page.query_selector)
Locator 是惰性定位,不会立刻查询 DOM,动作执行时才查找。
  1. # css选择器
  2. loc = page.locator("#kw")
  3. # xpath
  4. loc = page.locator("//input[@id='kw']")
  5. # 文本匹配
  6. loc = page.locator("text=百度一下")
  7. # 精确文本
  8. loc = page.locator("text='百度一下'")

  9. # 多个元素
  10. all_items = page.locator(".item").all()
  11. count = await page.locator(".item").count()
复制代码


元素操作
  1. # 输入文本
  2. await page.locator("#kw").fill("playwright教程")
  3. # 点击
  4. await page.locator("#su").click()
  5. # 双击
  6. await loc.dblclick()
  7. # 悬停
  8. await loc.hover()
  9. # 获取文本
  10. text = await page.locator("#result").text_content()
  11. # 获取属性
  12. attr = await page.locator("a").get_attribute("href")
  13. # 获取inner_html
  14. html = await page.locator("#main").inner_html()
  15. # 勾选复选框
  16. await page.locator("#agree").check()
  17. # 下拉选择
  18. await page.locator("#select").select_option("value1")
  19. # 键盘按键
  20. await page.keyboard.press("Enter")
  21. await page.keyboard.type("hello")
复制代码


六、截图、PDF
  1. # 可视区域截图
  2. await page.screenshot(path="screen.png")
  3. # 完整长页面截图
  4. await page.screenshot(path="full.png", full_page=True)

  5. # 导出PDF(仅chromium headless)
  6. await page.pdf(path="out.pdf", format="A4")
复制代码


七、处理弹窗、对话框
  1. page.on("dialog", lambda dialog: dialog.accept())
  2. await page.evaluate("alert('hello')")
复制代码


八、网络拦截、请求监听
监听请求响应
  1. def handle_request(req):
  2.     print(f"req:{req.method} {req.url}")

  3. def handle_response(resp):
  4.     if resp.status == 200:
  5.         print(resp.url)

  6. page.on("request", handle_request)
  7. page.on("response", handle_response)
复制代码

拦截修改请求,屏蔽图片 /css 加速爬虫
  1. await page.route("**/*.{png,jpg,jpeg,gif}", lambda route: route.abort())

  2. # 修改post请求
  3. async def modify_req(route):
  4.     headers = route.request.headers.copy()
  5.     headers["token"] = "xxxx"
  6.     await route.continue_(headers=headers)

  7. await page.route("**/api/login", modify_req)
复制代码


九、执行 JS 脚本
  1. # 无参数
  2. res = await page.evaluate("() => document.title")

  3. # 传参数
  4. res = await page.evaluate("(a,b)=> a+b", 10,20)

  5. # 在元素上执行js
  6. loc = page.locator("#id")
  7. val = await loc.evaluate("el => el.value")
复制代码


十、多页面、多标签
  1. # 新建tab
  2. page2 = await browser.new_page()
  3. await page2.goto("https://github.com")

  4. # 监听页面弹出
  5. new_page_coro = page.wait_for_event("page")
  6. await page.locator("text=打开新窗口").click()
  7. new_tab = await new_page_coro
复制代码


十一、上下文 Context:模拟浏览器环境,保存 cookie、本地存储
不要每次 new_page,优先使用 browser_context,隔离会话。
  1. context = await browser.new_context(
  2.     viewport={"width":1280,"height":720},
  3.     user_agent="Mozilla/5.0 ...",
  4.     locale="zh-CN",
  5.     geolocation={"latitude":22.54,"longitude":114.06},
  6.     permissions=["geolocation"]
  7. )

  8. # 加载cookie
  9. context.add_cookies([
  10.     {"name":"sessionid","value":"xxx","domain":".baidu.com","path":"/"}
  11. ])

  12. page = await context.new_page()

  13. # 保存cookie
  14. cookies = await context.cookies()
复制代码

持久化上下文(保存登录状态,下次免登录)
  1. context = await browser.new_context(storage_state="state.json")
  2. # 执行登录操作
  3. await context.storage_state(path="state.json")
复制代码

下次运行直接加载storage_state="state.json",cookie/localStorage 直接恢复。

十二、iframe 处理
  1. # 通过frame定位
  2. frame = page.frame_locator("iframe#myframe")
  3. await frame.locator("#input-inside-iframe").fill("test")
复制代码


十三、文件上传下载
文件上传
  1. # input type="file"
  2. await page.locator("input[type='file']").set_input_files(["a.jpg","b.jpg"])
复制代码

文件下载
  1. async with page.expect_download() as download_info:
  2.     await page.locator("text=下载文件").click()
  3. download = await download_info.value
  4. await download.save_as("./down.zip")
复制代码


十四、反爬相关配置
1. 关闭检测特征
  1. context = await browser.new_context(
  2.     extra_http_headers={"Accept-Language":"zh-CN,zh;q=0.9"}
  3. )
  4. # 隐藏webdriver标记
  5. await page.add_init_script("""
  6. Object.defineProperty(navigator, 'webdriver', {get: () => undefined})
  7. """)
复制代码

2. 使用slow_mo减慢操作速度,模拟真人
3. 尽量使用locator,不要大量 evaluate 硬写 js
4. 代理设置
  1. browser = await p.chromium.launch(proxy={
  2.     "server":"http://127.0.0.1:7890"
  3. })
复制代码


十五、异常与调试技巧
1. 开启 trace 录制,生成可视化调试报告
  1. await context.tracing.start(screenshots=True, snapshots=True, sources=True)
  2. # 自动化操作......
  3. await context.tracing.stop(path="trace.zip")
复制代码

运行:playwright show-trace trace.zip打开网页调试,可以回放每一步操作。
2. 断点暂停
  1. await page.pause()
复制代码

执行会打开 playwright inspector 调试器,可以直接复制 locator 选择器。
3. 常见报错
- TimeoutError:元素没出现,检查选择器、检查 wait_until,确认页面是否动态渲染。
- 沙箱报错 linux 环境:启动参数加args=["--no-sandbox"]

十六、实战小案例:异步爬虫抓取百度搜索结果
  1. import asyncio
  2. from playwright.async_api import async_playwright

  3. async def search_baidu(keyword):
  4.     async with async_playwright() as p:
  5.         browser = await p.chromium.launch(headless=True, args=["--no‑sandbox"])
  6.         context = await browser.new_context()
  7.         page = await context.new_page()
  8.         await page.goto("https://www.baidu.com", wait_until="networkidle")
  9.         await page.locator("#kw").fill(keyword)
  10.         await page.locator("#su").click()
  11.         await page.wait_for_selector(".result")

  12.         items = await page.locator(".result").all()
  13.         res = []
  14.         for item in items:
  15.             title = await item.locator("h3").text_content()
  16.             href = await item.locator("a").get_attribute("href")
  17.             res.append({"title":title,"href":href})
  18.         await browser.close()
  19.         return res

  20. if __name__ == "__main__":
  21.     data = asyncio.run(search_baidu("playwright python教程"))
  22.     for d in data:
  23.         print(d)
复制代码


十七、单元测试 pytest-playwright
直接写测试用例,fixture 自动提供 page 对象。
  1. def test_baidu(page):
  2.     page.goto("https://www.baidu.com")
  3.     assert "百度" in page.title()
复制代码

运行:
  1. pytest test_demo.py --browser chromium --headed
复制代码


十八、核心最佳实践总结
1. 优先使用 Locator,不要用query_selector,locator 自动重试,更稳定。
2. 禁止time.sleep(),使用 playwright 内置 wait_for_* 等待。
3. 使用BrowserContext隔离会话,方便持久化登录状态 storage_state。
4. 爬虫场景:拦截图片、css 资源减少带宽;必要配置代理。
5. 调试优先用page.pause()或者 trace 录制。
6. 大规模并发使用异步 API,不要同步。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|skypiea

GMT+8, 2026-9-4 13:43 , Processed in 0.042831 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表