Selenium 自动化 —— 一篇文章彻底搞懂XPath

 更多关于Selenium的知识请访问“兰亭序咖啡”的专栏:专栏《Selenium 从入门到精通》


文章目录

前言

一、什么是xpath?

二、XPath 节点

三. 节点的关系

1. 父(Parent)

2. 子(Children)

3. 同胞(Sibling)

4. 先辈(Ancestor)

5. 后代(Descendant)

四. 路径表达式

五. 谓语(Predicates)

六. 轴(Axes)

七. XPath 示例

1. 绝对路径

2. 所有位置元素

3. 使用谓语

4. 通过@根据属性筛选

5. 通过属性值筛选

6. 元素计数器

7. 根据标签名筛选

8. 函数—包含 contains

9. 函数—字符串长度

10. 逻辑或

11. 轴

12. 根据符合条件的子节点选父节点

八. Selenium 中使用XPath

总结


前言

如何定位一个XML(尤其是HTML)中的一个节点?前文我们学习了Selenium的常用的几种选择器,相比其它几种比较简单的比如id选择器、name选择器等外,最强大也是我们使用最频繁的是xpath选择器

本文,我们就对xpath进行全面的学习。


一、什么是xpath?

XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。(简单说就是在一个庞大复杂的XML中找到一个特定节点

而我们的 HTML 就是一种特殊的XML。所以 XPath 当然也可以用来对 HTML 元素和属性进行遍历。

XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。

/html/body/div[1]/div[2]/div[1]/input

这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。

/usr/local/apache/log/

二、XPath 节点

在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及根节点。 

下面我们对每种节点介绍。

XPath 是对 XML 的操作,但是我们用得比较多的是 HTML,所以下面的代码都会以 HTML 来演示。

<html xmlns:example="http://www.example.com">
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
 
<!-- 测试 HTML -->
<h1 name="header">我的第一个标题</h1>
 
<p>我的第一个段落。</p>
 
</body>
</html>

对于上面的代码:

  1. <html> 就是根节点
  2. 每个标签都是一个元素,比如:<h1>我的第一个标题</h1>
  3.  <h1 name="header">中的name=“header”就是一个属性
  4. <p>我的第一个段落。</p> 中的“我的第一个段落。”就是文本
  5. <html xmlns:example="http://www.example.com">中的namespace就是命名空间
  6. <!-- 测试 HTML -->就是一个注释
  7. 处理指令一般不怎么常用,如果在Vue中<div v-if="show">会比较常见。

特别注意:节点和元素的区别:

  • 节点是很广泛的概念,包括了元素、属性、文本、命名空间、处理指令、注释以及根节点
  • 元素只是节点的一种,属性也是一种节点,元素通常是html标签对!
  • 后面会介绍 * 表示所有元素,而node()表示任意节点。

三. 节点的关系

人和人之间有关系,比如父子,兄弟等,节点同样有这些关系

这些关系可以帮我们定位一个节点。

1. 父(Parent)

每个元素都只有一个父节点。

  • coffe的父节点是list
  • list的父节点是drink

但是注意:coffe只有一个父节点,drink不是coffe的父节点。

<div class="food">
	<div class="drink">
		<ol class="list">
			<li item="coffe">Coffee</li>
			<li item="tea">Tea</li>
			<li item="milk">Milk</li>
		</ol>
	</div>
</div>

2. 子(Children)

每个节点都有零个、一个或多个子节点。

  • food的子节点是drink
  • list的子节点有3个,分别是coffe、tea和milk
  • coffe没有子节点

特别注意:coffe不是food和drink的子节点。

<div class="food">
	<div class="drink">
		<ol class="list">
			<li item="coffe">Coffee</li>
			<li item="tea">Tea</li>
			<li item="milk">Milk</li>
		</ol>
	</div>
</div>

3. 同胞(Sibling)

拥有相同父节点的节点。

  • coffe、tea、milk他们的父节点都是list,所以他们是同胞节点。
  • drink只有list一个子节点,所以list没有同胞节点。
<div class="food">
	<div class="drink">
		<ol class="list">
			<li item="coffe">Coffee</li>
			<li item="tea">Tea</li>
			<li item="milk">Milk</li>
		</ol>
	</div>
</div>

4. 先辈(Ancestor)

某节点的父、父的父……

  • coffe的先辈节点有list、drink和food
<div class="food">
	<div class="drink">
		<ol class="list">
			<li item="coffe">Coffee</li>
			<li item="tea">Tea</li>
			<li item="milk">Milk</li>
		</ol>
	</div>
</div>

5. 后代(Descendant)

某个节点的子,子的子,等等。

  • food的后代节点有drink、list,还有coffe、tea、milk
<div class="food">
	<div class="drink">
		<ol class="list">
			<li item="coffe">Coffee</li>
			<li item="tea">Tea</li>
			<li item="milk">Milk</li>
		</ol>
	</div>
</div>

四. 路径表达式

XPath 使用路径表达式在 XML 文档中选取节点

最常用的路径表达式
路径表达式作用示例
nodename选取此节点的所有子节点。

input:选择所有<input>节点的所有子节点。

/

从根节点选取。

也就是绝对路径。

/html:选择根节点,网页的根节点都是<html>节点。

//

从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。

也就是相对路径。

//input:选中所有<input>节点。
.选取当前节点。
..选取当前节点的父节点。
@选取属性。//@id:选中所有有id属性的节点。        
*匹配任何元素

//*:任意元素的节点

//@*:属性为任意值的节点,换句话说就是有属性的节点,比如<html>和<body>这种节点不会被选中。

node()

匹配任何类型的节点

(特别区别*,元素是特殊的节点,属性也是节点)

//node():选中任意节点
|使用“|”运算符,可以选取若干个路径。也就是或//input | //ul:选中所有的<input>或者<ul>节点

是不是和 Linux 的路径语法很类似!区别在于一个是选择目录,一个是选择节点

//div/span 和 //div//span 有什么区别?(非常重要)

  • //div/span:选择div元素的子节点中的span
  • //div//span:选择div元素的后代节点中的span

比如对于下面的html,使用“//div/span”只能选中一个span,但是使用"//div//span"可以选中两个span!

<div>
  <span>Hello<span>
  <ul>
     <span>World</span>
  </ul>
<div>

节点和元素的区别?(特别重要)

以 * 和 node()为例:

  • //*:选中了5个元素:(5) [html, head, title, body, div.box]
  • //node():选中了8个节点:(8) [<!DOCTYPE html>, html, head, title, text, body, div.box, text]
<!DOCTYPE html>
<html>
	<head>
		<title>预定</title>
	</head>
	<body>
		<div class="box">Hello</div>
	</body>
</html>

五. 谓语(Predicates)

谓语用来查找某个特定的节点或者包含某个指定的值的节点。谓语被嵌在方括号中。

是不是不太好理解。

其实,我们学习中文或者英文语法的时候,也接触过 主+谓+宾语 的结构,这和XPath的谓语很类似。

谓语(Predicate) 是对主语动作状态或特征的陈述或说明,指出"做什么(what to do)" , "是什么(what is this)"。

谓语动词的位置一般在主语之后, 经常用动词和形容词搭配来充当谓语动词。

比如:

  • 选择div的第二个子节点
  • 选择有id属性的div节点
  • 数值大于35的节点
  • ……

有了这些谓词,我们可以更精确的定位到特定的节点

六. 轴(Axes)

前面介绍了节点之间的关系,比如父子关系、兄弟关系等。

Xpath 使用轴 定义了节点与当前节点之间的关系,相当于节点的运动路径。每一个轴都有一个基本节点类型。

 在 XPath 中,我们使用轴(如 child、parent、attribute 等)来定位节点

用关系来定位节点!

轴名称结果
ancestor选取当前节点的所有先辈(父、祖父等)。
ancestor-or-self选取当前节点的所有先辈(父、祖父等)以及当前节点本身。
attribute选取当前节点的所有属性。
child选取当前节点的所有子元素。
descendant选取当前节点的所有后代元素(子、孙等)。
descendant-or-self选取当前节点的所有后代元素(子、孙等)以及当前节点本身。
following选取文档中当前节点的结束标签之后的所有节点。
namespace选取当前节点的所有命名空间节点。
parent选取当前节点的父节点。
preceding选取文档中当前节点的开始标签之前的所有节点。
preceding-sibling选取当前节点之前的所有同级节点。
self选取当前节点。

语法规则:

轴名称::节点测试[谓语]

下面列举一些实例来说明!!!

例子结果
//div//child::input

选取所有属于div节点的子元素的 input 节点。

不过直接用简单的写法就行了://div//input

//input//attribute::id

选取所有input节点的 id 属性。(属性也是一种节点!

比如<input id="username" name="uname"> 

//ul//child::*

选取当前节点的所有子元素。(因为使用了//相对路径, 所以是所有后代节点

如果 //ul/child::*  因为是 / 绝度路径, 所以选中所有子节点

//input//attribute::*

选取input节点的所有属性。

<input id="username" name="uname" class="big">

//a//child::text()

选取a节点的所有文本子节点。

简单写法://a/text()

比如:<a>测试</a>  <a>Hello</a>

//a//child::node()

选取a节点的所有子节点。(注意是节点,所以也包括元素,而且使用的//相对,所以所有后代的节点)

//ul//descendant::input选取ul节点的所有 input 后代节点。
//input//ancestor::li选择input节点的所有 li 先辈节点。
ancestor-or-self::book选取当前节点的所有 book 先辈以及当前节点(如果此节点是 book 节点)
//ul/child::*/child::input

选取ul节点的所有 input 孙节点

相当于://ul/*/inut

所有的child::XXX 都可以直接写XXX

比如://a//child::text()   --> //a//text()

           //div//child::input --> //div//input

七. XPath 示例

1. 绝对路径

/html/body/div[2]/top-menu/header/div/div[1]/h1/a/img

2. 所有位置元素

//div //任意div节点
//div//img /*div的所有img后代*/

3. 使用谓语

//ul//li[1] /*选择第一个*/
//ul//li[position() = 1] /*多种写法*/

//ul//li[last()] /*选择最后一个*/

4. 通过@根据属性筛选

//@jscontent	/*所有带jscontent属性的节点*/
//span[@jscontent] /*所有带jscontent属性的span节点*/

//span[@*] /*所有带任意属性的span节点*/

//div[not(@*)] /*没有任何属性的div节点*/
//div[not(@id)] /*没有id属性的div节点*/

5. 通过属性值筛选

//span[@class='currency']
//span[normalize-space(@class)='currency']  /*去掉前后空格后再比较*/

6. 元素计数器

//ul[count(li)=5] /*有5个li的ul*/

//*[count(*)=3] /*有3个子元素的任意节点*/

7. 根据标签名筛选

//*[name()='span']	/*等同于//span*
//span

//*[starts-with(name(), 'scri')]  /*标签名以scri开头的标签*/
//*[contains(name(), 'pt')] /*标签名包含pt的标签*/

8. 函数—包含 contains

//div[contains(@class, 'rowFlightItem')]

如果使用全匹配是获取不到的//div[@class, 'tripselector_inbound'] 除非//div[@class, 'tripselector_inbound ng-star-inserted']

但是要特别注意,模糊匹配可能会匹配到不期望的对象

//flight//div[contains(@class, 'row')]

9. 函数—字符串长度

//*[string-length(name()) = 3] /*标签名字为3个字符串的节点,比如div,img*/

10. 逻辑或

//ul | //button /*ul标签或button*/

11. 轴

//div//child::ul  /*选择子节点是ul的div*/

//div/ul /*简洁写法*/

注意child和descendant的区别,一个儿子,一个是后代。儿子也是后代

后代节点轴

//div//descendant::*  /*选择div下面的所有元素*/

//div//*

后面的兄弟节点

//ul//li/following-sibling::*  /*ul下第一个后面的子节点!*/

12. 根据符合条件的子节点选父节点

//table[.//th[@scope="colgroup" and normalize-space(.)="成人"]]
.//tr[contains(@class, 'taxesOrFees-tr') and (.//td)]  /*子节点有td的tr*/
<table class="table">
      <caption class="">Departure flight - adult prices resume table</caption>
      <tbody>
        <tr class="colgroup_title">
          <th colspan="2" scope="colgroup">成人</th>
        </tr>

八. Selenium 中使用XPath

使用非常简单,就是By.xpath()方法即可:

WebElement element = driver.findElement(By.xpath("//input[@id='username']"));


总结

以上就是今天要讲的内容,本文系统全面的介绍了Xpath,从什么是Xpath讲起,到Xpath的基本概念,最后到语法和实战!相信这会让你在使用 Selenium 时如虎添翼!关注兰亭序咖啡的博客,我们一起对 Selenium 学习和探讨!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/619279.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[Algorithm][回溯][全排列][子集] + 回溯原理 详细讲解

目录 0.原理讲解1.全排列1.题目链接2.算法原理详解3.代码实现 2.子集1.题目链接2.算法原理详解3.代码实现 0.原理讲解 回溯算法通常⽤于解决组合问题、排列问题和搜索问题等回溯算法的基本思想&#xff1a; 从⼀个初始状态开始&#xff0c;按照⼀定的规则向前搜索&#xff0c;…

怎么下载抖音直播视频 怎么解析直播间链接的视频录制保存

尊敬的读者们&#xff0c;你们好&#xff01;今天我们将探讨一个非常实用的技巧——如何下载直播视频。随着网络技术的发展&#xff0c;直播视频已经成为我们日常生活中不可或缺的一部分。无论是观看比赛、欣赏音乐会还是探索新的美食&#xff0c;直播视频都为我们提供了更直观…

【qt】最快的开发界面效率——混合编程

混合编程 一.准备工作1.创建项目2.添加项目资源 二.ui界面设计1.menuBar菜单栏2.action ▲3.toolBar工具栏4.中心组件 三.代码界面设计1.toolBar添加组件2.statusBar状态栏添加组件 四.完成界面的功能1.对action配置信号槽2.对action转到信号槽3.代码添加的组件手动关联槽函数 …

YOLOv8+CLIP实现图文特征匹配

本文通过结合YOLOv8s的高效物体检测能力与CLIP的先进图像-文本匹配技术&#xff0c;展示了深度学习在处理和分析复杂多模态数据中的潜力。这种技术的应用不仅限于学术研究&#xff0c;还能广泛应用于工业、商业和日常技术产品中&#xff0c;以实现更智能的人机交互和信息处理。…

第四届微调——炼丹

学习地址&#xff1a;Tutorial/xtuner/README.md at main InternLM/Tutorial GitHub 笔记 微调是一种在已有的预训练模型基础上&#xff0c;通过使用新的数据对模型进行进一步优化和调整的技术手段。它的目的是使模型能够更好地适应特定的应用场景和任务需求&#xff0c;进一…

IDEA切换分支

方法一 1、选择要切换分支的module 2、右键&#xff0c;选择git 3、再点击branches 4、可以看到当前module的本地分支&#xff08;local Branches&#xff09;及远程分支&#xff08;Remote Branches&#xff09;列表。点击你要切换到的分支,Checkout即可。 方法二 1、点击…

MFC编程之设计美丽的对话框

目录 写在前面&#xff1a; Part 1&#xff1a;美美的设计一下计算器的布局 1.描述文字&#xff1a; ​编辑 2.ID&#xff1a; Part 2&#xff1a;美美熟悉一下计算器的工作流程 Part 3&#xff1a;美美设计一下控件功能 1.edit control&#xff1a; 2.相关变量初始化&…

Copilot for Microsoft 365 扩充新增 16 种语言

最近&#xff0c;微软公司发布公告&#xff0c;进一步扩大 Copilot for Microsoft 365 语言支持&#xff0c;新增 16 种&#xff0c;支持的语言总数达到 25 种。 新支持的语言如下&#xff1a; 阿拉伯语 捷克语 丹麦语 荷兰语 芬兰语 希伯来语 匈牙利语 韩语 挪威语&am…

Java面试之分布式篇

分布式锁的实现方案 &#xff08;1&#xff09;用数据库实现分布式锁比较简单&#xff0c;就是创建一张锁表&#xff0c;数据库对字段作唯一性约束。加锁的时候&#xff0c;在锁表中增加一条记录即可&#xff1b;释放锁的时候删除锁记录就行。如果有并发请求同时提交到数据库&…

二分判定+选插冒排序+归并快速堆希尔+计数排序

二分力扣题 一&#xff1a;搜索二维矩阵 74. 搜索二维矩阵 按照题意&#xff1a;直接利用二维数组转换成一维数组进行求解 方法一&#xff1a;普通等于的二分查找 class Solution { public:bool searchMatrix(vector<vector<int>>& matrix, int target) {t…

Shell编程之循环语甸与函数

for 遍历循环 1&#xff09;for 变量 in 取值列表 for i in $(seq 1 10) do 命令序列 .... done 2&#xff09;for ((变量初始值; 变量范围; 变量的迭代方式)) for ((i1; i<10; i)) do 命令序列 .... done IFS for循环取值列表分隔符 set | grep IFS …

SSH常用功能介绍-高级功能

一、介绍 SSH&#xff08;Secure Shell&#xff09;是一种用于远程登录和执行命令的网络协议&#xff0c;它提供了加密的连接&#xff0c;保证了数据的安全性。除了基本的远程登录功能外&#xff0c;SSH还提供了许多高级功能&#xff0c;以下是一些常用的高级功能介绍&#xf…

Redis集群安装

将Redis安装包分别上传到3个文件夹&#xff0c;并解压缩 #编译并指定安装目录 cd /root/usr/local/redis-cluster/redis-7001/redis-6.2.6/ make make PREFIX/root/usr/local/redis-cluster/redis-7001 install # cd /root/usr/local/redis-cluster/redis-7002/redis-6.2.6/ m…

FreeRTOS二值信号量

目录 一、信号量的概念 1、信号量的基本概念 2、信号量的分类 二、二值信号量简介 三、二值信号量相关API 1、创建二值信号量 2、释放二值信号量 3、获取二值信号量 四、二值信号量实操 1、实验需求 2、CubeMX配置 3、代码实现 一、信号量的概念 1、信号量的基本概…

使用 CloudFlare 后如何才能不影响搜索引擎蜘蛛爬虫

今天,明月给大家再次详细讲解一下,明月在使用 CloudFlare 后如何才能不影响搜索引擎蜘蛛爬虫对站点的抓取,因为这是很多首次使用 CloudFlare 的站长们容易忽略和触犯的问题,并不是 CloudFlare 不友好,而是 CloudFlare 的防火墙(WAF)实在是太给力。其实在【CloudFlare 如…

IDEA及Maven配置代理及Maven中央仓库配置详解

一、配置代理 首先&#xff0c;需要本地开启代理入口&#xff0c;如图。 这个跟你使用代理软件有关。像我使用的是qv2ray。 其次&#xff0c;idea配置代理&#xff0c;如图。 1.1 idea配置代理 打开Settings&#xff0c;如图 1.2 maven配置代理 maven配置代理&#xff0c;修…

2024湖南理工学院程序设计竞赛(同步赛) G. 区间递减(思维题 分类讨论 ST表)

题目 https://ac.nowcoder.com/acm/contest/82672/G 思路来源 出题人 涼風青葉7代码 题解 注意到三种情况即可&#xff0c; 第一种情况&#xff0c;10 9 8 1 2&#xff0c;保留1 第二种情况&#xff0c;6 5 10 9 4 4&#xff0c;保留5 4 4 第三种情况&#xff0c;6 5 4&…

基于Springboot的校园疫情防控管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的校园疫情防控管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系…

Python 整数类型(int)详解:无限范围与多种进制

引言 在编程中&#xff0c;整数是最基本的数据类型之一。不同编程语言对整数的处理方式各不相同&#xff0c;这往往影响到程序的性能和开发者的选择。本文将深入探讨 Python 中的整数类型&#xff08;int&#xff09;&#xff0c;其独特的处理方式&#xff0c;以及它在日常编程…

【数据结构】环状链表OJ题

✨✨✨专栏&#xff1a;数据结构 &#x1f9d1;‍&#x1f393;个人主页&#xff1a;SWsunlight 一、OJ 环形链表&#xff1a; 快慢指针即可解决问题: 2情况&#xff1a; 快指针走到结尾&#xff08;不是环&#xff09;快指针和尾指针相遇&#xff08;是环的&#xff09; …