playwright是微软在2020年开源的新一代支持异步的自动化测试工具,对市面上的主流浏览器(Chromium、Firefox、Webkit)都提供了支持,API功能简洁又强大。
官网文档:https://playwright.dev/python/docs/api/class-playwright
一、特点
- 安装和配置过程非常简单,安装过程中自动安装对应的浏览器和驱动
- 支持无头、有头模式
- 提供和自动等待相关的API,页面加载时会自动等待对应的节点加载,大大减小编写复杂度,比如:page.wait_for_load_state(state='networkidle'),会等待页面加载完成
二、安装
-
安装依赖
pip3 install playwright
python版本需要 > 3.7
-
安装驱动
playwright install
会下载全部驱动,速度较慢,如果只安装某一个驱动,就在命令后带上驱动名,可以用:playwright install --help查看命令
三、基本使用
-
同步模式 -- 类似于Selenium
from playwright.sync_api import sync_playwright with sync_playwright() as p: for browser_type in [p.chromium, p.firefox, p.webkit]: browser = browser_type.launch(headless=False) page = browser.new_page() page.goto('https://www.baidu.com/') page.screenshot(path=f'{browser_type.name}.png') print(page.title()) browser.close()
-
异步模式 -- 类似于Pyppetter
import asyncio from playwright.async_api import async_playwright async def main(): async with async_playwright() as p: for browser_type in [p.chromium, p.firefox, p.webkit]: browser = await browser_type.launch(headless=False) page = await browser.new_page() await page.goto('https://www.baidu.com/') await page.screenshot(path=f'{browser_type.name}.png') print(await page.title()) await browser.close() asyncio.run(main())
-
移动端浏览器页面
from playwright.sync_api import sync_playwright with sync_playwright() as playwright: iphone = playwright.devices["iPhone 12"] browser = playwright.webkit.launch(headless=False) context = browser.new_context(**iphone) page = context.new_page() page.goto("https://weibo.com/") page.wait_for_load_state(state='networkidle') # 当前页面初始化和加载完成的状态 page.screenshot(path='weibo.png') browser.close()
四、自动录制脚本
该功能可以录制我们在浏览器中的操作并自动生成代码,有了该功能,甚至一行代码都不用写
-
命令行
playwright codegen
执行命令后会自动打开浏览器,后续在浏览器上的操作都会自动翻译成代码
-
查看codegen命令具体参数
playwright codegen --help
-
具体参数:
-o, --output <file name> saves the generated script to a file --target <language> language to generate, one of javascript, playwright-test, python, python-async, python-pytest, csharp, csharp-mstest, csharp-nunit, java (default: "python") --save-trace <filename> record a trace for the session and save it to a file -b, --browser <browserType> browser to use, one of cr, chromium, ff, firefox, wk, webkit (default: "chromium") --block-service-workers block service workers --channel <channel> Chromium distribution channel, "chrome", "chrome-beta", "msedge-dev", etc --color-scheme <scheme> emulate preferred color scheme, "light" or "dark" --device <deviceName> emulate device, for example "iPhone 11" --geolocation <coordinates> specify geolocation coordinates, for example "37.819722,-122.478611" --ignore-https-errors ignore https errors --load-storage <filename> load context storage state from the file, previously saved with --save-storage --lang <language> specify language / locale, for example "en-GB" --proxy-server <proxy> specify proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080" --timeout <timeout> timeout for Playwright actions in milliseconds, no timeout by default --user-agent <ua string> specify user agent string --viewport-size <size> specify browser viewport size in pixels, for example "1280, 720" -h, --help display help for command
五、选择器
除了正常的css选择器以外,还扩展了文本选择、xpath、以及css选择器与文本和节点关系来配合筛选
- 选择器
# css选择器 page.click('#button') # 文本选择器 page.click('text=登录') # 开头需指明'text=' # xpath选择器 page.click('xpath=//button') # 开头需指明'xpath=' # css选择器+文本 page.click('p:has-text("Playwright")') # :has-text() -> 包含指定字符串 page.click('p:has-text("contact us")') # :text() -> 完全匹配字符串 # css选择器+节点关系 page.click('p:has(span)') # :has() -> 包含某个子节点 选择包含span子节点的p标签 page.click('input:right-of(:text("用户名"))') # :right-of() -> 位置在某个节点的右侧 选择在文本内容为'用户名'节点右侧的input节点
六、常用方法
-
方法
# 监听事件, 比如close、console、load、request、response等 page.on(event, callback) # 请求拦截 page.route(url, handler) # url可以是普通字符串,也可以是正则pattern字符串,即re.compile(r'xxx') # 设置页面大小 page.set_viewport_size({'width':1366, 'height':768}) # 访问具体网站 page.goto(url) # 等待页面加载完成 page.wait_for_load_state(state='networkidle') # 截图 page.screenshot(type=None, path=None) # 点击页面元素 page.click(selector) # 获取页面源码 page.content() # 获取单个节点 element = page.query_selector(selector) element.get_attribute('属性名') # 获取节点属性 element.text_content() # 获取节点文本 # 获取多个节点 elements = page.query_selector_all(selector) for ele in elements: ele.get_attribute('属性名') # 获取属性 ele.text_content() # 获取文本 # 文本输入 # 方式一 page.fill(selector, value, timeout=None) # 根据选择器,输入文本内容,timeout可设置对应节点的最长等待时间 # 方式二: 可以先获取节点,然后调用节点的fill()方法
七、事件监听
Page对象提供了on方法,用来监听页面中的各个事件,比如close、console、load、request、response等
-
示例
from playwright.sync_api import sync_playwright def on_response(response): # 直接截获ajax请求数据 if '/api/movie' in response.url and response.status == 200: print(response.json()) with sync_playwright() as playwright: browser = playwright.chromium.launch(headless=False) page = browser.new_page() # 事件监听,例如close、console、load、request、response等 page.on('response', on_response) page.goto("https://spa6.scrape.center/") # 访问网址 page.wait_for_load_state(state='networkidle') # 等待当前页面初始化和加载完成 browser.close()
八、请求拦截器
-
page.route(url, handler)
- 参数1:表示匹配的url
- 1、可以是完整的url,或者url的后半部分(必须到末位字符)
- 比如'https://www.baidu.com/'、'www.baidu.com/'、'baidu.com'等均可拦截'https://www.baidu.com/'
- 2、可以是正则pattern
- 比如re.compile(r'\.(png|jpg|jpeg)')
- 1、可以是完整的url,或者url的后半部分(必须到末位字符)
- 参数2:handler(route)
- 参数route:
- route.request:返回Request对象
- route.abort():停止请求
- route.continue_()
- 不指定参数,表示继续请求
- 指定关键字参数url,则表示跳转
- 其它参数还包括method、headers、postData
- route.fulfill():修改响应内容
- 指定body参数,可以直接响应自定义文本内容
- 指定path参数,可响应指定的本地文件
- 其它参数还包括status、headers、json、contentType、response
- 参数route:
- 参数1:表示匹配的url
-
示例
import re from playwright.sync_api import sync_playwright with sync_playwright() as playwright: browser = playwright.chromium.launch(headless=False) page = browser.new_page() # 停止请求 page.route(re.compile(r'\.(png|jpg|jpeg)'), lambda route: route.abort()) # 过滤图片 # 跳转请求 page.route('https://spa6.scrape.center/', lambda route: route.continue_(url='https://www.baidu.com/')) # 用给定的内容响应 # page.route('https://www.zhihu.com/', lambda route: route.fulfill(body='指定返回的内容')) page.route('https://www.zhihu.com/', lambda route: route.fulfill(path='./test.html')) page.goto("https://spa6.scrape.center/") # 访问网址 page.wait_for_load_state(state='networkidle') # 等待当前页面初始化和加载完成 page.goto('https://www.zhihu.com/') page.wait_for_load_state(state='networkidle') print(page.content()) browser.close()