【爬虫】PlayWright使用说明
持续更新中
1. 安装
安装参考:安装
支持pip和conda安装,以conda为例:
conda config --add channels conda-forge
conda config --add channels microsoft
conda install pytest-playwright
playwright install
如遇到防火墙或者公司网络限制,可参考我另一篇文字conda的proxy设置方式:[]
如果是laywright install
的时候需要proxy,则:
set HTTP_PROXY=你的proxy地址
set HTTPS_PROXY=你的proxy地址
playwright install
2. 使用
2.1 事件
事件列表:
close
: page 关闭console
:当页面中的 JavaScript 调用控制台 API 方法之一(例如console.log
或console.dir
)时产生的事件。- 传递进
console.log
的参数可在ConsoleMessage事件处理程序参数中使用。,ConsoleMessage
对象由页面通过page.on("console")
事件分派。 - 对于页面中记录的每条
ConsoleMessage
,Playwright 上下文中都会有相应的事件。
- 传递进
crash
:page崩溃。- 如果浏览器page尝试分配过多内存,则可能会崩溃。当page崩溃时,正在进行的操作和后续操作将抛出。
dialog
: JavaScript 对话框出现事件,如alert
,prompt
,confirm
或beforeunload
。domcontentloaded
:JavaScript的DOMContentLoaded事件被分发时的事件。- 当 HTML 文档已完全解析且所有延迟脚本(deferred scripts)(
<script defer src="…">
和<script type="module">
)已下载且执行完时,将触发DOMContentLoaded
事件。它不会等待图像、子帧和异步脚本等其他内容完成加载。 DOMContentLoaded
不等待样式表(stylesheets )加载,但延迟脚本(deferred scripts)会等待样式表(stylesheets ),并且DOMContentLoaded
事件排在延迟脚本之后。此外,非延迟或异步的脚本(例如<script>
)将等待已解析的样式表加载。- 应仅使用不同的事件
load
来检测页面是否已完全加载。使用load
一个常见错误是用成了DOMContentLoaded
,因为后者可能更合适。 - 此事件不可取消。
- 当 HTML 文档已完全解析且所有延迟脚本(deferred scripts)(
download
: 附件(attachment)开始下载的事件。page.on("download")
可分发Download对象,该对象可用于对下载文件的操作。
filechooser
:当应该出现文件选择器( file chooser)时的事件,例如单击<input type=file>
后。frameattached
:Frame对象被附加(attached)的事件。- Frame介绍: 通过使用Frame,你可以在同一个浏览器窗口中显示不止一个页面,简而言之,就是在一个窗口中显示多个页面。 每个页面称之为一个框架。并且每个框架独立于其他的框架。
Frame
对象的生命周期受三个事件控制:page.on("frameattached")
,page.on("framenavigated")
,page.on("framedetached")
framedetached
: Frame被分离( detached).framenavigated
:Frame被导航到新的 url。load
: JavaScript的load事件被分发时的事件.- load介绍:整个页面加载完成后会触发load事件,包括所有依赖资源(例如样式表、脚本、iframe 和图像,但延迟加载( loaded lazily)的资源除外)。这不同于DOMContentLoaded,后者在页面 DOM 加载完成后立即触发,而不等待资源完成加载。
pageerror
:当页面内发生未捕获的异常时的事件。popup
:当页面打开新选项卡或窗口时的事件。browser_context.on("page")
也会触发此事件,但仅针对与此页面相关的弹出窗口(popups)。- 该页面最早可用的时刻是导航到初始 URL 时。例如,当使用
window.open('http://example.com')
打开弹出窗口时,当对http://example.com”
的网络请求完成并且其响应已开始加载时,将触发此事件弹出窗口。
request
:当页面发出请求时的事件。- request对象介绍:每当页面发送对网络资源的请求时,
Page
对象都会发出以下事件序列:page.on("request")
、page.on("response")
、page.on("requestfinished")
。
- request对象介绍:每当页面发送对网络资源的请求时,
requestfailed
:当请求失败时的事件,例如超时。requestfinished
:当响应正文下载且请求完成时的事件。response
:当/如果收到请求的响应状态和标头时的事件。websocket
:WebSocket请求发出时的事件。worker
:当页面生成专用 WebWorker 时的事件。- Web Workers 可以在与 Web 应用程序的主执行线程分开的后台线程中运行脚本操作。这样做的优点是可以在单独的线程中执行繁重的处理,从而允许主(通常是 UI)线程运行而不会被阻塞/减慢。
- 处理crash,处理崩溃最常见的方式是捕获异常:
try:# crash might happen during a click.page.click("button")# or while waiting for an event.page.wait_for_event("popup")
except Error as e:pass# when the page crashes, exception message contains "crash".
2.2 page.on() 监听事件
2.3 wait_util参数
wait_until : Union["commit", "domcontentloaded", "load", "networkidle", None]
等待到某个事件触发,默认值 load
. 可选参数:
'domcontentloaded'
-DOMContentLoaded
事件触发'load'
-load
事件触发.'networkidle'
- 不建议使用,当网络断连至少500
ms时触发。不要使用此方法进行测试,而是依靠网络assert来评估准备情况。'commit'
- 当收到网络响应并且文档开始时加载中时触发。
2.4 Role:
"alert" | "alertdialog" | "application" | "article" | "banner" | "blockquote" | "button" | "caption" | "cell" | "checkbox" | "code" | "columnheader" | "combobox" | "complementary" | "contentinfo" | "definition" | "deletion" | "dialog" | "directory" | "document" | "emphasis" | "feed" | "figure" | "form" | "generic" | "grid" | "gridcell" | "group" | "heading" | "img" | "insertion" | "link" | "list" | "listbox" | "listitem" | "log" | "main" | "marquee" | "math" | "meter" | "menu" | "menubar" | "menuitem" | "menuitemcheckbox" | "menuitemradio" | "navigation" | "none" | "note" | "option" | "paragraph" | "presentation" | "progressbar" | "radio" | "radiogroup" | "region" | "row" | "rowgroup" | "rowheader" | "scrollbar" | "search" | "searchbox" | "separator" | "slider" | "spinbutton" | "status" | "strong" | "subscript" | "superscript" | "switch" | "tab" | "table" | "tablist" | "tabpanel" | "term" | "textbox" | "time" | "timer" | "toolbar" | "tooltip" | "tree" | "treegrid" | "treeitem"
三、 调试和定位元素
在编写自动化测试脚本时,经常需要调试和定位页面上的元素。Playwright提供了多种方法来定位元素,如使用CSS选择器、XPath等。
3.1 调试
使用page.pause()
:在脚本中添加page.pause()
方法,可以在执行到该位置时暂停脚本,并自动打开Playwright Inspector
工具,方便进行页面调试。
Playwright Inspector是Playwright框架中自带的GUI工具,可以辅助开发者调试Playwright脚本。以下是Playwright Inspector的使用方法:
【PlayWright】Playwright Inspector使用
3.2 定位元素 Locator
Playwright提供了page.locator()
方法来定位页面上的元素,它支持多种选择器,如CSS选择器、XPath等。
Locator
是用来执行动作的对象。以前的Page.click
已经被废弃,用Locator.click
.
除了推荐的Locator(如 page.get_by_role()
和 page.get_by_text()
)之外,Playwright 还支持本各种其他定位器。
chrom中便捷获取xpath的方法
Locator获取元素属性:
<a data-v-323b850e="" class="titlecontent" href="https://xxxxxxx" target="_blank" title="硬件单板互连设计工程师" style="max-width: 598px;"><!----><span data-v-323b850e="">硬件单板互连设计工程师</span>
</a>
h1 = i.locator('a.titlecontent')
url = h1.get_attribute('href') # https://xxxxxxx
title = h1.get_attribute('title') # 硬件单板互连设计工程师
3.2.1 CSS locator
3.2.2 N-th element locator
3.2.3 Parent element locator
3.2.4 Parent element locator
3.2.5 Vue locator
3.2.6 XPath locator
3.2.7 Label to form control retargeting
3.2.8 Legacy text locator
3.2.9 id, data-testid, data-test-id, data-test selectors
3.2.10 Chaining selectors
3.2.11 Intermediate matches
3.3 定位元素 ElementHandle
The difference between the Locator and ElementHandle is that the ElementHandle points to a particular element, while Locator captures the logic of how to retrieve an element.
ElementHandle 也可以用get_attribute
获取元素属性。
Locator转ElementHandle
Locator有以下两个函数,可用来将返回Locator对应的ElementHandle
def element_handle(self, *, timeout: typing.Optional[float] = None) -> "ElementHandle":"""Locator.element_handleResolves given locator to the first matching DOM element. If there are no matching elements, waits for one. Ifmultiple elements match the locator, throws.Parameters----------timeout : Union[float, None]Maximum time in milliseconds. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. The default value canbe changed by using the `browser_context.set_default_timeout()` or `page.set_default_timeout()` methods.Returns-------ElementHandle"""return mapping.from_impl(self._sync(self._impl_obj.element_handle(timeout=timeout)))def element_handles(self) -> typing.List["ElementHandle"]:"""Locator.element_handlesResolves given locator to all matching DOM elements. If there are no matching elements, returns an empty list.Returns-------List[ElementHandle]"""return mapping.from_impl_list(self._sync(self._impl_obj.element_handles()))
参考
官网教程
官方视频