(5)pytest+Selenium自动化测试-元素定位之XPath定位

上一节课咱们搞定了 CSS Selector,是不是已经能应对大部分复杂场景了?但如果遇到 "需要根据文本内容定位"、"元素层级特别复杂" 的情况,CSS Selector 就有点 "力不从心" 啦~ 这时候,XPath 这个 "全能王者" 就要登场!它不仅兼容 CSS 的大部分功能,还能直接定位文本、处理更灵活的层级关系,这节课咱们就彻底吃透 XPath,让你在自动化测试中 "无往不利"!

XPath 是什么?------ 比CSS更灵活的"定位神器"

XPath(XML Path Language)原本是用于解析XML文档的语言,因为它能遍历文档中任意节点,被完美应用到自动化测试的元素定位中。和CSS Selector相比,它的核心优势的是:

  • 支持文本定位(直接根据元素显示的文字找,CSS不支持!);
  • 支持反向定位(通过子元素找父元素,CSS做不到!);
  • 层级关系更灵活,支持复杂的节点遍历;
  • 兼容所有浏览器和移动端测试框架(Appium也能用!)。

简单说:CSS 是 "精准高效",XPath 是 "全能灵活",两者结合,自动化定位就没有解决不了的问题!

XPath 核心语法实战 ------ 从基础到高级,步步为营

XPath基础语法

以下表中是XPath选取节点的基础语法表达式:

|--------------|-----------------|
| 表达式 | 描述 |
| nodename | 选取此名称的所有子节点 |
| / | 从该节点的子元素选取 |
| // | 从该节点的子孙元素选取 |
| . | 选取当前节点 |
| .. | 选取当前节点的父节点 |
| @ | 选取属性 |

该部分的讲解,为了方便大家更好的理解XPath的基础语法,我们自定义一个HTML的结构进行案例讲解。

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>XPath 学习示例</title>
</head>
<body>
    <div id="container">
        <h1 class="title">欢迎学习 XPath</h1>
        <p>这是第一段介绍。</p>
        <div class="content">
            <p>这是第二段介绍,位于一个嵌套的 div 中。</p>
            <a href="https://www.example.com" target="_blank">访问示例网站</a>
        </div>
    </div>
    <p>这是最后一段介绍,在 container div 的外面。</p>
</body>
</html>

1、选取节点(nodename)

语法: nodename
作用: 直接写节点名称,选取所有该名称的子节点(相对当前上下文)。
示例: 在Html中,选取所有< p >节点

Xpath表达式://p (结合 // 从全局查找)

结果:选取到 3 个 <p> 节点,分别是:

  • <p>这是第一段介绍。</p>
  • <p>这是第二段介绍,位于一个嵌套的 div 中。</p>
  • <p>这是最后一段介绍,在 container div 的外面。</p>

2. 绝对路径(/)

语法: /根节点/子节点/...
作用: 从文档根节点开始,逐级向下选取直接子节点(类似文件系统的绝对路径)。
示例: 从根节点出发,精确查找嵌套的 <a> 标签

XPath 表达式:/html/body/div/div/a

解析:

  • /html: 从文档的根节点 <html> 开始。
  • /body: 选取 <html> 的直接子节点 <body>。
  • /div: 选取 <body> 的直接子节点 <div>(即 div#container)。
  • /div: 选取上一个 div 的直接子节点 <div>(即 div.content)。
  • /a: 选取上一个 div 的直接子节点 <a>。

结果:精确地选取到 1 个节点,即 <a href="https://www.example.com" ...>。

3. 相对路径(//)

语法: //节点 或 上下文//节点
作用: 不考虑节点在文档中的位置(忽略层级),从当前上下文(或全局)查找所有匹配的节点(包括子孙节点)。
示例: 在Html中,选取所有< p >节点

XPath表达式://p

结果:3 个 <p> 都被选中,分别是:

  • <p>这是第一段介绍。</p>
  • <p>这是第二段介绍,位于一个嵌套的 div 中。</p>
  • <p>这是最后一段介绍,在 container div 的外面。</p>

4. 当前节点(.)

语法: .
作用: 表示 "当前节点",常用于限定查找范围(避免全局查找的歧义)。
示例: 假设我们已经定位到id="container"的 div 节点,现在要在这个 div 内部找a。

XPath 表达式:.//a

解析:. 代表当前的 div 节点,//a 表示在当前节点的所有后代中查找 <a> 标签。

结果:选取到 1 个节点,即 <a href="https://www.example.com" ...>。

5. 父节点(..)

语法: ..
作用: 表示 "当前节点的父节点",用于向上回溯层级。
示例: 查找 <a> 标签的父节点

XPath表达式://a/..

解析://a 找到文档中的 <a> 标签,/.. 表示选取该 <a> 节点的父节点。

结果:选取到 1 个节点,即 <div class="content">。

6. 选取属性(@)

语法: @属性名
作用: @ 符号用于选取节点的属性。
示例: 查找 id 属性值为 container 的 div 节点

XPath 表达式: //div[@id="container"]

解析: 这是最常用的场景之一。[] 中的内容是条件表达式。@id="container" 表示节点的 id 属性值必须严格等于 "container"。

结果: 精确地选取到 1 个节点,即 <div id="container">。

XPath高级语法

我们可以将高级语法理解为 XPath 的 "查询条件" 和 "定位策略" 的扩展。

  • 谓语 (Predicate) []: 这是最核心的高级特性,用来过滤节点。所有复杂的条件都写在方括号 [] 内。
  • 运算符 (Operators): 在谓语内部使用,用于比较、计算和逻辑判断(如 =, !=, >, <, and, or, +, - 等)。
  • 轴 (Axes): 定义了当前节点与目标节点之间的 "树状关系"(如 child, parent, sibling, ancestor 等),让你能以更精细的方式定位节点。
  • 函数(Function):提供文本处理、数值计算、节点位置等能力(如:text(), position(), contains(), starts-with()等)。

谓语、运算符、轴、函数的完整定义可参考官方文档,这里我们将通过任务驱动的方式,结合下方的 HTML 文档实例,重点学习这些特性的实际用法。

html 复制代码
<!DOCTYPE html>
<html>
<head>
    <title>XPath 学习示例</title>
</head>
<body>
    <div id="container">
        <h1 class="title">欢迎学习 XPath</h1>
        <p>这是第一段介绍。</p>
        <div class="content">
            <p>这是第二段介绍,位于一个嵌套的 div 中。</p>
            <a href="https://www.example.com" target="_blank">访问示例网站</a>
            <p>这是第三段介绍,也在 content div 中。</p>
        </div>
        <p>这是第四段介绍。</p>
    </div>
    <p>这是最后一段介绍,在 container div 的外面。</p>
    <ul>
        <li>列表项 1</li>
        <li class="highlight">列表项 2 (高亮)</li>
        <li>列表项 3</li>
    </ul>
</body>
</html>

任务一:精准定位 - 使用 "属性" 和 "文本" 作为条件

目标1: 找到 class 为 highlight 的列表项 <li>。

XPath 表达式: //li[@class="highlight"]

解析:

  • //li: 找到文档中所有的 <li> 节点。
  • ...\]: 这是一个谓语,对前面找到的 \ 节点进行过滤。

  • @class: 使用 @ 选取 class 属性。
  • =: 这是一个比较运算符,表示 "等于"。
  • "highlight": 字符串字面量,作为比较的目标值。

结果: 精确地选取到 <li class="highlight">列表项 2 (高亮)</li>。
目标2:找到文本内容为 "这是第四段介绍。" 的 <p> 节点。

XPath 表达式: //p[text()="这是第四段介绍。"]

解析:

  • text(): 这是一个函数,返回节点的文本内容。
  • text()="这是第四段介绍。": 在谓语中,我们比较节点的文本内容是否等于指定字符串。

任务二:范围查找 - 使用 "逻辑运算" 和 "位置"

目标: 找到 div#container 下的第 2 个和第 3 个 <p> 节点。

XPath 表达式: //div[@id="container"]/p[position()=2 or position()=3]

解析:

  • //div[@id="container"]/p: 首先定位到 div#container 的直接子节点 <p>。
  • ...\]: 谓语,对这组 \ 节点进行过滤。

  • position(): 一个函数,返回节点在其兄弟节点中的位置(从 1 开始)。
  • =: 比较运算符。
  • or: 逻辑运算符,表示 "或"。

结果: 选取到 "这是第二段介绍..." 和 "这是第三段介绍..." 这两个 <p> 节点。

更简洁的写法: //div[@id="container"]/p[position()>=2 and position()<=3],这里使用了 >=, <= 和 and。

任务三:复杂关系定位 - 使用 "轴" 和 "节点关系"

目标1: 找到 <li class="highlight"> 节点的前一个兄弟节点。

XPath 表达式: //li[@class="highlight"]/preceding-sibling::li[1]

解析:

  • //li[@class="highlight"]: 首先,定位到我们的 "基准节点"。
  • /preceding-sibling::: 这是一个轴 (Axis)。
  • preceding-sibling 轴定义了所有在基准节点之前、且与基准节点拥有同一个父节点的节点。
  • ::: 轴分隔符,用于连接轴名称和节点测试。
  • li: 节点测试。在 preceding-sibling 轴找到的所有节点中,我们只想要 <li> 节点。
  • 1\]: 这是一个简化的谓语,表示取第一个符合条件的节点。

目标2: 找到 <a> 标签(链接)的父节点的父节点(即 div#container)。

XPath 表达式: //a/ancestor::div[@id="container"]

解析:

  • //a: 找到所有 <a> 标签。
  • /ancestor::: 这是一个轴,表示查找基准节点的所有祖先节点(父、祖父、曾祖父等)。
  • div[@id="container"]: 在所有祖先节点中,我们只想要 id 为 container 的 <div> 节点。

结果: 选取到 <div id="container">。

对比: //a/parent::*/parent::div 也能达到同样效果,但 ancestor 轴更直接、更优雅。

任务四:动态内容提取 - 使用 "计算" 和 "模糊匹配"

目标1: 假设有一个网页,其列表项的 id 是动态生成的,如 item-1, item-2, item-3...,我们想找到 id 以 item- 开头的所有 <li>。

XPath 表达式: //li[starts-with(@id, "item-")]

解析:

  • starts-with(): 这是一个字符串函数,用于模糊匹配。
  • starts-with(@id, "item-"): 条件为 "id 属性的值是否以 item- 开头"。

结果: 所有 id 如 item-1, item-2 等的 <li> 都会被选中。
目标2: 找到 div#container 中,文本内容包含 "示例" 二字的 <a> 标签。

XPath 表达式: //div[@id="container"]//a[contains(text(), "示例")]

解析:

  • contains(): 另一个常用的字符串函数,表示 "包含"。
  • contains(text(), "示例"): 条件为 "节点的文本内容是否包含'示例'这个子字符串"。

结果: 选取到 <a href="https://www.example.com" ...>访问示例网站</a>。

案例实战

还是以登录百度为例,使用本节课讲解的内容,定位到"登录"按钮并点击打开登录对话框,然后输出用户名和密码, 代码改造如下:

python 复制代码
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.by import By

def test_baidu():
    # 初始化浏览器驱动(chrome浏览器)
    driver = webdriver.Chrome()
    # 打开百度
    driver.get("https://www.baidu.com/")
    # 定位到登录按钮,并点击
    driver.find_element(By.XPATH,"//a[@id='s-top-loginbtn']").click()
    sleep(3)
    # 定位到手机号码输入框,并输入
    driver.find_element(By.XPATH,"//input[@name='userName']").send_keys("15111111111")
    # 找到密码输入框,并输入密码
    driver.find_element(By.XPATH,"//input[@placeholder='密码']").send_keys("79&abe$")
    # 等待3秒
    sleep(3)
    # 关闭浏览器
    driver.quit()

if __name__ == "__main__":
    test_baidu()

小结

XPath 是自动化测试的 "全能定位工具",尤其是高级定位方式,完美弥补了 CSS Selector 的不足!核心要掌握 "文本匹配" 和 "层级遍历",再配合属性模糊匹配,无论是动态元素、复杂嵌套,还是无属性元素,都能轻松搞定~ 建议大家把 XPath 和 CSS Selector 结合使用:简单场景用 CSS(高效简洁),复杂场景用 XPath(灵活全能)。

到这里,复杂定位的两大神器就全部讲解完毕啦!从基础定位到 CSS、XPath,咱们已经掌握了自动化测试元素定位的核心技能~ 接下来可以结合实际项目练手,比如搭建一个简单的测试脚本,用不同的定位方式定位页面元素,对比它们的优劣。如果在练习中遇到具体问题,或者想了解定位工具(如 Chrome 开发者工具)的使用技巧,欢迎随时告诉我哦!

相关推荐
L.Ru2 小时前
SIP抓包工具-sngrep的使用
测试工具·信息与通信·sngrep
卓码软件测评13 小时前
第三方软件测评机构:【Gatling与JMeter的架构对比:异步与非阻塞I/O模型如何实现更高并发】
测试工具·jmeter·架构·测试用例·负载均衡·压力测试
美团程序员13 小时前
一篇文章教你搞定:”xx 功能如何测试?“常见面试题型!
测试工具·面试·职场和发展·测试用例
软件测试雪儿18 小时前
高频Postman软件测试面试题
测试工具·lua·postman
2501_9151063219 小时前
iOS App 测试工具全景分析,构建从开发调试到线上监控的多阶段工具链体系
android·测试工具·ios·小程序·uni-app·iphone·webview
小白学大数据21 小时前
构建混合爬虫:何时使用Requests,何时切换至Selenium处理请求头?
爬虫·python·selenium·测试工具
Hacker_Fuchen1 天前
POST请求提交数据的三种方式及通过Postman实现
自动化测试·软件测试·测试工具·postman
安然无虞1 天前
JMeter性能测试工具·下
开发语言·测试工具·jmeter
Wpa.wk1 天前
自动化测试环境配置-java+python
java·开发语言·python·测试工具·自动化