框架介绍和安装
Playwright是一个开源的自动化库,由Microsoft开发,用于自动化基于Chromium,Firefox,和WebKit的浏览器。它支持多种语言,包括Python,并能在Windows,Linux,和macos上运行。
支持同步和异步执行。
playwright 与 selenium 区别
selenium
WebDriver 的底层实现是通过调用浏览器驱动程序与浏览器交互来实现的。具体来说,下面是 WebDriver 底层实现的一般步骤:
- 用户编写测试脚本或代码,调用 Selenium 提供的 API。
- 测试脚本通过 Selenium 提供的 WebDriver API(如
find_element_by_xpath()
、click()
、send_keys()
等)发送命令。 - WebDriver 接收到命令后,根据命令的内容,调用相应的浏览器驱动程序。
- 浏览器驱动程序将命令转换为对应浏览器支持的实际操作,如打开网页、定位元素、模拟用户输入等。
- 浏览器驱动程序通过浏览器提供的接口来与浏览器进行通信,在浏览器中执行相应的操作。
- 浏览器执行完操作后,将结果返回给 WebDriver。
- WebDriver 将结果返回给测试脚本,测试脚本根据返回的结果进行进一步操作或断言。
流程: python代码调用selenium - webdriver - 浏览器驱动控制浏览器 - 信息返回给webdriver - 返回给python代码
playwright
Playwright 的底层实现是通过对不同浏览器的原生 API 进行封装和封装,并通过自定义协议与浏览器通信来实现。playwright是直接操作浏览器,所以playwright会比selenium快
!!!playwright自带有驱动,本机可以不用下载浏览器- 启动浏览器实例:
- 首先,通过 Playwright 提供的 API 创建并启动所需浏览器实例,例如 Chromium、Firefox 或 WebKit。
- 发送指令与浏览器交互:
- 使用 Playwright 提供的方法,向浏览器发送指令以执行测试脚本中的操作,例如打开链接、定位元素、模拟用户行为等。
- 执行测试脚本:
- 通过浏览器实例执行测试脚本,执行操作并获取结果,例如页面元素状态、网络请求信息等。
- 关闭浏览器实例:
- 当测试脚本执行完成后,通过 Playwright 提供的 API 关闭浏览器实例,释放资源。
- 启动浏览器实例:
环境安装
1 | $ pip install playwright |
playwright自带浏览器驱动安装
1 | # 安装 firefox、webkit、chromium |
playwright 使用本地浏览器运行
1 | from playwright.sync_api import sync_playwright |
脚本录制功能
启用录制工具命令
1 | $ playwright codegen |
使用内置支持浏览器类型
1 | # 使用firefox |
使用方法 - 本地执行
1 | # 同步api |
远程执行
connect(options)
: 在远程计算机上连接浏览器实例
在远程计算机上安装Playwright,并通过终端命令
npx playwright serve --port=8585
启动Playwright Server。
在本地计算机上可以通过以下方式连接到远程浏览器实例
1 | import playwright.sync_api as p |
设置整个浏览器对象操作设置
1 | def launch( |
可以设置浏览器特定操作,可以在browser = p.chromium.launch()
方法中传递特定参数
- headless:设置是否以无头浏览器运行,默认为True。若是本地浏览器,可能还需要设置实际参数进行操作
- show_mo:模拟用户操作的延迟时间,单位ms,当前浏览器全局生效,默认为0
- args:传递浏览器实例的其他命令行参数列表
- proxy:设置代理
- executable_path:启动本地浏览器时路径
- downloads_path:设置下载路径
等待 - 且注意事项
由于Playwright底层是基于异步实现的,使用time.sleep()会导致代码阻塞,而Playwright的操作可能会在时间等待期间进行异步操作,这样就会导致程序出现错误或不可预测的行为。会导致出错
强制等待 - page.wait_for_timeout(1000)
- 单位:ms
如果要使用强制等待可以使用这个代替
page.wait_for_selector(selector, options?)
参数
- options - [“attached”, “detached”, “hidden”, “visible”] 默认visible
等待指定选择器匹配的元素出现在页面上
1 | page.wait_for_selector('#myElement') |
wait_for_function(page_function)
等待js函数返回ture
1 | page.wait_for_function('document.querySelector("#myElement").textContent === "Hello"') |
wait_for_event(target, event)
等待指定事件在目标对象上触发。
1 | page.wait_for_event('domcontentloaded') |
wait_for_navigation()
等待页面导航完成(例如页面加载或页面跳转)
1 | page.wait_for_navigation(state, timeout) |
page.wait_for_load_state("load")
page对象的方法,用于等待页面加载到指定状态
- 参数
- state
- domcontentloaded - 等到加载DOMContentLoaded事件
- load - 等到加载load事件
- networkidle - 等到500 ms没有网络请求交互
- timeout
- state
wait_for_request(url_or_predicate)
等待一个网络请求触发,并匹配给定的 URL 或谓词函数。
1 | page.wait_for_request('https://example.com/data.json') |
wait_for_response(url_or_predicate)
等待一个网络响应返回,并匹配给定的 URL 或谓词函数。
1 | page.wait_for_response('https://example.com/data.json') |
wait_for_url()
等待页面跳转某个url
1 | page.wait_for_url('https://www.baidu.com') |
locator().waitFor()
1 | # 等待元素消失 |
Browser(浏览器对象)
1 | from playwright.sync_api import sync_playwright |
创建浏览器上下文 - browser.new_context()
1 | # 创建上下文 |
获取所有浏览器上下文对象 - browser.contexts
1 | # 获取浏览器所有上下文对象,列表形式展示 |
创建页面实例 - browser.new_page()
1 | # 创建页面,这里会弹出页面窗口 |
获取浏览器所属的浏览器类型 - browser.browser_type
1 | # 获取浏览器上下文对象类型 - BrowserType 对象 |
额外方法
方法:
launch(options)
: 通过指定的选项启动一个指定类型的浏览器实例。1
2# 根据 BrowserType 对象 启动一个新的想通浏览器实例
new_browser = chromium_browser_type.launch(headless=False)connect(options)
: 连接到一个远程浏览器实例,可以在不同的计算机上控制同一个浏览器实例。1
2
3
4
5
6
7
8
9
10
11
12# 获取 Chromium 浏览器类型对象
chromium_browser_type = p.chromium
# 连接到一个远程 Chromium 浏览器实例
browser = chromium_browser_type.connect({
"wsEndpoint": "ws://[远程计算机IP]:8585",
})
# 创建一个新的页面
page = browser.new_page()
# 在新页面加载并展示百度网站
page.goto("https://www.baidu.com")
# 关闭浏览器
browser.close()
判断浏览器对象是否连接 - browser.is_connected()
1 | # 用于检查浏览器实例是否连接到 Playwright 服务器 |
客户端调试协议(CDP)会话 - browser.new_browser_cdp_session()
用于创建一个与浏览器实例关联的新的浏览器客户端调试协议(CDP)会话, 返回CDPsession实例
CDP(Chrome DevTools Protocol)会话在 Playwright 中的作用主要体现在以下几个方面:
- 执行高级的浏览器操作:通过 CDP 会话,您可以执行一些高级的浏览器操作,比如模拟用户输入、网络请求拦截、执行 JavaScript 等操作。这些高级操作通常是通过 CDP 提供的接口实现的,可以实现更灵活和定制化的功能。
- 调试浏览器:CDP 会话可以用于调试浏览器,包括检查 DOM 结构、网络请求、性能指标等。您可以通过 CDP 会话与浏览器进行交互,查看浏览器的内部状态。
- 监控浏览器性能:通过 CDP 会话,您可以监控浏览器的性能指标,如内存占用、CPU 使用率、页面加载时间等。这对于性能优化和调试非常有帮助。
1 | import playwright.sync_api as p |
事件监听 - browser.on()
绑定监听器,给浏览器对象操作绑定一个函数,当操作执行时会被监听到,触发该函数
1 | # 定义事件处理函数 |
一次性事件监听 - browser.once()
用于为浏览器实例注册一次性事件监听器。只会被处罚一次,并在执行后自动移除,不会重复执行。
1 | # 定义事件处理函数 |
移除监听 - browser.remove_listener()
用于移除先前使用browser.on()
方法添加的事件监听器。
1 | # 添加 close 事件监听器 |
开启性能跟踪 - browser.start_tracing(path, screenshots) & browser.stop_tracing()
用于开始对浏览器实例进行性能追踪。如网络请求、JavaScript 执行时间、内存占用等信息,以便分析和优化页面性能。
- 参数
path="trace.json"
: 指定保存性能追踪数据的文件路径。在这个示例中,性能追踪数据将被保存在名为trace.json
的文件中。screenshots=True
: 如果将此参数设置为True
,则在性能追踪过程中还会捕获页面截图。这对于分析页面加载过程中的视觉表现非常有用,可以帮助进一步了解页面的性能情况。
1 | # 启动一个本地 Chrome 浏览器实例 |
获取当前浏览器版本号 - browser.version
获取当前浏览器版本
1 | brVerion = browser.version |
关闭 - browser.close()
1 | # 退出上下文 |
context(浏览器上下文)
浏览器上下文提供了一种操作多个独立浏览器会话的方法。
1 | from playwright.sync_api import sync_playwright |
添加cookie - context.add_cookie()
将 Cookie 添加到此浏览器上下文。此上下文中的所有页面都将安装这些 Cookie。
1 | # 启动一个本地 Chromium 浏览器实例 |
获取cookie - context.cookies()
此方法将返回所有 Cookie。如果指定了 URL,则仅返回影响这些 URL 的 Cookie(cookie受跨域影响)
1 | # 获取cookie |
清除cookie记录 - context.clear_cookies
1 | context.clear_cookies() |
浏览器授权 - context.grant_permissions()
向浏览器上下文授予指定的权限。如果指定,则仅向给定来源授予相应的权限,可以模拟浏览器环境中向页面添加例如摄像头、麦克风、通知等权限。
- 环境光传感器 - ambient-light-sensor
- 相机 - camera
- 地理位置 - geolocation
- 陀螺 - gyroscope
- 麦克风 - microphone
- 通知 - notifications
- 存储访问 - storage-access
1 | # 启动一个浏览器实例 |
清除权限 - context.clear_permissions
1 | context.clear_permissions() |
关闭浏览器上下文context.close(str)
关闭浏览器上下文。属于该浏览器上下文的所有页面(page)都将关闭。
参数
str(可选) - 要报告给被上下文关闭中断的操作的原因 (添加于:v1.40)
context.add_init_script()
用于向浏览器上下文(Context)中添加自定义的初始化脚本(init script)。这个初始化脚本会在每次新页面被打开前执行,可以用来注入自定义的 JavaScript 代码,从而在页面加载前执行特定操作或修改页面行为。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# 创建初始化脚本,用于在每次新页面加载前输出一条信息
init_script = """
console.log('Custom init script executed!');
"""
# 启动一个本地 Chromium 浏览器实例
browser = p.chromium.launch()
# 创建浏览器的上下文
context = browser.new_context()
# 向上下文中添加初始化脚本
context.add_init_script(init_script)
# 在上下文中创建新页面
page = context.new_page()
# 在新页面中访问网站
page.goto("https://example.com")
# 等待页面加载完成
page.wait_for_load_state("load")
监听等待特定事件触发 - expect_event()
用于在页面监听并等待特定事件的方法。通过 expect_event
方法,您可以设置条件来监听页面中触发的特定事件,并在事件发生时进行断言验证或执行其他操作。
等待给定的 event
触发 - wait_for_event()
context.new_cdp_session()
返回新创建的会话
创建一个页面 - context.new_page()
1 | browser = p.chromium.launch(headless=False) |
用于浏览器上下文捕获网络请求的功能 - context.route()
启用路由后,与 URL 模式匹配的每个请求都将暂停
1 | browser = p.chromium.launch(headless=False) |
清除router捕获功能 - unroute()
清除使用 browser_context.route()和 browser_context.route_from_har()创建的所有路由规则 - unroute_all()
从 HAR 文件创建虚拟的路由 - route_from_har
pass
统一设置超时时间 - set_default_navigation_timeout(timeout)
超时生效的方法
page.go_back()
page.go_forward()
page.goto()
page.reload()
page.set_content()
page.expect_navigation()
1 | # 设置默认的页面导航超时时间为10秒(10000毫秒) |
设置所有超时时间 - set_default_timeout(timeout)
1 | context.set_default_timeout(timeout) |
设置请求头 - set_extra_http_headers()
设置该上下文请求时发送的,如果相同参数,将使用页面特定的标头值而不是浏览器上下文标头值。
1 | context.set_extra_http_headers(headers) |
设置地理位置 - set_geolocation()
1 | context.set_geolocation({"latitude": 59.95, "longitude": 30.31667}) |
模拟网络离线状态 - set_offline()
1 | context.set_offline(offline) |
获取浏览器缓存数据 - storage_state()
1 | context.storage_state(path) |
获取上下文中所有现有的后台页面 - background_pages
用于获取当前浏览器上下文(Context)关联的所有后台页面(background pages)。后台页面是指在后台运行的页面,通常是一些扩展或插件创建的页面,独立于当前活动页面,可以在后台执行一些任务或逻辑。
1 | # 启动一个本地 Chromium 浏览器实例 |
获取上下文所有打开的页面 - pages
1 | context.pages |
发起请求 - request
使用此 API 发出的请求将使用上下文 Cookie。
context相关事件
on(“backgroundpage”)
适用于 Chromium 浏览器的持久上下文
在上下文中创建新的后台页面时发出
1 | background_page = context.wait_for_event("backgroundpage") |
on(“close”)
在浏览器上下文关闭时发出
- 浏览器上下文已关闭。
- 浏览器应用程序已关闭或崩溃。
- 已调用 browser.close()方法。
on(“console”)
当页面中的 JavaScript 调用某个控制台 API 方法(例如 console.log
或 console.dir
)时发出
on(“dialog”)
当出现 JavaScript 对话框(例如 alert
、prompt
、confirm
或 beforeunload
)时发出。侦听器必须 dialog.accept()或 dialog.dismiss()对话框 - 否则页面将 冻结等待对话框,并且像单击之类的操作将永远不会完成
1 | context.on("dialog", lambda dialog: dialog.accept()) |
on(“page”)
在 BrowserContext 中创建新页面时发出该事件。该页面可能仍在加载中。弹出页面也会触发该事件
on(“request”)
从通过此上下文创建的任何页面发出请求时发出。 request 对象是只读的。要仅侦听来自特定页面的请求,请使用 page.on(“request”)
on(“requestfailed”)
请求失败时发出,例如超时。如果仅侦听来自特定页面的失败请求,请使用 page.on(“requestfailed”)。
on(“requestfinished”)
在下载响应正文后请求成功完成时发出。对于成功的响应,事件顺序为 request、response 和 requestfinished。要侦听来自特定页面的成功请求,请使用 page.on(“requestfinished”)。
on(“response”)
当收到请求的 响应 状态和标头时发出。对于成功的响应,事件顺序为 request、response 和 requestfinished。要监听来自特定页面的响应事件,请使用 page.on(“response”)。
on(“serviceworker”)
仅基于 Chromium 的浏览器支持 Service Worker。
当在上下文中创建新的服务工作线程时发出。
on(“weberror”)
当此上下文中任何页面的异常未处理时发出。要监听来自特定页面的错误,请改用 page.on(“pageerror”)。
page元素定位
定位器 - page.Locator() 方法
定位器(Locator)是 Playwright 的自动等待和重试能力的核心部分。定位器是一种随时在网页上查找元素的方法,用于在元素上执行诸如 .click、.fill 之类的操作。可以使用 page.locator(selector, **kwargs) 方法创建自定义定位器。支持css、xpath。返回一个定位器;Locator 对象的主要优点是它们可以自动等待元素出现在页面上
参数讲解 locator(selector, **kwargs)
selector - 用于解析 DOM 元素的选择器。
定位器返回单个元素 - page.locator()
1 | # 通过特定选择器查找 |
page.locator()
方法返回一个元素定位器 Locator
所以通过page.locator()
返回的对象可以继续使用.locator()
进行内部子元素定位
链式调用
page.locator()
的返回值本身也有 locator()
方法,这意味着你可以链式地定位元素。例如,
1 | page.locator('.my-class').locator('.my-subclass') |
返回全部元素 - locator.all()
locator.all() 不会等待元素匹配定位器,而是立即返回页面中存在的内容。
当定位器指向元素列 表时,这将返回一个定位器数组,指向它们各自的元素。
1 | # 查找所有带有 class 为 'example' 的元素 |
返回全部匹配元素的数量 - locator.count()
1 | # 查找所有带有 class 为 'example' 的元素,并返回数量 |
匹配元素的文本内容 - locator.all_inner_texts()
1 | # 获取文本内容 |
获取元素的DOM - locator.inner_html()
1 | page.get_by_role("link").inner_html() |
获取元素的文本内容 - locator.inner_text()
1 | page.get_by_role("link").inner_text() |
获取元素DOM属性值 - locator.get_attribute()
用于从匹配的元素中获取指定属性的值。您可以指定要获取的属性名称,并返回相应的属性值。
1 | # 选择要获取属性值的元素 |
匹配多种元素
and_()
1
2# 匹配两种or多种元素定位
button = page.get_by_role("button").and_(page.getByTitle("Subscribe"))使用多种元素匹配
1
2# 查找具有 role 为 'button' 和 title 为 'Subscribe' 的元素
button = page.query_selector('[role="button"][title="Subscribe"]')
设置字段值locator.fill()
1 | # 为输入字段设置值 |
输入框聚焦 - locator.focus()
用于将页面上匹配的元素(通过定位器选择)设置为焦点。这可以模拟用户手动点击元素以使其聚焦的操作。
1 | # 选择要设置焦点的输入框元素 |
输入框焦点 - locator.blur()
1 | # 定位到一个输入框元素 |
获取定位属性的元素的边界框信息 - locator.bounding_box()
1 | # 获取具有 role 为 'button' 的元素的边界框信息 {横坐标, 纵坐标, 宽, 高} |
选中选框/按钮元素 - locator.check()
确保选中复选框或单选按钮元素, 如果不是,则此方法会抛出异常。如果元素已选中,则此方法立即返回。注意:需要将元素滚动到视图中。
1 | # 定位带有 role 为 'checkbox' 的元素并选中它 |
清除选中元素- locator.clear()
此方法会等待 可操作性 检查,聚焦元素,清除其内容并在清除后触发 input 事件。
如果目标元素不是 <input>
、<textarea>
或 [contenteditable] 元素,则此方法会抛出错误。但是,如果元素位于具有关联 控件 的 <label>
元素内,则将清除该控件。
1 | input_locator = page.locator('input[type="text"]') # 替换成您要操作的输入框的选择器 |
点击选中元素 - locator.click()
1 | # 通过 CSS 选择器定位具有 role 为 'button' 的元素并点击 |
双击选中元素 - locator.dblclick()
1 | # 双击选中元素,参数与click()一致 |
locator.dispatch_event()
以编程方式在匹配的元素上调度事件
1 | # 通过 CSS 选择器定位需要模拟点击事件的元素 |
元素拖动 - locator.drag_to()
1 | # 选择要拖动的源元素和目标元素 |
执行js代码 - locator.evaluate()
执行 JavaScript 代码,并将结果返回给 Python 程序。
1 | # 使用 evaluate 方法获取页面中某个节点的 innerText |
执行js代码 - locator.evaluate_all()
这个方法用于在页面上下文中对所有匹配的元素执行JavaScript代码,并返回一个包含所有结果的数组。它对于处理多个匹配元素非常有用
1 | elements = page.locator('div').evaluate_all('(elements) => elements.map(el => el.textContent)') |
执行js代码 - locator.evaluate_handle()
这个方法用于在页面上下文中执行JavaScript代码,返回一个 Promise,用于在后续的操作中获取结果。并使用结果返回一个远程对象(evaluateHandle对象),可通过调用evaluateHandle.dispose()
方法显式地释放。
1 | handle = page.locator('button').evaluate_handle('(buttons) => buttons[0]') |
过滤器 - locator.filter()
1 | row_locator = page.locator("tr") |
切换iframe - locator.frame_locator()
用于在定位器的上下文中查找嵌套的 iframe 元素。在页面上有嵌套的 iframe 结构时,可以使用该方法来选择 iframe 元素并返回一个新的定位器,该定位器指向iframe
1 | # 选择页面中包含 iframe 的元素 |
高亮显示选中元素 - element.highlight()
对选中的元素,进行高亮显示
1 | element = page.locator().get_by_text("新闻") |
鼠标悬停 - element.hover()
将鼠标悬停在匹配的元素上。
1 | page.get_by_role("link").hover() |
获取元素的value属性值 - locator.input_value()
返回匹配的 <input>
或 <textarea>
或 <select>
元素的值。
1 | value = page.get_by_role("textbox").input_value() |
返回定位元素是否选中 - locator.is_checked()
返回该元素是否被选中。 如果该元素不是复选框或单选按钮输入,则抛出异常
1 | checked = page.get_by_role("checkbox").is_checked() |
返回该元素是否被禁用 - locator.is_disabled()
1 | disabled = page.get_by_role("button").is_disabled() |
判断元素是否可编辑 - locator.is_editable()
1 | editable = page.get_by_role("textbox").is_editable() |
判断元素是否启用 - locator.is_enabled()
1 | enabled = page.get_by_role("button").is_enabled() |
判断元素是否隐藏 - locator.is_hidden()
1 | hidden = page.get_by_role("button").is_hidden() |
判断元素是否可见 - locator.is_visible()
1 | visible = page.get_by_role("button").is_visible() |
按下元素 - locator.press()
类似聚焦匹配的元素并按下的组合键
1 | page.locator('a').press("Backspace") |
滚动元素至可见 - locator.scroll_into_view_if_needed()
将滚动到元素可见。这个方法会检查元素是否在视窗内,如果不在的话会自动滚动到元素可见。
1 | # 使用locator定位需要操作的元素 |
选择单个或多个select - element.select_option()
1 | """ html |
设置单选框或复选框状态 - locator.set_checked()
设置复选框或单选按钮元素状态。
确保匹配的元素是复选框或单选按钮输入
将元素滚动到视图中-
1 | page.get_by_role("checkbox").set_checked(True) |
获取单选框或复选框状态 - locator.is_checked()
1 | page.get_by_role("checkbox").is_checked() # 返回布尔值 |
取消选中 - locator.uncheck()
确保复选框或单选按钮元素未被选中。
1 | page.get_by_role("checkbox").uncheck() |
等待 - locator.wait_for()
当定位器指定的元素满足 state
选项时返回。
如果目标元素已满足条件,则该方法立即返回。否则,将最多等待 timeout
毫秒,直到满足条件
1 | order_sent = page.locator("#order-sent") |
文件上传 - locator.set_input_files()
将文件或多个文件上传到 <input type=file>
。对于具有 [webkitdirectory]
属性的输入,仅支持单个目录路径
1 | # Select one file |
点击选择器元素 - locator.tap()
1 | page.locator('a').tap() |
返回选择器的第一个元素 - locator.first
1 | page.locator('a').first |
返回选择器的最后一个元素 - locator.last
1 | page.locator('a').last |
获取第n个元素 - locator.nth()
返回第 n 个匹配元素的定位器。它是从零开始的,nth(0)
选择第一个元素
1 | page.locator('a').nth(2) # 返回定位的所有a标签的3个元素 |
返回当前元素页面信息 - locator.page
1 | page.locator('a').page |
选择器(Selector)是用于创建定位器的字符串。Playwright 支持许多不同的选择器,比如 Text、CSS、XPath 等。阅读 in-depth guide 文档,了解更多关于可用的选择器以及如何进行选择的信息。
page.select() 下拉选项
它可以根据 option 元素的值、文本内容或索引来选择下拉列表中的选项。
基本使用
1 | # 通过值选择选项 |
多选下拉列表
1 | page.select('select#fruits', ['apple', 'banana']) |
超时设置
1 | page.select('select#fruits', 'apple', timeout=5000) |
联动选择
在某些情况下,下拉列表的选项会受到先前的选择而改变。可以使用waitForElementState
方法来等待元素变为可选择状态。
1 | await page.waitForElementState('select#fruits', 'visible') |
内置定位器
page.get_by_role()
通过显式和隐式可访问性属性进行定位。role属性
用于根据 role 属性来定位元素。
ARIA(无障碍开发) role属性, 有些元素隐式存在role属性
1 | """ html |
page.get_by_text()
通过文本内容定位。
1 | """ html |
page.get_by_label()
通过关联标签的文本定位表单控件。
用于根据标签文本来定位元素。
允许通过关联的 <label>
或 aria-labelledby
元素的文本,或通过 aria-label
属性来定位输入元素
1 | """ html |
page.get_by_placeholder()
按占位符定位输入。
1 | ''' |
page.get_by_alt_text()
通过替代文本定位元素,通常是图像。
用于根据元素的 alt
属性文本值来定位元素的内置方法是page.locator()
结合image
标签的alt
属性,或结合aria-label
属性等
1 | """ html |
page.get_by_title()
通过标题属性定位元素。
允许根据元素的 title 属性定位元素
1 | """ html |
page.get_by_test_id()
根据data-testid属性定位元素可以配置其他属性)
按测试 ID 定位元素。
1 | """ html |
locator.get_by_placeholder( ) 通过占位符文本定位输入元素。
1 | """ html |
page操作
方法
打开页面 - page.goto()
参数
url
- 跳转或打开的urlreferer
- 设置页面导航的引用url,模拟用户从某个特定页面跳转过来1
page.goto(url, referer="https://example.com")
timeout
- 超时时间, 单位毫秒wait_until
- 等待条件- load : 等待页面完全加载
- domcontentloaded : 等待DOM内容加载完成
- network:等待所有请求完毕
1
page.goto(url, wait_until=['load', 'domcontentloaded'])
获取标题名称 - page.title()
1 | # 获取页面标题 |
获取页面html
内容 - page.content()
1 | # 获取页面的HTML内容,包括文档类型声明 |
关闭页面 - page.close()
1 | page.close() |
判断页面是否关闭 - page.is_closed()
1 | # 判断页面是否关闭 |
刷新页面 - page.reload()
1 | # 刷新当前页面 |
返回上一页历史 - page.go_back()
如果有多个重定向,则导航将使用最后一个重定向的响应进行解析。如果无法前进,则返回 null
1 | page.go_back() |
跳转下一页历史 - page.go_forward()
如果有多个重定向,则导航将使用最后一个重定向的响应进行解析。如果无法前进,则返回 null
1 | page.go_forward() |
页面截图 - page.screenshot(options)
options
path
保存路径及截图名
1
page.screenshot(path="./images/a.png")
等待页面元素加载成功 - page.wait_for_selector(selector, timeout=1000)
1 | # 在页面上等待直到出现具有 class 为 'example' 的元素 |
在页面中执行 JavaScript 代码 - page.evaluate(script)
1 | # 使用 evaluate 方法执行 JavaScript 代码,结果返回js代码的返回值 |
设置页面视口大小 - page.set_viewport_size(width, height)
1 | ''' |
模拟键盘输入 - page.type(selector, text)
1 | page.type('#kw', 'asdf') |
模拟键盘输入 - page.fill(selector, text)
1 | page.fill('#kw', 'asdf') |
清空输入框内容 - page.clear()
1 | page.locator('#kw').clear() |
模拟鼠标点击 - page.click(selector)
- 参数
- button - left(左键)、right(右键)、middle(中键)、默认left
- click_count - 点击次数,默认为1
- delay - 按下、释放间隔时间
- modifiers - 同时要按下的修饰键:’Alt’ | ‘Control’ | ‘ControlOrMeta’ | ‘Meta’ | ‘Shift’
- position - 点击的坐标位置:{x:10, y:20}
- timeout - 等待元素可点击时间,超过即超时
- force - 释放绕过可操作性检查
1 | page.fill('#kw') |
模拟鼠标双击 - page.dblclick(selector)
参考click()
模拟鼠标悬停 - page.hover(selector)
1 | page.locator('#kw').hover |
获取页面上的所有链接 - page.query_selector_all('a')
返回所有page中’a’标签,返回JSHandle对象
1 | element1 = page.querySelector('button') |
设置单选框或复选框的状态 - page.set_checked()
1 | page.get_by_role("checkbox").set_checked(True) |
取消选中的单选框 - page.uncheck()
1 | page.get_by_role("checkbox").uncheck() |
select下拉框选项 - page.select_option()
选中一个值
1
page.locator('#city').selector_option('shenzhen')
选中多个值
1
page.locator('#city').selector_option(value=['shenzhen','guangzhou','dongguan'])
文件上传 - page.set_input_files()
单文件上传
1
page.locator('#upload').set_input_files('myfile.pdf')
上传多个文件
1
page.locator('#upload').set_input_files(['myfile1.pdf', 'myfile2.pdf'])
元素拖拽 - page.drag_and_drop()
参数
source
用于搜索要拖动元素的选择器。如果有多个元素满足选择器,则将使用第一个元素。
target
用于搜索要放置元素的选择器。如果有多个元素满足选择器,则将使用第一个元素。
source_position
(可选)相对于元素填充框的左上角单击此点上的源元素。如果未指定,则使用元素的某个可见点。x
y
target_position
(可选)相对于元素填充框的左上角放置在目标元素上的此点。如果未指定,则使用元素的某个可见点。x
y
1
2
3
4
5
6
7
8
9
10source = page.locator('#source')
target = page.locator('#target')
page.drag_and_drop("#source", "#target")
# or specify exact positions relative to the top-left corners of the elements:
page.drag_and_drop(
"#source",
"#target",
source_position={"x": 34, "y": 7},
target_position={"x": 10, "y": 20}
)
聚焦元素 - page.focus()
1 | page.locator("#source").focus() |
用于模拟按下和释放键盘按键的操作 - press()
1 | # 模拟按下回车键 |
对话框
- page.on()
1 | # 使用page.on监听dialog事件,监听并处理弹窗 |
dialog方法&属性 解析
dialog 方法
dialog.accept(prompt_text)
prompt_text 指要在提示中输入的文本。如果对话框的
type
不是提示,则不会产生任何效果dialog.dismiss()
在关闭对话框后返回。
dialog 属性
dialog.default_value
如果对话框是提示,则返回默认提示值。否则,返回空字符串。
dialog.message
对话框中显示的消息。
dialog.page
启动此对话框的页面
dialog.type
返回对话框的类型,可以是
alert
、beforeunload
、confirm
或prompt
之一。
下载
page.on(filename)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17browser = p.chromium.launch()
page = browser.new_page()
# 监听并处理下载
def handle_download(download):
download_path = f"/path/to/save/{download.suggested_filename}"
download.path = download_path
print(f"Download started: {download.url}, saving to {download_path}")
# 添加下载监听
page.on("download", handle_download)
# 打开一个页面,包含下载链接
page.goto('https://www.example.com')
# 点击触发下载的链接
page.click('a#download-btn')
# 等待下载完成
with page.expect_download() as download_info:
download_info.save_as('/path/to/save/file.txt')download方法&属性 解析
download 方法
- download.cancel()
取消下载。如果下载已经完成或取消,则不会失败。成功取消后,
download.failure()
将解析为'canceled'
。- download.delete()
删除已下载的文件。如有必要,将等待下载完成。
- download.failure()
如果存在下载错误,则返回该错误。如有必要,将等待下载完成。
- download.path()
返回成功下载的已下载文件路径,如果下载失败/取消,则抛出异常。如有必要,该方法将等待下载完成。
- download.save_as(“/path/to/save/at/“ + download.suggested_filename)
另存外方法。下载仍在进行中时,可以安全地调用此方法。
download 属性
download.page
获取下载所属的页面。
download.suggested_filename
返回此下载的建议文件名。
download.url
返回下载的网址。
文件上传
page.on(“filechooser”, handle_file_chooser)
1
2
3
4
5
6
7
8
9
10
11
12def handle_file_chooser(file_chooser):
# 上传文件,file_chooser.accept(["绝对路径文件名"])
file_chooser.accept(["/path/to/file.txt"])
print("File uploaded successfully")
# 监听文件选择器事件
page.on("filechooser", handle_file_chooser)
page.goto('https://www.example.com')
# 找到上传文件的input元素
upload_input = page.locator('input[type="file"]')
# 触发文件选择器并上传文件
upload_input.set_input_files("/path/to/file.txt")方法
file_chooser.set_files(files)
设置此选择器关联的文件输入的值
属性
file_chooser.element
返回与此文件选择器关联的输入元素。
file_chooser.is_multiple()
返回此文件选择器是否接受多个文件。
file_chooser.page
返回此文件选择器所属的页面。
iframe
1 | browser = p.chromium.launch() |
注册自定义的定位器处理程序 - page.add_locator_handler()
1 | # 自定义的定位器处理程序,用于根据元素的文本内容来定位元素 |
删除自定义定位处理程序 - page.remove_locator_handler()
1 | page.remove_locator_handler(locator) |
页面置顶 - page.bring_to_front()
将页面置顶(激活标签页)。
脚本调试 - page.pause()
执行到这一步时,会会弹出playwright调试工具(可以使用playwright定位方法),打断点;类似于前端debugger
生成pdf - page.pdf(path=”page.pdf”)
属性
获取页面的 URL - page.url
获取浏览器所属上下文 - page.context
获取附加页面的所有框架数组 - page.frames
指示页面已关闭 - page.is_closed()
页面的主框架 - page.main_frame
获取页面宽高 - page.viewport_size
获取页面关联的视频对象 - page.video
鼠标操作
每个 页面 对象都有自己的鼠标,可通过 page.mouse 访问。
移动 - mouse.move(x, y)
调度 mousemove
事件。
1 | mouse.move(x, y) |
按下 - mouse . down()
调度 mousedown
事件。
1 | mouse.down() |
抬起 - mouse.up()
调度 mouseup
事件。
1 | mouse.up() |
滚轮 - mouse.whell()
调度 wheel
事件。此方法通常用于手动滚动页面。有关滚动的其他方法
1 | mouse.wheel(delta_x, delta_y) |
点击 - mouse.click(x, y)
类似mouse.move(x, y)、mouse.down()、mouse.up() 的快捷方式。
1 | mouse.click(x, y) |
双击 - mouse.dblclick(x, y)
mouse.move(x, y)、mouse.down()、mouse.up()、mouse.down() 和 mouse.up() 的快捷方式。
1 | mouse.dblclick(x, y) |
键盘操作
在大多数情况下,您应该使用 locator.fill() 代替。只有在页面上有特殊的键盘处理时才需要逐个按键
page.keyboard 键盘 属性&方法
keyboard.down(key)
键的示例如下:F1 - F12
、Digit0- Digit9
、KeyA- KeyZ
、Backquote
、Minus
、Equal
、Backslash
、Backspace
、Tab
、Delete
、Escape
、ArrowDown
、End
、Enter
、Home
、Insert
、PageDown
、PageUp
、ArrowRight
、ArrowUp
等。
还支持以下修饰键快捷键:Shift
、Control
、Alt
、Meta
、ShiftLeft
、ControlOrMeta
。ControlOrMeta
在 Windows 和 Linux 上解析为 Control,在 macOS 上解析为 Meta
。
按住 Shift
键将键入与 key
对应的大写字母文本。
如果 key
是单个字符,则区分大小写,因此值 a
和 A
将生成不同的文本。
1 | # 按下键盘的 "Enter" 键 |
keyboard.insert_text(key)
仅调度 input
事件,不发出 keydown
、keyup
或 keypress
事件
用户在键盘上键入文本的操作。这个方法可以用来模拟用户键入文本到输入框或其他元素上。
1 | # 定位到输入框 |
keyboard.press(key)
在大多数情况下,您应该使用 locator.press() 代替。
模拟按下键盘上的特定按键
1 | # 模拟输入 'a' |
keyboard.type()
在大多数情况下,您应该使用 locator.fill() 代替。只有在页面上有特殊的键盘处理时才需要逐个按键
1 | # 定位到输入框元素 |
keyboard.up(key)
调度一个 keyup
事件。
1 | # 按下键盘的 "Enter" 键 |
请求监听 - request
当页面发送网络资源请求时,页面 都会发出以下事件序列
- 当页面发出请求时,会发出 page.on(“request”)。
- 当/如果收到请求的响应状态和标头时,会发出 page.on(“response”)。
- 当响应正文下载完成且请求完成时,会发出 page.on(“requestfinished”)。
1 | # 监听页面内请求 |
方法
包含所有请求 HTTP 标头 - request.all_headers()
标头名称采用小写形式。
1 | # 监听页面内请求 |
返回与名称匹配的标头的值 - request.header_value(name)
名称不区分大小写。
1 | # 监听页面内请求 |
一个数组,包含与此请求关联的所有请求 HTTP 标头 - request.headers_array()
以键值对的形式返回
1 | # 监听页面内请求 |
返回匹配的 响应 对象 - request.response()
如果由于错误而未收到响应,则返回 null
1 | def on_request(request): |
返回给定请求的资源大小信息 - request.sizes()
1 | def on_request(request): |
属性
记录所有失败请求 - request.failure
1 | page.on("requestfailed", lambda request: print(request.url + " " + request.failure)) |
获取请求方法 - request.method
1 | page.on("requestfailed", lambda request: print(request.url + " " + request.method)) |
请求的帖子正文 - request.post_data
1 | page.on("requestfailed", lambda request: print(request.url + " " + request.post_data)) |
返回解析后的请求正文 - request.post_data_json
1 | page.on("requestfailed", lambda request: print(request.url + " " + request.post_data_json)) |
重定向前请求 - request.redirected_from
没有重定向操作则为None
1 | page.on("requestfailed", lambda request: print(request.url + " " + request.redirected_from)) |
重定向后请求 - request.resource_type
1 | page.on("requestfailed", lambda request: print(request.url + " " + request.redirected_to)) |
渲染引擎感知到的请求资源类型 - request.resource_type
1 | page.on("requestfailed", lambda request: print(request.url + " " + request.resource_type)) |
响应 - response
方法
关联的所有响应 HTTP 标头 - response.all_headers()
1 | page.on("response", lambda request: print(request.url + " " + response.all_headers())) |
响应正文的缓冲区 - response.body()
1 | page.on("response", lambda request: print(request.url + " " + response.body())) |
返回与名称匹配的标头的值 - header_value()
1 | page.on("response", lambda request: print(response.header_value('content-type'))) |
一个数组,包含与此响应关联的所有请求 HTTP 标头 - response.headers_array()
返回服务器的 IP 地址和端口 - response.server_addr()
返回响应正文的 JSON 表示形式 - response.json()
返回响应正文的文本表示形式 - response.text()
属性
一个包含响应 HTTP 标头的对象 - response.headers
返回响应是否成功 - response.ok
返回匹配的 Request 对象 - response.request
返回响应状态码 - response.status
响应的状态文本(成功时通常为“OK”) - response.status_text
响应url - response.url
CDP(Chrome DevTools Protocol)会话
CDPSession
实例用于与原始 Chrome Devtools 协议进行通信
- 可以使用
session.send
方法调用协议方法。 - 可以使用
session.on
方法订阅协议事件。
跟踪查看器 - Tracing
使用跟踪查看器(Tracing),生成的zip压缩包可以使用
playwright show-trace xxx.zip
进行GUI分析
开始跟踪 - tracing.start(screenshots=True, snapshots=True)
1 | browser = p.chromium.launch() |
在 tracing.start中开辟多个跟踪块 - start_chunk&stop_chunk
开始新的跟踪块。如果您想在同一个 BrowserContext 上记录多个跟踪,请使用一次 tracing.start(),然后使用 tracing.start_chunk() 和 tracing.stop_chunk() 创建多个跟踪块。
1 | context = |
结束跟踪并生成文件 - tracing.stop(path=”trace.zip”)
1 | context.tracing.stop(path="trace.zip") |
视频 - page.video
删除视频文件 - page.video.delete()
删除视频文件。如有必要,将等待视频完成。
返回此视频将录制到的文件系统路径 - page.video.path()
将视频保存到用户指定的路径 - page.video.save_as(path)
错误处理 - WebError
WebError 类表示页面中抛出的未处理异常。它通过 context.on(“weberror”) 事件进行调度
1 | context.on("weberror", lambda web_error: print(f"uncaught exception: {web_error.error}")) |
抛出未处理错误 - web_error.error
1 | context.on("weberror", lambda web_error: print(f"uncaught exception: {web_error.error}")) |
产生此未处理异常的页面 - web_error.page
1 | context.on("weberror", lambda web_error: print(f"uncaught exception: {web_error.page}")) |
路由 - route
pass
tracing 解析
使用playwright 发送请求
playwright 也可以调用请求的方式,进行接口测试
1 |