Python + Selenium —— 网页元素定位之Xpath定位!

前面讲的定位方式,都能够很方便的定位到网页元素。但是这些属性并非所有的网页元素都具备,可以这么说,绝大部分情况下都很难保证元素具备这些属性。

也就是很多时候需要使用其他的方式来定位,在 WebDriver 中提供了 Xpath 和 Css 选择器两种语言来辅助定位。这两种语言都很强大,能够定位网页上的任意元素。

在网络爬虫中,也通常会用借助 lxml 库使用 Xpath 进行网页的解析。

目录

    • 基本定位语法

    • 元素属性定位

    • 层级属性结合定位

    • 使用谓语定位

    • 使用逻辑运算符

    • 使用文本定位

    • 使用部分匹配函数

    • 什么是 Xpath?

    • 绝对路径:

    • 相对路径

    • 验证 Xpath

什么是 Xpath?

Xpath 是一种用在 XML 文档中定位元素的语言,同样也支持 HTML 元素的解析。我们以百度中的HTML 代码为例。

<form id="form" name="f" action="/s" class="fm">
…
  <span class="bg s_ipt_wr quickdelete-wrap">
    <span class="soutu-btn"></span>
      <input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">
    </span>
  <span class="bg s_btn_wr">
    <input type="submit" id="su" value="百度一下" class="bg s_btn">
  </span>
…
</form>

所谓 Xpath,是指 XML path language。path 就是路径,那么 Xpath 主要是通过路径来查找元素。

我们通过下面一张小图来了解一下 HTML 中的结构:

HTML 的结构就是树形结构,HTML 是根节点,所有的其他元素节点都是从根节点发出的。其他的元素都是这棵树上的节点Node,每个节点还可能有属性和文本。

节点之间存在各种关系:

  • 父节点(Parent):HTML 是 body 和 head 节点的父节点;

  • 子节点(Child):head 和 body 是 HTML 的子节点;

  • 兄弟节点(Sibling):拥有相同的父节点,head 和 body 就是兄弟节点。title 和 div 不是兄弟,因为他们不是同一个父节点。

  • 祖先节点(Ancestor):body 是 form 的祖先节点,爷爷辈及以上?;

  • 后代节点(Descendant):form 是 HTML 的后代节点,孙子辈及以下?。

Xpath 中的绝对路径从 HTML 根节点开始算,相对路径从任意节点开始。

通过开发者工具,我们可以拷贝到 Xpath 的绝对路径和相对路径代码:

但是由于拷贝出来的代码缺乏灵活性,也不全然准确。大部分情况下,都需要自己定义 Xpath 语句,因此 Xpath 语法还是有必要学习。

现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
qq群号:691998057【暗号:csdn999】

绝对路径:

Xpath 中最直观的定位策略就是绝对路径。

以百度中的输入框和按钮为例,通过拷贝出来的 full Xpath:

/html/body/div[2]/div/div/div/div/form/span/input

这就是一个绝对路径我们可以看出,绝对路径是从根节点/html开始往下,一层层的表示出来直到需要的节点为止。

这明显不是理智的选项,因此了解以下即可,不用往心里去。

相对路径

除了绝对路径,Xpath 中更常用的方式是相对路径定位方法,以“//”开头。

相对路径可以从任意节点开始,一般我们会选取一个可以唯一定位到的元素开始写,可以增加查找的准确性。

相对路径可以通过以下的方式来定位元素:

基本定位语法

定位语法主要依赖于以下特殊符号:

表达式说明举例
/从根节点开始选取/html/div/span
//从任意节点开始选取//input
.选取当前节点
..选取当前节点的父节点//input/… 会选取 input 的父节点
@选取属性,或者根据属性选取//input[@data] 选取具备 data 属性的 input 元素
//@data 选取所有 data 属性
*通配符,表示任意节点或任意属性

元素属性定位

属性定位是通过 @ 符号指定需要使用的属性。

  1. 根据元素是否具备某个属性查找元素

//*[@data-recordid]

选取包含data-recordid属性的所有节点。可以定位到以下元素:

<tr role="row" data-boundview="gridview-1029" data-recordid="B36BCA33" ></tr>
  1. 根据属性是否等于某值查找元素

//span[@role='img']

选取属性 role 的属性值为 img 的所有节点。可以定位到以下元素:

<span role="img" class="x-btn-icon-el" unselectable="on" style=""></span>

注意,属性值必须要加引号,单双引号都可以。

层级属性结合定位

遇到某些元素无法精确定位的时候,可以查找其父级及其祖先节点,找到有确定的祖先节点后通过层级依次向下定位。

以下面的结构为例:

<form action="search" id="form" method="post">
    <span class="bg">
        <span class="soutu">搜索</span>
    </span>
    <span class="soutu">
        <input type="text" name="key" id="su">
    </span>
</form>
  1. 根据层级向下找,从 form 找到绿色的 span:

//form[@id="form"]/span/span
  1. 查找某元素内部的所有元素,选取 form 元素内部的所有 span:

//form[@id="form"]//span

第二个双斜杠,表示选取内部所有的 span,不管层级关系

  1. 使用星号找不特定的元素

//*[@id="form"]//*[@type="text"]

选取 id 属性为 form 的任意属性内部,并且 type 属性为 text 的任意元素。这里会找到 input。

  1. 使用..从下往上找,根据 input 查找其父节点 span:

//input[@name="key"]/..

注意最后的两个点,找到 input 节点的上级节点,如果还要再往上再加 /..

  1. 找同级节点:
    比如我们想通过第一个 span 标签去 找 div 标签。树形结构中,兄弟节点之间的关系是通过父节点建立起来的。所以可以先找到父节点,再通过父节点找同级节点。

//span[@class="bg"]/../div

先通过/..找到 span 的父节点,再通过父节点找到 div。

使用谓语定位

谓语是 Xpath 中用于描述元素位置。主要有数字下标、最后一个子元素last()、元素下标函数position()

  1. 使用下标的方式,从 form 找到 input :

//form[@id="form"]/span[2]/input

Xpath 中的下标从 1 开始。

  1. 查找最后一个子元素,选取 form 下的最后一个 span:

//form[@id="form"]/span[last()]
  1. 查找倒数第几个子元素,选取 form 下的倒数第一个 span:

//form[@id="form"]/span[last()-1]
  1. 使用 position() 函数,选取 from 下第二个 span:

//form[@id="form"]/span[position()=2]
  1. 使用 position() 函数,选取下标大于 2 的 span:

//form[@id="form"]/span[position()>2]

使用逻辑运算符

如果元素的某个属性无法精确定位到这个元素,我们还可以用逻辑运算符 and 连接多个属性进行定位,以百度输入框为例。

  1. 使用 and :

//*[@name='wd' and @class='s_ipt']

查找 name 属性为 wd 并且 class 属性为 s_ipt 的任意元素

  1. 使用 or

//*[@name='wd' or @class='s_ipt']

查找 name 属性为 wd 或者 class 属性为 s_ipt 的任意元素,取其中之一满足即可。

  1. 使用|,同时查找多个路径,取或:

//form[@id="form"]//span | //form[@id="form"]//input

选取 form 下所有的 span 和所有的 input。

使用文本定位

使用文本定位,是 Xpath 中的一大特色。在自动化测试中,为了让代码的可读性更高,可以使用文本的方式。
以下一个案例:


部分网页结构如下:

<tr>
  <td valign="top">
    <input type="radio" name="payment" value="1" checked="" iscod="0">
  </td>
  <td valign="top">
    <strong>支付宝</strong>
  </td>
</tr>

其实我们需要点的是前的单选框,但是单选框没有任何特殊的标识,不够灵活。我们可以通过后面的名称,如(支付宝、余额支付等)来找到其对应行的 radio,再去点击。

我们就需要先通过文本定位到“支付宝”,再去找其同一行(tr)的 input 节点。如果理不清楚,我们可以先画一个结构图:

红色箭头表示查找路径,先定位到“支付宝”所在的 strong,再定位 td -> tr -> td - >input 。那么要定位“支付宝”文本,就需要用到 Xpath 中的函数 text() 或 string(),注意是函数,所以括号不能少。

text():当前元素节点包含的文本内容;
表达式//div[text()="文本"],能找到:

<div>文本</div>
  • 1

不能找到:

<div><span>文本</span></div>
  • 1

string():当前元素节点内部所有节点元素的文本内容。表达式//div[string()="文本"]上述两种情况都能找到。

好,接着写上面的内容。先通过 //strong[text()="支付宝"]定位到“支付宝”所在的元素 strong,再找上级 td -> tr,再向下找:

//strong[text()="支付宝"]/../../td[1]/input

也可以写为:

//td[string()="支付宝"]/../td[1]/input

使用部分匹配函数

Xpath 中有提供了几个函数,用来进行部分匹配。

函数说明举例
contains选取属性或者文本包含某些字符//div[contains(@id, ‘data’)] 选取 id 属性包含 data 的 div 元素
//div[contains(string(), ‘支付宝’)] 选取内部文本包含“支付宝”的 div 元素
starts-with选取属性或者文本以某些字符开头//div[starts-with(@id, ‘data’)] 选取 id 属性以 data 开头的 div 元素
//div[starts-with(string(), ‘银联’)] 选取内部文本以“银联”开头的 div 元素
ends-with选取属性或者文本以某些字符开头//div[ends-with(@id, ‘require’)] 选取 id 属性以 require 结尾的 div 元素
//div[ends-with(string(), ‘支付’)] 选取内部文本以“支付”结尾的 div 元素

验证 Xpath

验证 xpath 有两种方法:

  1. 在开发者工具的 Elements 中按Ctrl + F,在搜索框中输入 Xpath:

  1. 在开发者工具的 Console 中使用 $x()

下面是配套资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!

最后: 可以在公众号:程序员小濠 ! 免费领取一份216页软件测试工程师面试宝典文档资料。以及相对应的视频学习教程免费分享!,其中包括了有基础知识、Linux必备、Shell、互联网程序原理、Mysql数据库、抓包工具专题、接口测试工具、测试进阶-Python编程、Web自动化测试、APP自动化测试、接口自动化测试、测试高级持续集成、测试架构开发测试框架、性能测试、安全测试等。

如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一键三连哦!

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

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

相关文章

【Linux】进程间通信——system V 共享内存、消息队列、信号量

需要云服务器等云产品来学习Linux的同学可以移步/–>腾讯云<–/官网&#xff0c;轻量型云服务器低至112元/年&#xff0c;优惠多多。&#xff08;联系我有折扣哦&#xff09; 文章目录 写在前面1. 共享内存1.1 共享内存的概念1.2 共享内存的原理1.3 共享内存的使用1.3.1 …

Linux/Traceback

Enumeration nmap 使用nmap初步扫描发现只开放了22和80端口&#xff0c;端口详细扫描情况如下 先看看web是什么样子的&#xff0c;打开网站发现有一条留言&#xff0c;显示该站点已经被黑了&#xff0c; 并且留下了后门 查看源代码&#xff0c;可以看到下面的注释 <!--So…

(C语言)编译和链接

前言͟͟͞͞&#x1f48c;&#xff1a;对于现在的各种编译器而言许多都是好多个功能的集成&#xff0c;那么我们的代码到底是如何去实现的呢&#xff1f;难道我们的计算机可以直接读懂我们所写的代码&#xff0c;并运行吗&#xff1f;对于很多细心的小伙伴们可能会想这样的问题…

Arduino开发实例-INA219 电流传感器驱动

INA219 电流传感器驱动 文章目录 INA219 电流传感器驱动1、INA219 电流传感器介绍2、硬件准备及接线3、代码实现1、INA219 电流传感器介绍 INA219 模块用于同时测量电流和电压。 该模块使用 I2C 通信传输电压和电流数据。 其他特性: 测量精度:1%最大测量电压:26V最大测量电…

解决小程序字体在最左上角问题

问题如下 原因&#xff1a; 出现这种现象的原因是项目默认开启了Skyline渲染模式&#xff0c;因为Skyline渲染模式不支持原生导航栏&#xff0c;所以在json文件中设置的导航栏失效&#xff0c;文字就会向上移动&#xff0c;如果想要使用原生的导航栏&#xff0c;可以将app.jso…

C#,入门教程(20)——列表(List)的基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(19)——循环语句&#xff08;for&#xff0c;while&#xff0c;foreach&#xff09;的基础知识https://blog.csdn.net/beijinghorn/article/details/124060844 List顾名思义就是数据列表&#xff0c;区别于数据数组&#xff08;arr…

centos7安装Redis7.2.4

文章目录 下载Redis解压Redis安装gcc依赖&#xff08;Redis是C语言编写的&#xff0c;编译需要&#xff09;编译安装src目录下二进制文件安装到/usr/local/bin修改redis.conf文件启动redis服务外部连接测试 参考&#xff1a; 在centos中安装redis-5.0.7 Memory overcommit must…

基于JavaWeb+SSM+Vue停车场微信小程序系统的设计和实现

基于JavaWebSSMVue停车场微信小程序系统的设计和实现 滑到文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 滑到文末获取源码 Lun文目录 目录 1系统概述 1 1.1 研究背景 1 1.2研究目的 1 1.3系统设计思想 1 2相关…

Linux命令手册

简介 Multics&#xff08;大而全&#xff09;项目失败&#xff0c;吸取教训启动Unix&#xff08;小而精&#xff09;&#xff0c;Linus Benedict Torvalds受Unix启发开发初始版本Linux内核&#xff0c;Git也由其开发&#xff0c;目的是为了更好的管理Linux内核开发。Unix是商业…

有线桥接|Wifi隔了一堵墙就没信号?房间的网线口利用起来,让房间死角也有网!

前言 本篇文章是路由器有线桥接主路由&#xff0c;起到AP&#xff08;热点&#xff09;的效果 上次发布的无线桥接&#xff0c;使用的前提是需要把旧路由放置在主路由的信号范围内&#xff0c;这极大限制了桥接路由器的放置位置。 如果隔了一堵墙基本上就无法连接Wifi&#x…

供应链安全项目in-toto开源框架详解

引言&#xff1a;in-toto 是一个开源框架&#xff0c;能够以密码学的方式验证构件生产路径上的每个组件和步骤。它可与主流的构建工具、部署工具进行集成。in-toto已经被CNCF技术监督委员会 (Technical Oversight Committee&#xff0c;TOC)接纳为CNCF孵化项目。 1. 背景 由于…

微信小程序之WXML 模板语法之数据绑定、事件绑定、wx:if和列表渲染

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

一键搭建你的知识库

效果 说明 由于安装包安装需要glibc>2.7 我就不尝试了 因为glib升级是一个繁琐的过程 没有升级的意义 只是为了体验知识库 没必要浪费时间 1.1docker compose部署trilium 1.1.创建目录 mkdir -p /opt/triliumcd /opt/trilium 1.2.编写docker-comppose.yml文件 vim dock…

使用STM32的GPIO口实现LED闪烁

✅作者简介&#xff1a;热爱科研的嵌入式开发者&#xff0c;修心和技术同步精进 代码获取、问题探讨及文章转载可私信。 ☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。 &#x1f34e;获取更多嵌入式资料可点击链接进群领取&#xff0c;谢谢支持&#xff01;&#x1f447…

JavaWeb-Cookie与Session

一、概念 是否还记得我们在HTTP概念中提到&#xff1a;HTTP的一大特点是无状态&#xff0c;这意味着多次HTTP请求之间是无法共享数据的。而在请求之间共享一些数据又是我们期望达到的效果。&#xff08;例如登录的记住我功能&#xff09;于是便有了会话跟踪技术&#xff0c;而…

Qt拖拽组件与键盘事件

1.相关说明 1.设置widget或view的拖拽和放置模式函数setDragDropMode参数说明&#xff0c;NoDragDrop(无拖拽和放置)、DragOnly(只允许拖拽)、DropOnly(只允许放置)、DragDrop(允许拖拽和放置)、InternalMove(只移动不复制) 2.设置widget或view的放置动作函数setDefaultDropAct…

python 实现大语言模型中的概率论:两人轮流出手对决时取胜概率的推导

假设你跟朋友通过打赌投篮来打赌一万块。你们找到一个篮球框&#xff0c;然后约定轮流投篮&#xff0c;谁先投进谁赢。假设你投进的概率是 p&#xff0c;也就是投不进的概率是 1-p&#xff0c;你对手投进的概率是 q,投不进的概率是 1-q&#xff0c;如果由你先投&#xff0c;那么…

反序列化提升刷题(2)

今天的例题&#xff1a; <?phphighlight_file(__FILE__);class ctfshowvip{public $username;public $password;public $code;public function __construct($u,$p){$this->username$u;$this->password$p;}public function __wakeup(){if($this->username! || $thi…

解决 vue 项目开发越久 node_modules包越大的问题

解决 vue 项目开发越久 node_modules包越大的问题 node_modules.cache 文件&#xff08;编译缓存文件 可以删除 &#xff09; compression-webpack-plugin 禁止缓存 const CompressionPlugin require("compression-webpack-plugin");module.exports {plugins: [ne…

面向对象之深度优先和广度优先

面向对象深度优先和广度优先是什么&#xff1f; 二叉树的两种遍历是数据结构的经典考察题目, 广度遍历考察队列结构, 深度遍历考察递归 深度优先 先序遍历(父, 左子, 右子) 0, 1, 3, 7, 8, 4, 9, 2, 5, 6 中序遍历(左子, 父, 右子) 7, 3, 8, 1, 9, 4, 0, 5, 2, 6 后序遍历(左子…