playwright有自己强大的内置定位器,也支持传统的Xpath与CSS定位,本次以课堂派登录页为例子进行详细的定位方法测试。
常见的role类型,如下: | role | HTML示例 | 说明 | | -------- | ------------------------- | ----- | | button | `<button>` | 按钮 | | link | `<a>` | 链接 | | textbox | `<input>` / `<textarea>` | 文本输入框 | | checkbox | `<input type="checkbox">` | 复选框 | | radio | `<input type="radio">` | 单选框 | | combobox | `<select>` | 下拉框 | | heading | `<h1>`~`<h6>` | 标题 | | dialog | `<dialog>` / modal | 弹窗 | | img | `<img>` | 图片 | | table | `<table>` | 表格 |
可访问文本的标签优先级: | 优先级 | 来源 | | --- | ------------------------------- | | 1 | `aria-labelledby` | | 2 | `aria-label` | | 3 | `<label>` 标签 | | 4 | 元素文本内容 | | 5 | 其他控件如:placeholder |
则根据上述两点,账号输入框、密码输入框、登录按钮定位表达式如下:
pythonpage.get_by_role("textbox", name="请输入邮箱/手机号/账号").fill("")
page.get_by_role("textbox", name="请输入密码").fill("")
page.get_by_role("button", name="登录").click()
| 值 | 描述 | | --- | ------------------------------- | |True | 要求元素名称与name完全一致 | |False| 不要求完全一致,元素名称包含name即可 |
则之前的表达式可做如下修改:
pythonpage.get_by_role("textbox", name="邮箱/手机号/账号", exact=False).fill("")
page.get_by_role("textbox", name="密码", exact=False).fill("")
page.get_by_role("button", name="登录").click()
| 参数 | 类型 | 作用 |
|---|---|---|
| checked | bool | checkbox/radio状态 |
| pressed | bool | 按钮是否处于 pressed 状态 |
| selected | bool | option/tab选中 |
| expanded | bool | 是否展开 |
| level | int | heading等级 |
| disabled | bool | 是否禁用 |
注意该函数仅匹配DOM中的“可见文本节点”,而无法匹配placeholder中的内容,因为后者是HTML属性,不是文本节点。
| 值 | 描述 | | --- | ------------------------------- | |True | 要求元素名称与name完全一致 | |False| 不要求完全一致,元素名称包含name即可 |
使用该定位方式后的登录脚本则可修改为:
pythonpage.get_by_role("textbox", name="邮箱/手机号/账号", exact=False).fill("")
page.get_by_role("textbox", name="密码", exact=False).fill("")
page.get_by_text("登录", exact=True).click()
相关信息
一个 HTML 元素通常由三部分组成:
开始标签 + 属性 + 文本节点 + 结束标签 例如: <button class="login-btn">登录</button>
| 部分 | 类型 | 示例 |
|---|---|---|
<button> | 标签(HTML元素) | button |
class="login-btn" | HTML属性 | class |
登录 | 文本节点 | text node |
</button> | 结束标签 | button |
而
<input type="text" placeholder="请输入邮箱">
属性包括:
| 属性 | 值 |
|---|---|
| type | text |
| placeholder | 请输入邮箱 |
| class | el-input__inner |
| 值 | 描述 | | --- | ------------------------------- | |True | 要求元素名称与name完全一致 | |False| 不要求完全一致,元素名称包含name即可 |
这里以登录页面的“下次自动登录”进行举例,值得注意的是,该元素可以通过该方法定位到,但定位到的元素却无法进行点击操作,对于定位到的元素能否被点击,playwright有自己的一套判断标准,在这里不进行展开:
pythonpct = page.get_by_label("下次自动登录").count()
print("找到存在label标签的元素{}".format(pct))
>>>
1
使用标签中Placeholder的属性值进行定位:
使用该定位方式后的登录脚本则可修改为:
pythonpage.get_by_placeholder("邮箱/手机号/账号", exact=False).fill("")
page.get_by_placeholder("密码", exact=False).fill("")
page.get_by_text("登录", exact=True).click()
使用元素中的alt的属性值来进行定位(该元素通常是图像),由于登录页无该元素,在这里引用playwright官方文档中的例子进行说明:
html<img alt="playwright logo" src="/img/playwright-logo.svg" width="100" />
pythonpage.get_by_alt_text("playwright logo").click()
依旧使用playwright官方文档中的例子进行说明:
html<span title='Issues count'>25 issues</span>
pythonpage.get_by_title("Issues count").click()
专门用于通过 开发者预先在页面上标记的属性 来快速、稳定地定位元素。该标记旨在提高跨团队协作的效率。
html<input data-testid="login-username" placeholder="请输入账号">
pythonppage.get_by_test_id("login-username").fill("admin")
Playwright在原生的CSS的基础上新增了一些伪类选择器,如下:
| 伪类 | 作用 | 示例 |
|---|---|---|
:visible | 匹配可见元素 | button:visible |
:has-text() | 匹配包含指定文本 | button:has-text("Login") |
:has() | 匹配包含指定子元素 | div:has(button) |
nth= | 第N个元素 | |
:nth-match() | 第 N 个匹配元素 | :nth-match(button,3) |
结合上述定位方式后的登录脚本则可修改为:
python page.locator("input").locator("nth=0").fill("")
page.locator("input").locator("nth=1").fill("")
page.locator("button:has-text('登录')").click()
相关信息
伪类:一种用于描述元素特定状态或特征的CSS选择器,语法特点是以“:”开头,作用是满足某种条件是匹配元素,关于常见的CSS伪类请移步CSS 伪类
常见的Xpath表达式:
| 语法 | 含义 | 示例 |
|---|---|---|
// | 任意层级查找 | //div |
/ | 直接子节点 | /html/body/div |
@ | 属性 | //input[@id='username'] |
text() | 文本 | //button[text()='Login'] |
contains() | 包含 | //div[contains(@class,'login')] |
| | 管道运算符(Union)合并多个 XPath 查询结果 | //button | //a(匹配 button 或 a) |
结合上述定位方式后的登录脚本则可修改为:
python page.locator('//input[@placeholder="请输入邮箱/手机号/账号"]').fill("")
page.locator('//input[@placeholder="请输入密码"]').fill("")
page.locator('//button[./span="登录"]').click()
Playwright的官方文档强调优先使用内置定位,原因是内置定位方式更接近用户行为,定位方便,稳定性高,维护成本低,综合衡量我推荐的元素定位顺序如下:
在元素定位的过程中,我们经常会遇到这种情况:元素可以定位的到,但是无法对其进行点击、输入等操作,然后我们就会往外层找一点/往里层找一点,直到能进行操作为止,较为耗时间,有没有什么方法能够大致的判断出该节点是否可交互,我的经验是尽量定位真控件而不是伪控件。
| 控件类型 | HTML标签 |
|---|---|
| 输入框 | input |
| 按钮 | button |
| 下拉框 | select |
| 复选框 | input type="checkbox" |
| 单选框 | input type="radio" |
| class特征 | 组件 |
|---|---|
| el- | ElementUI |
| ant- | Ant Design |
| mui- | Material UI |
| v- | Vue组件 |
本文作者:精卫
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!