CSS Selector详解及Playwright应用

如何调试

注意事项

  • 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 选择器可以分为以下几类,每类选择器有特定的关键字或符号:

  1. 基本选择器
  • 元素选择器:直接使用 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 的输入框。
  1. 组合选择器
  • 后代选择器:选择某个元素内的所有指定后代元素。
    • 关键字:空格
    • 语法:parent descendant
    • 示例:div p 选择 <div> 内的所有 <p>
  • 子选择器:选择某个元素的直接子元素。
    • 关键字:>
    • 语法:parent > child
    • 示例:ul > li 选择 <ul> 的直接子元素 <li>
  • 相邻兄弟选择器:选择紧跟在某元素后的第一个兄弟元素。
    • 关键字:+
    • 语法:element + element
    • 示例:h1 + p 选择紧跟在 <h1> 后的第一个 <p>
  • 通用兄弟选择器:选择某元素后的所有兄弟元素。
    • 关键字:~
    • 语法:element ~ element
    • 示例:h1 ~ p 选择 <h1> 后的所有同级 <p> 元素。
  1. 伪类选择器
  • 用于选择元素特定状态或位置。
  • 关键字::
  • 常见伪类:
    • :hover:鼠标悬停时的状态。
    • :first-child:选择第一个子元素。
    • :last-child:选择最后一个子元素。
    • :nth-child(n):选择第 n 个子元素(n 可以是数字、关键字如 odd/even、公式如 2n+1)。
    • :not(selector):选择不符合某个选择器的元素。
  • 示例:a:hover 选择鼠标悬停在 <a> 元素时的状态。
  1. 伪元素选择器
  • 用于选择元素的特定部分。
  • 关键字:::(CSS3 推荐,CSS2 使用 : 兼容)
  • 常见伪元素:
    • ::before:在元素内容前插入内容。
    • ::after:在元素内容后插入内容。
    • ::first-line:选择元素的第一行。
    • ::first-letter:选择元素的首字母。
  • 示例:p::first-letter { font-size: 2em; } 放大段落首字母。
  1. 分组选择器
  • 将多个选择器组合,应用相同样式。
  • 关键字:,(逗号)
  • 语法:selector1, selector2
  • 示例:h1, h2, h3 为所有 <h1><h2><h3> 应用相同样式。

playwright不支持的伪类/伪元素

:visited, :hover, :active

:contains()

::before, ::after


三、CSS 选择器的语法

CSS 选择器的基本结构:

selector {
  property: value;
}
  • selector:选择器,用于定位 HTML 元素。
  • property:CSS 属性,如 colorfont-size
  • value:属性的值,如 red16px

选择器可以单独使用,也可以组合使用以提高精确度。例如:

div.container > p:first-child {
  color: blue;
}

上述代码选择 <div class="container"> 中第一个直接子元素 <p>,并设置其文字颜色为蓝色。


四、CSS 选择器的使用场景

  1. 样式应用:为特定元素或元素组设置样式(如字体、颜色、边距)。
  2. 动态效果:通过伪类(如 :hover:focus)实现交互效果。
  3. 内容修饰:通过伪元素(如 ::before::after)添加装饰性内容。
  4. 复杂结构定位:通过组合选择器定位 DOM 树中的特定元素。
  5. 响应式设计:结合媒体查询和选择器为不同设备应用不同样式。

五、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> 鼠标悬停时变红(伪类选择器)。
  • 段落首字母放大(伪元素选择器)。

七、注意事项

  1. 性能:选择器复杂性会影响渲染性能,尽量避免过于复杂的嵌套选择器。
  2. 特异性:优先级高的选择器可能导致样式难以覆盖,建议保持选择器简洁。
  3. 浏览器兼容性:某些伪类和伪元素(如 ::selection)在老版本浏览器可能不完全支持。
  4. 语义化:选择器应与 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 选择器,包括以下类型:

  1. 元素选择器
  • 定位特定标签名的元素。
  • 示例:page.locator('p') 定位所有 <p> 元素。
  1. 类选择器
  • 使用 . 定位具有特定 class 的元素。
  • 示例:page.locator('.btn') 定位所有 class="btn" 的元素。
  1. ID 选择器
  • 使用 # 定位具有特定 ID 的元素。
  • 示例:page.locator('#header') 定位 id="header" 的元素。
  1. 属性选择器
  • 定位具有特定属性的元素。
  • 示例:page.locator('input[type="text"]') 定位所有 type="text" 的输入框。
  1. 后代选择器
  • 使用空格定位父元素内的后代元素。
  • 示例:page.locator('div p') 定位 <div> 内的所有 <p>
  1. 子选择器
  • 使用 > 定位直接子元素。
  • 示例:page.locator('ul > li') 定位 <ul> 的直接子 <li>
  1. 伪类选择器
  • Playwright 支持标准伪类(如 :hover, :first-child)以及自定义伪类(如 :visible)。
  • 示例:page.locator('button:visible') 定位所有可见的 <button> 元素。
  1. 组合选择器
  • 使用逗号组合多个选择器。
  • 示例:page.locator('button:has-text("Log in"), button:has-text("Sign in")') 定位文本为 “Log in” 或 “Sign in” 的按钮。

三、Playwright 增强的 CSS 选择器特性

Playwright 对标准 CSS 选择器进行了扩展,增加了以下功能:

  1. 自定义伪类
  • :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” 文本的元素。
  1. Shadow DOM 支持
  • Playwright 的 CSS 选择器默认可以穿透开放模式的 Shadow DOM,无需额外配置。
  • 示例:page.locator('x-details div') 可以定位 Shadow DOM 内的 <div>
  1. 布局选择器
  • Playwright 支持基于页面布局的伪类,如 :right-of(), :left-of(), :above(), :below(), :near()
  • 示例:page.locator('input:right-of(:text("Password"))') 定位位于 “Password” 文本右侧的输入框。
  • 注意:布局选择器依赖页面布局,可能会因像素级变化导致不稳定,需谨慎使用。
  1. 数据属性选择器
  • 推荐使用 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 选择器的典型场景:

  1. 点击按钮
   await page.locator('button.submit').click(); // 点击 class="submit" 的按钮
  1. 填写表单
   await page.locator('input[name="username"]').fill('JohnDoe'); // 填写用户名
  1. 获取文本内容
   const text = await page.locator('#header').textContent();
   console.log(text); // 输出 id="header" 元素的文本
  1. 处理动态内容
    Playwright 的自动等待机制确保元素可操作,结合 CSS 选择器可处理动态加载的元素。
   await page.locator('.dynamic-content:visible').waitFor(); // 等待动态内容可见
   await page.locator('.dynamic-content').click();
  1. 定位多个元素
    使用 locatorAll() 获取匹配选择器的所有元素。
   const items = await page.locator('ul > li').all();
   for (const item of items) {
     console.log(await item.textContent());
   }
  1. 链式定位
    链式调用 locator() 缩小定位范围。
   const locator = page.locator('div.container').locator('p:first-child');
   await locator.click(); // 点击 div.container 中的第一个 <p>
  1. 处理 Shadow DOM
   await page.locator('x-custom-component button').click(); // 定位 Shadow DOM 内的按钮

五、最佳实践

  1. 优先使用用户感知的定位器
  • 使用 page.getByRole(), page.getByText(), page.getByTestId() 等内置定位器,这些更贴近用户交互,稳定性更高。
  • 示例:page.getByRole('button', { name: 'Sign in' })page.locator('button.sign-in') 更可靠。
  1. 避免复杂选择器
  • 过长的 CSS 选择器(如 #tsf > div:nth-child(2) > div > input)与 DOM 结构紧密耦合,易因页面变化失效。
  • 推荐使用简洁、稳定的选择器,如 [data-testid="search"]
  1. 使用数据属性
  • 为测试添加 data-testid 或自定义数据属性,明确区分测试和样式逻辑。
  • 示例:<button data-testid="submit">Submit</button>,然后使用 page.getByTestId('submit')
  1. 处理动态元素
  • 利用 Playwright 的自动等待机制,无需手动添加 waitForTimeout
  • 示例:await page.locator('.dynamic:visible').click() 自动等待元素可见。
  1. 避免伪元素
  • Playwright 不支持定位 ::before::after 等伪元素,因为它们不在 DOM 树中。
  1. 测试稳定性
  • 使用 expect 断言元素状态(如 isVisible())确保测试健壮性。
  • 示例:
    javascript const locator = page.locator('.welcome'); await expect(locator).toBeVisible();
  1. 调试选择器
  • 使用 Chrome DevTools 或 Playwright 的 Codegen 工具(playwright codegen)生成可靠的选择器。
  • 示例:运行 npx playwright codegen https://example.com 自动生成选择器代码。

六、注意事项

  1. 优先级与 CSS 选择器
  • Playwright 不依赖 CSS 优先级,而是直接使用选择器匹配元素。确保选择器唯一以避免歧义。
  1. Shadow DOM 限制
  • CSS 选择器可以穿透开放模式的 Shadow DOM,但对闭合模式(closed Shadow DOM)不支持。
  1. 性能考虑
  • 避免使用过于复杂的选择器(如多层嵌套),以减少查询时间。
  • 示例:div > div > div > button 可能比 [data-testid="button"] 慢且不稳定。
  1. 与 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 属性选择器操作符:

  1. [attribute]
  • 描述: 匹配具有指定属性的元素,不关心属性值。
  • 示例: [title] 选择带有 title 属性的元素(如 <a title="链接">)。
  • 用例: 查找具有特定属性的元素,忽略其值。
  1. [attribute="value"]
  • 操作符: =
  • 描述: 匹配属性值完全等于指定值的元素。
  • 示例: [action="/submit.do"] 选择 <form action="/submit.do">
  • 用例: 精确匹配特定属性值。
  1. [attribute~="value"]
  • 操作符: ~=
  • 描述: 匹配属性值是以空格分隔的列表,且包含指定值的元素。
  • 示例: [class~="button"] 选择 <div class="button primary">
  • 用例: 用于像 class 这样包含多个值的属性。
  1. [attribute|="value"]
  • 操作符: |=
  • 描述: 匹配属性值完全等于指定值或以指定值开头并紧跟连字符 (-) 的元素。
  • 示例: [lang|="en"] 选择 <html lang="en"><html lang="en-US">
  • 用例: 常用于语言代码或连字符分隔的值。
  1. [attribute^="value"]
  • 操作符: ^=
  • 描述: 匹配属性值以指定值开头的元素。
  • 示例: [href^="https"] 选择 <a href="https://example.com">
  • 用例: 匹配 URL 或以特定前缀开头的字符串。
  1. [attribute$="value"]
  • 操作符: $=
  • 描述: 匹配属性值以指定值结尾的元素。
  • 示例: [action$=".do"] 选择 <form action="/submit.do">(与你之前的问题相关)。
  • 用例: 匹配文件扩展名或特定后缀,如 .do
  1. [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())

代码说明

  1. 使用 [action$=".do"]:
  • $= 操作符匹配 action 属性以 .do 结尾的表单(如 <form action="/submit.do">)。
  • 这与你之前的问题中使用的选择器一致。
  1. 其他操作符示例:
  • [action="/submit.do"] 使用 = 操作符进行精确匹配。
  • [action*="submit"] 使用 *= 操作符匹配包含 submitaction 属性。
  1. 打印详细信息:
  • 使用 count() 获取匹配的表单数量。
  • 使用 get_attribute() 获取 actionmethod 属性。
  • 使用 inner_html() 获取表单的内部 HTML。
  • 使用 is_visible() 检查表单是否可见。
  1. 新标签页和屏幕录制:
  • 代码包含了打开新标签页(通过点击 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,我可以帮助优化选择器或处理动态内容。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注