Post

0704Playwright

Playwright(p257)是微软开源的自动化测试工具(官方文档),它的api设计接近 pypeteer(综合起来Playwright>Pypeteer>Selenium)。

Playwright特点:

  • 支持主流的浏览器。基于chromium(Chrome、Edge)、FireFox、Safari(基于Webkit)
  • 支持移动端页面测试
  • 安装和配置简单,无需安装额外的WebDriver(跟Pypeteer无非就是它帮你安装好依赖的东西)
  • Playwright 提供和自动等待相关的 API,在页面加载时会自动等待对应的节点加载,大大减小了 API编写的复杂度。
  • 自动代码生成

安装

  • pip3 install playwright [chromium|FireFox|wekit]
  • 下载必要的浏览器(好家伙把主流的浏览器[chromium、FireFox、wekit]都下载下来了)和配置对应驱动、环境变量:playwright install
    • 安装到目录:/Users/xx/Library/Caches/ms-playwright/

使用

典型的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#同步版本
from playwright.sync_api import sync_playwright
with sync_playwright() as playwright:
    browser = playwright.chromium.launch(headless=False)#这里跟Pypeteer的launch差不多
    context = browser.new_context()
    page = context.new_page()                           #也可以用browser.new_page()
    page.goto("https://cn.bing.com/")
    label=page.locator("#sb_form_q")                    #查找id=sb_form_q,输入python,回车
    label.fill("python")
    label.press("Enter")
    time.sleep(20)
    page.close()
    context.close()

#异步版本
import asyncio
from playwright.async_api import async_playwright
async def main() -> None:
    async with async_playwright() as playwright:
        browser = await playwright.chromium.launch(headless=False)
        context = await browser.new_context()
        page = await context.new_page()
        await page.goto("https://cn.bing.com/")
        await page.fill('#sb_form_q','python')      #晕 page.locator 没有异步版本函数
        await page.press('#sb_form_q','Enter')
        await asyncio.sleep(20)
        await page.close()
        await context.close()
        await browser.close()

asyncio.run(main())

launch的参数。

launch传入的参数跟Pypeteer,命名有些差异

参数名称参数类型参数说明
executable_pathstr可执行文件的路径。实际就是指定chromium浏览器路径(也可以指定Chrome路径)
envDict[str, str|float|bool]|环境变量,可以传人字典形式的数据 
headlessbool是否以”无头”的模式运行 . 默认为 true
slow_mofloat操作减速,单位是毫秒。减缓Pyppeteer的一些模拟操作
argsSequence[str]在执行过程中传入的额外参数.args=[’–disable-infobars’,#禁用提示条
‘–window-size=1366,768’#页面大小设置
]
ignore_default_argsbool是否忽略Pyppeteer的默认参数。如果使用这个参数,那么最好通过 args 设置一些参数,否则可能会出现一些意想不到的问题。这个参数相对比较危险,慎用。
handle_sigintbool是否响应 SIGINT 信号,也就是是否可以使用 Ctrl+C终止测览器程序默认是 True
handle_sigtermbool是否响应 SIGTERM 信号(一般是 ki11 命令),默认是 True
handle_sighupbool是否响应 SIGHUP信号,即挂起信号,例如终端退出操作,默认是True。
timeoutfloat等待浏览器实例启动的最 超时(以毫秒为单位)。默认值为 30000
devtoolsbool是否自动为每一个页面开启调试工具,默认是 false。如果将这个参数设置参数就会无效,会被强制设置为 false为 True 那么 headless
proxyProxySettings 
downloads_pathstrPath

CSS选择器(Playwright对CSS选择器又做了扩展!!!!)

扩展作用例子
text=str
text(str)
文本选择器page.click(“text=Log in”)#匹配 文本=Log in
page.click(“#nav-bar:text(‘Contact us’)”)#匹配 id=na-bar节点文本值=Contact us
has-text(str)包含文本(Playwright的constains)page.click(“article:has-text(‘Playwright’)”)#匹配 article节点文本值包含Playwright
has() page.click(“article:has(‘div.promo’)”) #返回<article>内部具有 <div class=’promo’> 的元素

XPath(带前缀xpath=):

page.click('xpath=button')

模拟成移动浏览器

1
2
3
iPhone= playwright.devices['iPhone 12 Pro Max']
browser = await playwright.chromium.launch(headless=False)
context = await browser.new_context(**iPhone,locale='zh-CN')

自动代码生成

  • 查看命令:playwright codegen --help
  • 执行代码生成会打开浏览器和playwright inspector(实时显示代码生成)
  • 主要的参数
    • --target:生成语言。python、python-async(异步执行)
    • -b:浏览器(chromium、webkit、firforx)
    • 例子:playwright codegen --target=python-async -o script3.py https://www.bing.com

其他函数

  • 1.page的其他函数/属性
函数功能例子
goto until参数:<>
“domcontentloaded”:在触发“domcontentloaded”事件时完成操作。
“load”:触发 load事件时完成操作。
“networkidle”:当500毫秒内没有新的网络请求时触发,认为操作已完成。
“commit”:考虑在接收到网络响应并且文档开始加载时完成操作。
proxy:
{“server”: “host:port”, “username”: “user”, “password”: “pwd”}
locator定位到指定节点 
click点击page.click(“#nav-bar:text(‘Contact us’)”)
fill输入字符串page.fill(‘#sb_form_q’,’python’)
type在指定的元素中输入文本内容page.type(‘#sb_form_q’, ‘python’, delay=100)
press page.press(‘#sb_form_q’,’Enter’)
evaluate执行js codeawait page.evaluate(‘window.scrollBy(0, document.body.scrollHeight)’)# 滚动到页面底部
eval_on_selector
eval_on_selector_all
在单个/所有符合选择器的节点执行js
等效于Pypeteer
 
on事件监听(和Pypeteer 
route路由处理page.route(re.compile(“.(png)|(jpe{0,1}g)”), lambda route,request:route.abort())#不处理图片请求
page.route(‘/’, lambda route,request:route.fulfill(path=”./my_response.html”)) #替换请求页面
add_init_script page.add_init_script(‘Object.defineProperty(navigator, “webdriver”, {get: () => undefined})’)#反爬虫检测
query_selector
query_selector_all
获取单/多个,未找到返回Noneelement=page.query_selector(‘a.name’)
elements=page.query_selector_all(‘a.name’)
get_attribute获取节点属性href=page.get_attribute(‘a.name’, “href’)
wait_for_event wait_*类函数可能抛异常
wait_for_load_state等待页面的加载状态state参数:(goto的util参数)

page.goto(‘https://cn.bing.com’)
page.wait_for_load_state(‘networkidle0’)# 等待网络空闲状态
wait_for_function该方法会持续执行指定的 JavaScript 函数,直到函数返回 True。它可以用于等待页面上动态变化的内容出现,或者等待异步操作完成。page.wait_for_function(‘()=>document.querySelector(“#myButton”).disabled===false’)
wait_for_selector等待与指定 CSS 选择器匹配的元素出现在页面中page.wait_for_selector(‘#myButton’)
page.wait_for_selector(‘.my-div’, visible=True) # 等待可见的元素
wait_for_timeout等待调用方法时等待的时间(相当于sleep) 
wait_for_url等待主框架导航到给定的URLawait page.click(“a.delayed-navigation”)
await page.wait_for_url(“**/target.html”)
expect_navigation等待页面完成导航# 点击搜索按钮
with page.expect navigation():page.click(“text-百度一下”)
expect_event  
expect_popup  
expect_worker  
expect_request  
expect_request_finished  
screenshot截图 
conent获取html源码 
keyboard kb=page.keyboard
kb.type(‘Hello World!’)
#删除掉 World
kb.press(‘ArrowLeft’)
kb.down(‘Shift’)
for i in rang(len(‘ World’)):kb.press(‘ArrowLeft’)
kb.up(‘Shift’)
kb.press(‘Backspace’)#按回车
mouse鼠标page.mouse.click(x,y,button,click_count,delay)
page.mouse.wheel(delta_x, delta_y)
page.mouse.move(0, 0)#移动到[0,0]坐标
page.mouse.down()
page.mouse.up()
  • 2.节点函数/属性
函数功能例子
text_content获取文本page.query_selector(“h2”).text_content()
get_attribute获取节点属性page.query_selector(‘img.cover’).get_attribute(‘src’)
  • 3.Locator函数
函数功能例子
count返回匹配数量count()==0则没有匹配的节点
click执行点击loc.click(click_count=5,delay=100)
press输入内容loc.press(‘Enter’)
type输入文本内容loc.type( ‘python’, delay=100)
drag_to拖到 
all返回所有匹配元素到list 
get_attribute获取属性 
inner_html  
inner_text  
text_content节点文本 
scroll_into_view_if_needed滚动到view 

Q&A

  • ` Execution context was destroyed, most likely because of a navigation`

    检查代码是否在跳转了新页面后又在使用query_selector之类的函数。比如用迭代器(yield,惰性求值导致页面跳转后还去执行前一个页面的操作)存储了所有页面,处理完当前的页面再for取出下一个页面

This post is licensed under CC BY 4.0 by the author.