如何调试
注意事项
- Playwright 专有伪类:
:text()
、:text-is()
、:text-matches()
、:nth-match(selector, idx)
是 Playwright 独有,需通过:where()
或:has()
嵌入 CSS。 - :where()和:has()是css selector标准语法
- 标准 CSS 伪类:如
:first-child
、:not()
是标准 CSS,Playwright 完全支持。 - 性能:复杂伪类(如
:has()
、:text-matches()
)可能影响性能,尽量结合具体类或 ID。 - 调试:使用
.count()
、.is_visible()
和page.content()
排查count=0
问题。 - 你的场景:
:has()
、:where()
、:text-is()
和:visible
是最常用的,适合定位 “No Ice” 和 “Medium”。 - locator()支持链式定位.locator(selector).locator(selector)
- :has-text()不用:where(),但只能用于element直接带有text的情况,不能跨tag级别查询,尽量少用。
Text匹配与使用场景 – :where(:text()) :where()支持多条件,单条件可以直接使用tag:text()
伪类 | 匹配方式 | 大小写敏感 | 适用场景 | 示例 HTML 匹配情况 |
---|---|---|---|---|
:text("value") | 部分匹配 | 不区分 | 快速查找包含某文本的元素,可能有歧义 | <div>No Ice</div> , <div>No Ice Cream</div> |
:text-is("value") | 精确匹配 | 区分(可加 i ) | 需要精确匹配特定文本,避免部分匹配的歧义 | <div>No Ice</div> (不匹配 <div>No Ice Cream</div> ) |
:text-matches("regex") | 正则表达式 | 区分(可加 i ) | 复杂文本模式或部分匹配,例如动态标题或特定格式 | <div>DOUBLE CHOCO COCO NUTS Ingredients</div> |
在Chrome devTools里面
1. console里面, 注意需要先输入allow paste
然后利用属性调试文字
在playwright中
'div.option[data-testid="dropdown-option"]:where(:text("9:00 AM CDT"))'
:where(:text("")) 不是css selector定义
不是css selector定义,而是playwright增强,我们无法在浏览器中直接调试。
可以利用其他定位方式+element.textContent.trim(),打印文字看看。
document.querySelectorAll('div.option[data-testid="dropdown-option"]').forEach(element => {
console.log("Time:", element.textContent.trim());
if (element.textContent.trim() === "8:00 PM CDT") {
element.style.border = "2px solid red";
}
});
多属性定位
div.option[data-testid="dropdown-option"][role="option"]
用BeautifulSoup4调试
from bs4 import BeautifulSoup
# Modified HTML with 9:00 AM CDT added
html = """
<div class="diningOptionsContent" role="form" data-testid="diningOptions">
<div class="prompt" id="time-dropdown-label">Time</div>
<div class="options">
<div class="dropDown withBorder" aria-labelledby="#time-dropdown-label" aria-description="select a time" role="combobox" aria-haspopup="false" aria-expanded="false" data-testid="fulfillment-time-selector" tabindex="0">
<div class="dropDownLabel">7:15 AM CDT</div>
<div class="arrow">
<div aria-hidden="true" class="dropDownArrow"></div>
</div>
<div class="dropDownContent hide" data-testid="fulfillment-time-selector" role="listbox">
<div class="option" tabindex="0" role="option" data-testid="dropdown-option">7:15 AM CDT</div>
<div class="option" tabindex="0" role="option" data-testid="dropdown-option">7:30 AM CDT</div>
<div class="option" tabindex="0" role="option" data-testid="dropdown-option">7:45 AM CDT</div>
<div class="option" tabindex="0" role="option" data-testid="dropdown-option">9:00 AM CDT</div>
</div>
</div>
</div>
</div>
"""
# Parse HTML
soup = BeautifulSoup(html, 'html.parser')
# Test selector
selector = 'div.option[data-testid="dropdown-option"]'
options = soup.select(selector)
# Debug: List options and check for "9:00 AM CDT"
print("Available options:")
for option in options:
text = option.get_text(strip=True)
print(f"Time: {text}")
if text == "9:00 AM CDT":
print(f"Found 9:00 AM CDT: {option}")
操作符
元素关系操作符号
空格: 选择某个元素内的所有指定后代元素
+ 第一个兄弟元素 sibling
> 直接子元素
~ 所有兄弟元素
属性匹配操作符
[attribute] 选择有该属性的元素
[attribute=”value”] 属性值精确等于
[attribute*=”value”] 包含该值
[attribute^=”value”] 以该值开头 start with
[attribute$=”value”] 以该值结尾 end with
[attribute~=”value”] 空格间隔的属性值之一匹配
[attribute|=”value”] 精确等于该值,或以该值加上一个’-‘开头
第一部分: CSS Selector详解
CSS 选择器(CSS Selector)是用于定位和选择 HTML 元素以应用样式的工具,是 CSS 核心的一部分。以下是对 CSS 选择器的详细介绍,包括关键字、语法、使用场景和示例。
一、CSS 选择器的作用
CSS 选择器用于从 HTML 文档中选择特定的元素,以便应用样式或操作。选择器可以基于元素的标签名、类、ID、属性、层级关系、状态等进行定位。
二、CSS 选择器的分类及关键字
CSS 选择器可以分为以下几类,每类选择器有特定的关键字或符号:
- 基本选择器
- 元素选择器:直接使用 HTML 标签名。
- 语法:
tagname
- 示例:
p
选择所有<p>
标签。
- 语法:
- 类选择器:通过元素的
class
属性选择。- 关键字:
.
(点) - 语法:
.classname
- 示例:
.btn
选择所有具有class="btn"
的元素。
- 关键字:
- ID 选择器:通过元素的
id
属性选择。- 关键字:
#
- 语法:
#idname
- 示例:
#header
选择id="header"
的元素。
- 关键字:
- 通配符选择器:选择所有元素。
- 关键字:
*
- 语法:
*
- 示例:
* { margin: 0; }
为所有元素设置 margin 为 0。
- 关键字:
- 属性选择器:根据元素的属性或属性值选择。
- 关键字:
[]
- 语法:
[attribute]
,[attribute="value"]
,[attribute*="value"]
等 - 示例:
[type="text"]
选择所有type
属性为text
的输入框。
- 关键字:
- 组合选择器
- 后代选择器:选择某个元素内的所有指定后代元素。
- 关键字:空格
- 语法:
parent descendant
- 示例:
div p
选择<div>
内的所有<p>
。
- 子选择器:选择某个元素的直接子元素。
- 关键字:
>
- 语法:
parent > child
- 示例:
ul > li
选择<ul>
的直接子元素<li>
。
- 关键字:
- 相邻兄弟选择器:选择紧跟在某元素后的第一个兄弟元素。
- 关键字:
+
- 语法:
element + element
- 示例:
h1 + p
选择紧跟在<h1>
后的第一个<p>
。
- 关键字:
- 通用兄弟选择器:选择某元素后的所有兄弟元素。
- 关键字:
~
- 语法:
element ~ element
- 示例:
h1 ~ p
选择<h1>
后的所有同级<p>
元素。
- 关键字:
- 伪类选择器
- 用于选择元素特定状态或位置。
- 关键字:
:
- 常见伪类:
:hover
:鼠标悬停时的状态。:first-child
:选择第一个子元素。:last-child
:选择最后一个子元素。:nth-child(n)
:选择第 n 个子元素(n 可以是数字、关键字如odd
/even
、公式如2n+1
)。:not(selector)
:选择不符合某个选择器的元素。
- 示例:
a:hover
选择鼠标悬停在<a>
元素时的状态。
- 伪元素选择器
- 用于选择元素的特定部分。
- 关键字:
::
(CSS3 推荐,CSS2 使用:
兼容) - 常见伪元素:
::before
:在元素内容前插入内容。::after
:在元素内容后插入内容。::first-line
:选择元素的第一行。::first-letter
:选择元素的首字母。
- 示例:
p::first-letter { font-size: 2em; }
放大段落首字母。
- 分组选择器
- 将多个选择器组合,应用相同样式。
- 关键字:
,
(逗号) - 语法:
selector1, selector2
- 示例:
h1, h2, h3
为所有<h1>
、<h2>
、<h3>
应用相同样式。
playwright不支持的伪类/伪元素
:visited, :hover, :active
:contains()
::before, ::after
三、CSS 选择器的语法
CSS 选择器的基本结构:
selector {
property: value;
}
- selector:选择器,用于定位 HTML 元素。
- property:CSS 属性,如
color
、font-size
。 - value:属性的值,如
red
、16px
。
选择器可以单独使用,也可以组合使用以提高精确度。例如:
div.container > p:first-child {
color: blue;
}
上述代码选择 <div class="container">
中第一个直接子元素 <p>
,并设置其文字颜色为蓝色。
四、CSS 选择器的使用场景
- 样式应用:为特定元素或元素组设置样式(如字体、颜色、边距)。
- 动态效果:通过伪类(如
:hover
、:focus
)实现交互效果。 - 内容修饰:通过伪元素(如
::before
、::after
)添加装饰性内容。 - 复杂结构定位:通过组合选择器定位 DOM 树中的特定元素。
- 响应式设计:结合媒体查询和选择器为不同设备应用不同样式。
五、CSS 选择器的优先级
CSS 选择器的优先级决定了当多个选择器作用于同一元素时,哪个样式生效。优先级计算基于以下规则:
- 内联样式(直接写在 HTML 元素上的
style
属性):1000 - ID 选择器:100
- 类选择器、属性选择器、伪类:10
- 元素选择器、伪元素:1
- 通配符选择器:0
注意:
- 优先级高的选择器覆盖优先级低的。
- 如果优先级相同,后定义的样式覆盖先定义的。
!important
可以提升样式优先级,但应谨慎使用。
示例:
#container p { color: red; } /* 优先级 100 + 1 = 101 */
p { color: blue; } /* 优先级 1 */
<p>
的颜色将是红色,因为 #container p
的优先级更高。
六、示例代码
以下是一个综合示例,展示不同类型选择器的使用:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<style>
/* 元素选择器 */
p {
font-size: 16px;
}
/* 类选择器 */
.highlight {
background-color: yellow;
}
/* ID 选择器 */
#header {
color: navy;
}
/* 属性选择器 */
input[type="text"] {
border: 1px solid gray;
}
/* 后代选择器 */
div p {
margin-left: 10px;
}
/* 子选择器 */
ul > li {
list-style: none;
}
/* 相邻兄弟选择器 */
h1 + p {
font-weight: bold;
}
/* 伪类选择器 */
a:hover {
color: red;
}
/* 伪元素选择器 */
p::first-letter {
font-size: 1.5em;
}
/* 分组选择器 */
h1, h2, h3 {
font-family: Arial, sans-serif;
}
</style>
</head>
<body>
<div id="header">
<h1>标题</h1>
<p class="highlight">这是一个高亮段落</p>
<p>普通段落</p>
<ul>
<li>列表项1</li>
<li>列表项2</li>
</ul>
<input type="text" placeholder="输入文本">
<a href="#">链接</a>
</div>
</body>
</html>
效果说明:
<h1>
文字为 navy 色(ID 选择器)。- 第一个
<p>
有黄色背景(类选择器)。 - 所有
<p>
的字体大小为 16px(元素选择器)。 <div>
内的<p>
有左边距(后代选择器)。<ul>
的直接子<li>
无列表样式(子选择器)。- 紧跟
<h1>
的<p>
加粗(相邻兄弟选择器)。 <a>
鼠标悬停时变红(伪类选择器)。- 段落首字母放大(伪元素选择器)。
七、注意事项
- 性能:选择器复杂性会影响渲染性能,尽量避免过于复杂的嵌套选择器。
- 特异性:优先级高的选择器可能导致样式难以覆盖,建议保持选择器简洁。
- 浏览器兼容性:某些伪类和伪元素(如
::selection
)在老版本浏览器可能不完全支持。 - 语义化:选择器应与 HTML 结构语义化结合,避免过度依赖类或 ID。
八、扩展:现代 CSS 选择器
CSS3 和 CSS4 引入了一些高级选择器,增强了选择能力:
:where()
:简化复杂选择器逻辑。- 示例:
:where(h1, h2, h3) { color: blue; }
:has()
:选择包含特定子元素的父元素(部分浏览器支持)。- 示例:
section:has(h2) { border: 1px solid; }
:is()
:替代分组选择器,减少重复。- 示例:
:is(h1, h2, h3) { font-weight: bold; }
九、总结
CSS 选择器是 CSS 的核心工具,通过不同的选择器类型(基本、组合、伪类、伪元素等)和关键字(.
、#
、>
等),可以精确地定位 HTML 元素并应用样式。理解选择器的语法和优先级是编写高效、清晰 CSS 代码的关键。开发者应根据项目需求选择合适的选择器,并注意性能和兼容性。
在 Playwright 中,CSS 选择器是定位网页元素的主要方式之一,用于自动化测试、网页抓取和用户界面交互。Playwright 提供了强大的选择器支持,结合其 page.locator()
方法,可以高效、精准地定位 DOM 元素。以下是 CSS 选择器在 Playwright 中的详细使用说明,包括语法、常见用法、示例代码和最佳实践。
第二部分: CSS Selector详解
一、CSS 选择器在 Playwright 中的基本使用
Playwright 使用 page.locator()
方法来创建定位器(Locator),通过传入 CSS 选择器字符串来定位元素。Playwright 会自动检测 CSS 选择器,无需显式指定 css=
前缀(尽管可以手动添加以确保明确性)。
基本语法:
await page.locator('CSS_SELECTOR').ACTION();
CSS_SELECTOR
:标准的 CSS 选择器字符串,如div
,.class
,#id
,[attribute="value"]
等。ACTION
:对定位元素的操作,如click()
,fill()
,textContent()
等。
示例:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
// 使用 CSS 选择器定位元素
await page.locator('h1').click(); // 点击所有 <h1> 元素
await page.locator('.my-class').fill('Hello'); // 在 class="my-class" 的输入框中输入
await page.locator('#my-id').textContent(); // 获取 id="my-id" 元素的文本内容
await browser.close();
})();
二、支持的 CSS 选择器类型
Playwright 支持标准 CSS 选择器,包括以下类型:
- 元素选择器:
- 定位特定标签名的元素。
- 示例:
page.locator('p')
定位所有<p>
元素。
- 类选择器:
- 使用
.
定位具有特定 class 的元素。 - 示例:
page.locator('.btn')
定位所有class="btn"
的元素。
- ID 选择器:
- 使用
#
定位具有特定 ID 的元素。 - 示例:
page.locator('#header')
定位id="header"
的元素。
- 属性选择器:
- 定位具有特定属性的元素。
- 示例:
page.locator('input[type="text"]')
定位所有type="text"
的输入框。
- 后代选择器:
- 使用空格定位父元素内的后代元素。
- 示例:
page.locator('div p')
定位<div>
内的所有<p>
。
- 子选择器:
- 使用
>
定位直接子元素。 - 示例:
page.locator('ul > li')
定位<ul>
的直接子<li>
。
- 伪类选择器:
- Playwright 支持标准伪类(如
:hover
,:first-child
)以及自定义伪类(如:visible
)。 - 示例:
page.locator('button:visible')
定位所有可见的<button>
元素。
- 组合选择器:
- 使用逗号组合多个选择器。
- 示例:
page.locator('button:has-text("Log in"), button:has-text("Sign in")')
定位文本为 “Log in” 或 “Sign in” 的按钮。
三、Playwright 增强的 CSS 选择器特性
Playwright 对标准 CSS 选择器进行了扩展,增加了以下功能:
- 自定义伪类:
:visible
:定位可见元素。- 示例:
page.locator('input:visible')
只定位可见的输入框。
- 示例:
:has-text()
:定位包含指定文本的元素(大小写不敏感,忽略多余空格)。- 示例:
page.locator('article:has-text("Playwright")')
定位包含 “Playwright” 文本的<article>
。
- 示例:
:has()
:定位包含特定子元素的元素(实验性功能)。- 示例:
page.locator('article:has(div.promo)')
定位包含class="promo"
的<div>
的<article>
。
- 示例:
:nth-match()
:定位匹配选择器的第 n 个元素(0 基索引)。- 示例:
page.locator(':nth-match(:text("Buy"), 2)')
定位第三个包含 “Buy” 文本的元素。
- 示例:
- Shadow DOM 支持:
- Playwright 的 CSS 选择器默认可以穿透开放模式的 Shadow DOM,无需额外配置。
- 示例:
page.locator('x-details div')
可以定位 Shadow DOM 内的<div>
。
- 布局选择器:
- Playwright 支持基于页面布局的伪类,如
:right-of()
,:left-of()
,:above()
,:below()
,:near()
。 - 示例:
page.locator('input:right-of(:text("Password"))')
定位位于 “Password” 文本右侧的输入框。 - 注意:布局选择器依赖页面布局,可能会因像素级变化导致不稳定,需谨慎使用。
- 数据属性选择器:
- 推荐使用
data-testid
或自定义数据属性(如data-pw
)来定位元素,提高测试稳定性。 - 示例:
page.locator('[data-testid="submit"]')
定位具有data-testid="submit"
的元素。 - 配置自定义测试 ID:
javascript import { defineConfig } from '@playwright/test'; export default defineConfig({ use: { testIdAttribute: 'data-pw' } });
然后使用page.getByTestId('value')
定位data-pw="value"
的元素。
四、常见使用场景和示例
以下是一些在 Playwright 中使用 CSS 选择器的典型场景:
- 点击按钮:
await page.locator('button.submit').click(); // 点击 class="submit" 的按钮
- 填写表单:
await page.locator('input[name="username"]').fill('JohnDoe'); // 填写用户名
- 获取文本内容:
const text = await page.locator('#header').textContent();
console.log(text); // 输出 id="header" 元素的文本
- 处理动态内容:
Playwright 的自动等待机制确保元素可操作,结合 CSS 选择器可处理动态加载的元素。
await page.locator('.dynamic-content:visible').waitFor(); // 等待动态内容可见
await page.locator('.dynamic-content').click();
- 定位多个元素:
使用locatorAll()
获取匹配选择器的所有元素。
const items = await page.locator('ul > li').all();
for (const item of items) {
console.log(await item.textContent());
}
- 链式定位:
链式调用locator()
缩小定位范围。
const locator = page.locator('div.container').locator('p:first-child');
await locator.click(); // 点击 div.container 中的第一个 <p>
- 处理 Shadow DOM:
await page.locator('x-custom-component button').click(); // 定位 Shadow DOM 内的按钮
五、最佳实践
- 优先使用用户感知的定位器:
- 使用
page.getByRole()
,page.getByText()
,page.getByTestId()
等内置定位器,这些更贴近用户交互,稳定性更高。 - 示例:
page.getByRole('button', { name: 'Sign in' })
比page.locator('button.sign-in')
更可靠。
- 避免复杂选择器:
- 过长的 CSS 选择器(如
#tsf > div:nth-child(2) > div > input
)与 DOM 结构紧密耦合,易因页面变化失效。 - 推荐使用简洁、稳定的选择器,如
[data-testid="search"]
。
- 使用数据属性:
- 为测试添加
data-testid
或自定义数据属性,明确区分测试和样式逻辑。 - 示例:
<button data-testid="submit">Submit</button>
,然后使用page.getByTestId('submit')
。
- 处理动态元素:
- 利用 Playwright 的自动等待机制,无需手动添加
waitForTimeout
。 - 示例:
await page.locator('.dynamic:visible').click()
自动等待元素可见。
- 避免伪元素:
- Playwright 不支持定位
::before
或::after
等伪元素,因为它们不在 DOM 树中。
- 测试稳定性:
- 使用
expect
断言元素状态(如isVisible()
)确保测试健壮性。 - 示例:
javascript const locator = page.locator('.welcome'); await expect(locator).toBeVisible();
- 调试选择器:
- 使用 Chrome DevTools 或 Playwright 的 Codegen 工具(
playwright codegen
)生成可靠的选择器。 - 示例:运行
npx playwright codegen https://example.com
自动生成选择器代码。
六、注意事项
- 优先级与 CSS 选择器:
- Playwright 不依赖 CSS 优先级,而是直接使用选择器匹配元素。确保选择器唯一以避免歧义。
- Shadow DOM 限制:
- CSS 选择器可以穿透开放模式的 Shadow DOM,但对闭合模式(closed Shadow DOM)不支持。
- 性能考虑:
- 避免使用过于复杂的选择器(如多层嵌套),以减少查询时间。
- 示例:
div > div > div > button
可能比[data-testid="button"]
慢且不稳定。
- 与 XPath 对比:
- CSS 选择器通常比 XPath 更快且更易读,但在复杂 DOM 结构中,XPath 可能更灵活。
- 示例:
page.locator('//div[@class="container"]//a')
比page.locator('div.container a')
更适合复杂路径。
七、综合示例
以下是一个完整的 Playwright 脚本,展示 CSS 选择器的多种用法:
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto('https://example.com');
// 定位并点击按钮
await page.locator('button.submit').click();
// 填写表单
await page.locator('input[name="search"]').fill('Playwright');
// 获取文本
const title = await page.locator('h1').textContent();
console.log('页面标题:', title);
// 验证元素可见性
await expect(page.locator('.result:visible')).toBeVisible();
// 定位 Shadow DOM 内的元素
await page.locator('x-custom-component .inner-button').click();
// 处理多个元素
const links = await page.locator('a').all();
for (const link of links) {
console.log(await link.textContent());
}
await browser.close();
})();
八、总结
在 Playwright 中,CSS 选择器通过 page.locator()
方法提供了一种简单且强大的方式来定位网页元素。Playwright 增强了 CSS 选择器功能,支持自定义伪类、Shadow DOM 和布局选择器,同时通过自动等待和重试机制确保测试稳定性。开发者应优先使用用户感知的定位器(如 getByRole
)和数据属性选择器(如 data-testid
),避免复杂或脆弱的 CSS 选择器,以提高测试的健壮性和可维护性。
在 CSS 中,属性选择器使用特定的操作符来根据元素的属性值进行匹配。这些操作符可以用来精确匹配、部分匹配、开头匹配或结尾匹配等。以下是 CSS 属性选择器的操作符列表及其用法,并结合你之前的问题(在 Playwright Python 异步 API 中查找 action
属性以 .do
结尾的表单),说明如何使用这些操作符。
第三部分 CSS 属性选择器操作符
以下是主要的 CSS 属性选择器操作符:
[attribute]
- 描述: 匹配具有指定属性的元素,不关心属性值。
- 示例:
[title]
选择带有title
属性的元素(如<a title="链接">
)。 - 用例: 查找具有特定属性的元素,忽略其值。
[attribute="value"]
- 操作符:
=
- 描述: 匹配属性值完全等于指定值的元素。
- 示例:
[action="/submit.do"]
选择<form action="/submit.do">
。 - 用例: 精确匹配特定属性值。
[attribute~="value"]
- 操作符:
~=
- 描述: 匹配属性值是以空格分隔的列表,且包含指定值的元素。
- 示例:
[class~="button"]
选择<div class="button primary">
。 - 用例: 用于像
class
这样包含多个值的属性。
[attribute|="value"]
- 操作符:
|=
- 描述: 匹配属性值完全等于指定值或以指定值开头并紧跟连字符 (
-
) 的元素。 - 示例:
[lang|="en"]
选择<html lang="en">
或<html lang="en-US">
。 - 用例: 常用于语言代码或连字符分隔的值。
[attribute^="value"]
- 操作符:
^=
- 描述: 匹配属性值以指定值开头的元素。
- 示例:
[href^="https"]
选择<a href="https://example.com">
。 - 用例: 匹配 URL 或以特定前缀开头的字符串。
[attribute$="value"]
- 操作符:
$=
- 描述: 匹配属性值以指定值结尾的元素。
- 示例:
[action$=".do"]
选择<form action="/submit.do">
(与你之前的问题相关)。 - 用例: 匹配文件扩展名或特定后缀,如
.do
。
[attribute*="value"]
- 操作符:
*=
- 描述: 匹配属性值包含指定子字符串的元素。
- 示例:
[action*="submit"]
选择<form action="/path/submit.do">
。 - 用例: 查找属性值中包含特定部分的元素。
大小写敏感性
- 默认情况下,CSS 属性选择器是大小写敏感的。
- 要进行大小写不敏感匹配,可以在选择器末尾添加
i
: - 示例:
[action$=".do" i]
匹配.do
、.DO
或.Do
。
与你之前的问题的联系
你之前询问如何在 Playwright 的 Python 异步 API 中使用 .locator()
查找 action
属性以 .do
结尾的表单。你使用了 CSS 选择器 form[action$=".do"]
,这正是使用了 $=
操作符来匹配以 .do
结尾的 action
属性。以下是一个结合你的问题(包括新标签页和屏幕录制)的示例,展示如何使用不同操作符查找表单并打印详细信息。
示例代码
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
# 启动浏览器
browser = await p.chromium.launch(headless=False)
# 创建带视频录制的新浏览器上下文
context = await browser.new_context(
record_video_dir="videos/",
record_video_size={"width": 1280, "height": 720}
)
# 打开初始页面
page = await context.new_page()
await page.goto("https://example.com") # 替换为包含表单的页面
print(f"初始页面 URL: {await page.url}")
# 使用 [action$=".do"] 查找 action 属性以 .do 结尾的表单
locator = page.locator('form[action$=".do"]')
# 打印 locator 详细信息
print("\n=== 表单 locator 详细信息 ===")
count = await locator.count()
print(f"action 以 '.do' 结尾的表单数量: {count}")
# 遍历并打印每个匹配表单的详细信息
for i in range(count):
form = locator.nth(i)
action = await form.get_attribute("action")
print(f"表单 {i + 1} action: {action}")
method = await form.get_attribute("method") or "未指定"
print(f"表单 {i + 1} method: {method}")
inner_html = await form.inner_html()
print(f"表单 {i + 1} 内部 HTML: {inner_html}")
is_visible = await form.is_visible()
print(f"表单 {i + 1} 是否可见: {is_visible}")
# 示例:使用其他操作符
# 精确匹配 [action="/submit.do"]
exact_locator = page.locator('form[action="/submit.do"]')
print(f"\naction 精确为 '/submit.do' 的表单数量: {await exact_locator.count()}")
# 包含 submit [action*="submit"]
contains_locator = page.locator('form[action*="submit"]')
print(f"action 包含 'submit' 的表单数量: {await contains_locator.count()}")
# 示例:打开新标签页
link_locator = page.locator('a[target="_blank"]')
if await link_locator.count() > 0:
async with context.expect_page() as new_page_info:
await link_locator.first.click()
new_page = await new_page_info.value
await new_page.wait_for_load_state("load")
print(f"\n新标签页 URL: {await new_page.url}")
# 在新标签页中查找 action 以 .do 结尾的表单
new_page_locator = new_page.locator('form[action$=".do"]')
new_count = await new_page_locator.count()
print(f"新标签页中 action 以 '.do' 结尾的表单数量: {new_count}")
if new_count > 0:
action = await new_page_locator.first.get_attribute("action")
print(f"新标签页中第一个表单的 action: {action}")
await new_page.close()
# 打印视频路径
print(f"\n初始页面视频保存路径: {await page.video.path()}")
if 'new_page' in locals():
print(f"新标签页视频保存路径: {await new_page.video.path()}")
# 关闭页面和上下文
await page.close()
await context.close()
await browser.close()
# 运行异步函数
asyncio.run(main())
代码说明
- 使用
[action$=".do"]
:
$=
操作符匹配action
属性以.do
结尾的表单(如<form action="/submit.do">
)。- 这与你之前的问题中使用的选择器一致。
- 其他操作符示例:
[action="/submit.do"]
使用=
操作符进行精确匹配。[action*="submit"]
使用*=
操作符匹配包含submit
的action
属性。
- 打印详细信息:
- 使用
count()
获取匹配的表单数量。 - 使用
get_attribute()
获取action
和method
属性。 - 使用
inner_html()
获取表单的内部 HTML。 - 使用
is_visible()
检查表单是否可见。
- 新标签页和屏幕录制:
- 代码包含了打开新标签页(通过点击
target="_blank"
的链接)和屏幕录制的功能,结合了你之前的问题。 - 在新标签页中也应用了相同的表单查找逻辑。
注意事项
- 测试页面: 示例使用
https://example.com
,但它可能没有action
以.do
结尾的表单。替换为实际包含此类表单的页面(如使用 Struts 框架的旧版 Web 应用)。如果你有具体 URL,可以提供以便定制示例。 - 选择器调试: 如果
count()
返回0
,使用await page.content()
或await page.pause()
检查页面 HTML,确保选择器正确。 - 大小写敏感:
[action$=".do"]
是大小写敏感的。使用[action$=".do" i]
进行大小写不敏感匹配。 - 错误处理: 在访问元素前检查
count()
,以避免未找到元素时的错误。 - 避免
include
错误: 如果检查action
属性值,使用 Python 的endswith(".do")
:
action = await locator.first.get_attribute("action") or ""
if action.endswith(".do"):
print("action 以 .do 结尾")
示例输出
如果页面有一个表单 <form action="/submit.do" method="POST">...</form>
,输出可能如下:
初始页面 URL: https://example.com
=== 表单 locator 详细信息 ===
action 以 '.do' 结尾的表单数量: 1
表单 1 action: /submit.do
表单 1 method: POST
表单 1 内部 HTML: <input type="text" name="username">
表单 1 是否可见: True
action 精确为 '/submit.do' 的表单数量: 1
action 包含 'submit' 的表单数量: 1
新标签页 URL: https://www.example.org
新标签页中 action 以 '.do' 结尾的表单数量: 0
初始页面视频保存路径: videos/video123.webm
新标签页视频保存路径: videos/video124.webm
调试建议
- 无匹配: 如果没有找到表单,检查页面 HTML 或使用 Playwright 的调试工具(
await page.pause()
)。 - 动态加载: 如果表单是动态加载的,使用
await page.wait_for_selector('form[action$=".do"]')
确保其存在。 - 特定网站: 如果你在特定网站上测试,提供 URL,我可以帮助优化选择器或处理动态内容。