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

news2025/1/12 12:20:12

 更多关于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.coloradmin.cn/o/1669129.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LLM量化

Efficient Finetuning prefix tuning 针对每种任务&#xff0c;学习prefix vector 启发于prompting&#xff0c;调整上下文内容让模型去输出自己想要的内容 核心就是找到一个上下文去引导模型解决NLP生成任务 传统情况下&#xff0c;我们为了得到想要的结果&#xff0c;会…

1.9. 离散时间鞅-组合方法分析随机游动(不用鞅方法)

组合方法分析随机游动-不用鞅方法 组合方法分析随机游动(不用鞅方法)1. 反射原理 → \rightarrow →首击时分布2. 反正弦定律(末击时分布)组合方法分析随机游动(不用鞅方法) 本节将不使用鞅更深入地研究简单随机游动的属性,有益于过渡到马氏链的研究. 1. 反射原理

20240512,函数对象,常用算法:遍历,查找

函数对象 函数对象基本使用 重载 函数调用操作符 的类&#xff0c;其对象被称为函数对象&#xff1b;函数对象使用重载的&#xff08;&#xff09;时&#xff0c;行为类似函数调用&#xff0c;也叫仿函数 函数对象&#xff08;仿函数&#xff09;本质是一个类&#xff0c;不是…

【GlobalMapper精品教程】080:WGS84转UTM投影

参考阅读:ArcGIS实验教程——实验十:矢量数据投影变换 文章目录 一、加载实验数据二、设置输出坐标系三、数据导出一、加载实验数据 打开配套案例数据包中的data080.rar中的矢量数据,如下所示: 查看源坐标系:双击图层的,图层投影选项卡,数据的已有坐标系为WGS84地理坐标…

opencompass实践

参考教程 https://github.com/InternLM/Tutorial/blob/camp2/opencompass/readme.md 下载opencompass&#xff0c;配置必要的环境之后&#xff0c;解压下载的数据集 cp /share/temp/datasets/OpenCompassData-core-20231110.zip /root/opencompass/ unzip OpenCompassData-co…

Smurf 攻击是不是真的那么难以防护

Smurf攻击是一种网络攻击方式&#xff0c;属于分布式拒绝服务&#xff08;DDoS&#xff09;攻击的变种。以 1990 年代流行的名为 Smurf 的漏洞利用工具命名。该工具创建的 ICMP 数据包很小&#xff0c;但可以击落大目标。 它利用ICMP协议中的回声请求&#xff08;ping&#x…

第七次--大模型测评

在该章节中更多是体验与尝试 一、理论学习 类型&#xff1a;语言大模型和多模态大模型这两种是主要的类型。 挑战&#xff1a;要想办法建立一个全面的评价体系&#xff0c;还要能处理大规模的数据&#xff0c;并且要保证评测的准确性和可重复性&#xff0c;真不是一件容易的事…

Unity生命周期函数详解

Unity生命周期函数详解 Unity生命周期函数是Unity引擎中用于控制游戏对象行为的一系列方法。它们在游戏的不同阶段被自动调用&#xff0c;允许开发者在适当的时机执行特定的代码。了解和正确使用生命周期函数对于创建流畅和高效的游戏至关重要。 生命周期函数概述 Unity生命…

变量的解构赋值

变量的解构赋值 数组的解构赋值对象解构赋值 对象的解构与数组有一个重要的不同。嵌套结构的对象 字符串的解构赋值数值和布尔值的解构赋值函数参数的解构赋值 变量的解构赋值用途 交换变量的值从函数返回多个值函数参数的定义提取JSON数据设置默认值遍历Map和Set不完全解构输入…

TM1650 并联在I2C 信号线的处理方法

目的是可以并联多个TM1650 在标准I2C 总线上&#xff0c;并且不影响其他标准I2C 器件。思路就是拿个额外的开关控制每一片TM1650 的使能&#xff0c;就像SPI 的CS 信号那样。 协议 TM1650 的通信协议虽说不是标准I2C&#xff0c;但也算是比较兼容的&#xff0c;比方说&#x…

azkaban-tools 项目介绍

本文背景 应一个用户的好心和好奇心&#xff0c;在最近水深火热的百忙之中抽时间写完了一个简短的项目介绍&#xff0c;其实就是几个azkaban的批量操作脚本&#xff0c;但在大数据集群的“运维生涯”中&#xff0c;还是帮了自己不少忙&#xff0c;也算是为了它做一个简单的回顾…

SpringBoot集成jxls2实现复杂(多表格)excel导出

核心依赖 需求 导出多个表格&#xff0c;包含图片&#xff0c;类似商品标签 1.配置模板 创建一个xlsx的模板文件&#xff0c;配置如下 该模板进行遍历了两次&#xff0c;因为我想要导出的数据分为两列展示&#xff0c;左右布局&#xff0c;一个循环实现不了&#xff0c;所以采…

重学JavaScript高阶知识点(三)—— 详解Js中的内存管理

详解Js中的内存管理 1. 简介2. 内存生命周期3. JavaScript 的内存分配4. 垃圾回收 1. 简介 很多底层语言一般都有底层的内存管理接口&#xff0c;比如 C语言&#xff0c;可以调用对应的API去创建和释放内存空间。意思是需要手动去创建和释放内存空间&#xff0c;很明显&#x…

TCP服务器实现将客服端发送的信息广播发送(使用内核链表管理客户端信息)

目录 1.服务器端实现思路 2.服务器端代码 3.客户端代码 4.内核链表代码 5.运行格式 一、服务器端 二、客户端 6.效果 1.服务器端实现思路 Tcp广播服务初始化 等待客户端连接 广播发送 2.服务器端代码 #include "list.h" #include <signal.h> #def…

如何解决IntelliJ IDEA中pom.xml依赖项引发的安全漏洞黄线警告问题

背景 在开发过程中&#xff0c;当我们在pom.xml文件中添加依赖项时&#xff0c;经常会发现IntelliJ IDEA报出黄色警告线条&#xff0c;提示存在潜在的安全漏洞。警告的具体展现形式如下&#xff1a; 解决方案 首先&#xff0c;打开设置菜单界面&#xff0c;接着选择编辑器选…

神经网络复习--神经网络算法模型及BP算法

文章目录 神经网络模型的构成BP神经网络 神经网络模型的构成 三种表示方式&#xff1a; 神经网络的三要素&#xff1a; 具有突触或连接&#xff0c;用权重表示神经元的连接强度具有时空整合功能的输入信号累加器激励函数用于限制神经网络的输出 感知神经网络 BP神经网络 …

[嵌入式系统-75]:RT-Thread-快速上手:正点原子探索者 STM32F407示例

目录 正点原子探索者 STM32F407 上手指南 1. 简介 2. 准备工作 3. 运行第一个示例程序 3.1 编译下载 3.2 运行 继续学习 正点原子探索者 STM32F407 上手指南 1. 简介 探索者 STM32F407 是正点原子推出的一款基于 ARM Cortex-M4 内核的开发板&#xff0c;最高主频为 16…

机器人学导论实验2-差速驱动机器人的运动学与控制BJTU

目录 机器人导论实验-差速驱动机器人的运动学与控制 1 实验目的 2 任务一&#xff1a;前馈控制 2.1 内容分析 2.2 过程分析 2.3 结果分析 3 任务二&#xff1a;闭环控制 3.2 过程分析 3.3 结果分析 4 任务三&#xff1a;闭环控制&#xff08;改进&#xff09; 4.1 内容分…

Kotlin: ‘return‘ is not allowed here

报错&#xff1a;以下函数的内部函数return语句报错 Kotlin: return is not allowed here fun testReturn(summary: (String) -> String): String {var msg summary("summary收到参数")println("test内部调用参数&#xff1a;>结果是 &#xff1a;${msg…

(四十)第 6 章 树和二叉树(树的双亲表存储)

1. 背景说明 2. 示例代码 1) errorRecord.h // 记录错误宏定义头文件#ifndef ERROR_RECORD_H #define ERROR_RECORD_H#include <stdio.h> #include <string.h> #include <stdint.h>// 从文件路径中提取文件名 #define FILE_NAME(X) strrchr(X, \\) ? strrch…