元素定位之XPath定位-学习

一、XPath语法简介

XPath (XML Path Language) 是由国际标准化组织W3C指定的,用来在 XML 和 HTML 文档中选择节点的语言。

目前主流浏览器 (chrome、firefox,edge,safari) 都支持XPath语法,XPath有 1 和 2 两个版本,目前浏览器支持的是 XPath 1的语法。

为什么要学习 Xpath呢? 因为

  • 有些场景用css、id... 选择web元素 很麻烦,而XPath 却比较方便。
  • 另外 XPath 还有其他领域会使用到,比如 爬虫框架 Scrapy, 手机App框架 Appium。

真正在实际工作中,只有xpath和css的定位方式是可以用来做项目的。那我们应该选择哪个来运用到我们的项目呢?那我来告诉大家:习惯哪个就用哪个,或者把两者结合起来也行。CSS的语法比较简洁,运行速度稍快,但总体来讲,因为xpath的功能更多,更强大,而且xpath可以根据文字来定位,这个是比较强大的。

  • 分享XPath的原因:由于XPath在UI自动化中使用的频率较高,有必要学习。

练习代码:


<!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Xpath选择</title>
    </head>
    <style>
        /**{margin: 0; padding: 0;}*/
        body{width: 600px; height: 1000px; margin: 0 auto;}
        body{line-height: 30px;}
        h3{color: brown;}
        h4{color: rgb(22, 118, 173)}
        .select_city{color: brown; font-weight: bold;}
        select option{line-height: 30px;}
    </style>
    <body>
        <h3>select框</h3>
        <div>
        <h4>单选</h4>
        <p>姓名:</p>
        <select class="choose_1" >
            <option value="小江老师">小江老师</option>
            <option value="小雷老师">小雷老师</option>
            <option value="小凯老师" selected="selected">小凯老师</option>
        </select>            
        <h4>多选</h4>
        <p>课程:</p>
        
        <select  class="choose_2" multiple>
          <option value="小江老师">小江老师</option>
          <option value="小雷老师">小雷老师</option>
          <option value="小王老师">小王老师</option>
          <option value="小凯老师" selected="selected">小凯老师</option>
        </select> 
        
           <p class="select_city">城市选择</p>
           <div id="china">
               <p id="beijing" class='capital huge-city'>北京</p>
               <div><p>深圳</p></div>
               <p id="shanghai" class='huge-city'>上海</p>       
           </div>
           <div id="us">
               <span id="west" style="color:darkgreen">
                   <a id="newyork">纽约</a>
                   <a id="huston">休斯顿</a>
               </span>
               <span id="east" style="color:darkred">
                   <a id="chigaco">芝加哥</a>
               </span>
           </div>
        </div>
        <form action="" method="post">
              <h4>登录模块</h4>
              <p><span name='user'>账号</span><input type="text" name="user" id="user" value="1" placeholder="请输入账号" /></p>
              <p><span>密码</span><input type="password" name="pwd" id="" placeholder="请输入密码" /></p>
              <button><span>登录</span></button>
        </form>
      </body>
    </html>

在浏览器中 按F12打开调试窗口,点击 Elements(元素)标签。

要验证 XPath 语法是否能成功选择元素,按组合键 Ctrl + F ,就会出现 搜索框

XPath 语法中,整个HTML文档根节点用 “/” 表示,如果我们想选择的是根节点下面的html节点,则可以在搜索框输入

/html

如果输入下面的表达式

/html/body/div

这个表达式表示选择html下面的body下面的div元素。

 / 有点像 CSS中的 , 表示直接子节点关系。

1、绝对路径选择

从根节点开始的,到某个节点,每层都依次写下来,每层之间用 / 分隔的表达式,就是某元素的 绝对路径

上面的XPath表达式 /html/body/div ,就是一个绝对路径的XPath表达式, 等价于 css表达式 html>body>div

自动化程序要使用XPath来选择web元素,应该调用 WebDriver对象的方法 find_element_by_xpath 或者 find_elements_by_xpath,像这样:

elements = driver.find_elements(By.XPATH, "/html/body/div")

2、相对路径选择

有的时候,我们需要选择网页中某个元素, 不管它在什么位置 。

比如,选择示例页面的所有标签名为 div 的元素,如果使用css表达式,直接写一个 div 就行了。

那XPath怎么实现同样的功能呢? XPath需要前面加 // , 表示从当前节点往下寻找所有的后代元素,不管它在什么位置。

所以XPath表达式,应该这样写: //div

“//” 符号也可以继续加在后面,比如,要选择 所有的 div 元素里面的 所有的 p 元素 ,不管div 在什么位置,也不管p元素在div下面的什么位置,则可以这样写 //div//p

对应的自动化中元素定位如下

elements = driver.find_elements(By.XPATH, "//div//p")

如果使用CSS选择器,对应代码如下

elements = driver.find_elements(By.XPATH, "//div//p")

如果使用CSS选择器,对应代码如下

elements = driver.find_elements(By.CSS_SELECTOR,"div p") 
elements = driver.find_elements(By.CSS_SELECTOR,"div > p")

如果,要选择 所有的 div 元素里面的 直接子节点 p , XPath就应该这样写了 //div/p

如果使用CSS选择器,则为 div > p

3、通配符

如果要选择所有div节点的所有直接子节点,可以使用表达式 //div/*

是一个通配符,对应任意节点名的元素,等价于CSS选择器 div > *

代码如下:

elements = driver.find_elements(By.XPATH, "//div/*") 
for element in elements: 
    print(element.get_attribute('outerHTML'))

二、根据属性选择

XPath 可以根据属性来选择元素。

根据属性来选择元素 是通过 这种格式来的 [@属性名='属性值']

注意:

  • 属性名注意前面有个@
  • 属性值一定要用引号, 可以是单引号,也可以是双引号

1、根据id属性选择

选择 id 为 west 的元素,可以这样 //*[@id='west']

2、根据class属性选择

选择所有 select 元素中 class为 choose_1 的元素,可以这样 //select[@class='choose_1']

如果一个元素class 有多个,比如

<p id="beijing" class='capital huge-city'>北京</p>

如果要选 它, 对应的 xpath 就应该是 //p[@class="capital huge-city"]

不能只写一个属性,像这样 //p[@class="capital"] 则不行

//p[@class="capital huge-city"]

3、根据其他属性

同样的道理,我们也可以利用其它的属性选择

比如选择 具有multiple属性的所有页面元素 ,可以这样 //*[@multiple]

//*[@multiple]

4、属性值包含字符串

要选择 style属性值 包含 color 字符串的 页面元素 ,可以这样 //*[contains(@style,'color')]

要选择 style属性值 以 color 字符串 开头 的 页面元素 ,可以这样 //*[starts-with(@style,'color')] 、 //*[starts-with(@style,'c')] 写开头的一部分就可以

要选择 style属性值 以 某个 字符串 结尾 的 页面元素 ,大家可以推测是 //*[ends-with(@style,'color')]很遗憾,这是xpath 2.0 的语法 ,目前浏览器都不支持

//*[contains(@style,'color')]
//*[starts-with(@style,'color')]
//*[starts-with(@style,'c')]

实际项目地址(内网环境项目互联网无法访问):http://192.168.1.171/

//input[@placeholder="请输入用户名"]

# 匹配input标签包含type属性的值
//input[contains(@type, 'password')]  
//input[contains(@type, 'pa')] # 写一部分也是可以的

# 匹配 当文字中存在广州市 就满足
//div[@role='combobox']/div/div[contains(text(), '广州市')]
//div[contains(text(), '广州市')]

# 匹配a标签包含href属性的值
//a[contains(@href, 'news')]

# 匹配开始字段,ends-with方法不可用
//a[starts-with(@href,'https')]

# 匹配 当class中含有input 就满足条件
//input[contains(@class, 'input')]

在 XPath 中,可以使用 * 选择未知的节点,例如 //div/*/span,表示选择 div 节点下所有节点的 span 节点。

三、按次序选择

css表达式可以根据元素在父节点中的次序选择, 非常实用。使用 nth-childspan:nth-child(2)  选择的是 第2个子元素,并且是span类型

xpath也可以根据次序选择元素。 语法比css更简洁,直接在方括号中使用数字表示次序

span:nth-child(2)

1、某类型 第几个 子元素

比如

要选择 span类型第2个的子元素,就是

//span[2]

注意,选择的是 span类型第2个的子元素 , 不是 第2个子元素,并且是span类型 。

再比如,要选取父元素为div 中的 p类型 第2个 子元素

//div/p[2]

2、第几个子元素

也可以选择第2个子元素,不管是什么类型,采用通配符

比如 选择父元素为div的第2个子元素,不管是什么类型

//div/*[2]

3、某类型倒数第几个子元素

当然也可以选取倒数第几个子元素

比如:

  • 选取p类型倒数第1个子元素
//p[last()]
  • 选取p类型倒数第2个子元素
//p[last()-1]
  • 选择父元素为div中p类型倒数第3个子元素
//div/p[last()-2]

xpath还可以选择 当前节点的 所有后代元素(子、孙等),用这样的语法 descendant::

比如,要选择 id 为 china 的元素的 等 节点 p,这样写

//*[@id='china']/descendant::p

4、范围选择

xpath还可以选择子元素的次序范围。

比如,

  • 选取option类型第1到2个子元素
//option[position()<=2]

或者

  • 选取option类型第1到2个子元素
//option[position()<3]
  • 选择class属性为choose_1的前3个子元素
//*[@class='choose_1']/*[position()<=3]
  • 选择class属性为choose_1的后3个子元素
//*[@class='choose_1']/*[position()>=last()-2]

为什么不是 last()-3 呢? 因为

last() 本身代表最后一个元素

last()-1 本身代表倒数第2个元素

last()-2 本身代表倒数第3个元素

四、组选择、父节点、兄弟节点

1、组选择

css有组选择,可以同时使用多个表达式,多个表达式选择的结果都是要选择的元素

css 组选择,表达式之间用 逗号 隔开

XPath也有组选择, 是用 竖线 隔开多个表达式

比如,要选所有的option元素 和所有的 h4 元素,可以使用

//option | //h4

等同于CSS选择器

option , h4

再比如,要选所有的 class 为 choose_1 和 class 为 choose_2 的元素,可以使用

//*[@class='choose_1'] | //*[@class='choose_2']

等同于CSS选择器

.choose_1 , .choose_2

2、选择父节点

XPath可以选择父节点, 这是css做不到的。

某个元素的父节点用 /.. 表示

比如,要选择 id 为 china 的节点的父节点,可以这样写 //*[@id='china']/.. 

当某个元素没有特征可以直接选择,但是它有子节点有特征, 就可以采用这种方法,先选择子节点,再指定父节点。

还可以继续找上层父节点,比如 //*[@id='china']/../../..

//*[@id='china']/.. 
//*[@id='china']/../../..

XPath还可以选择 当前节点的 父级节点,用这样的语法 parent::

比如,要选择 id 为 china 的元素的 父级 节点div,这样写

//*[@id='china']/parent::div

3、兄弟节点选择

css选择器,要选择某个节点的后续兄弟节点,用 波浪线

xpath也可以选择 后续 兄弟节点,用这样的语法 following-sibling:: /ˈfɑːloʊɪŋ-ˈsɪblɪŋ/

比如,要选择 class 为 choose_1 的元素的所有后续兄弟节点 //*[@class='choose_1']/following-sibling::*

等同于CSS选择器 .choose_1 ~ *

如果,要选择后续节点中的div节点, 就应该这样写 //*[@class='choose_1']/following-sibling::div

XPath还可以选择 前面的 兄弟节点,用这样的语法 preceding-sibling:: /prɪˈsiːdɪŋ-ˈsɪblɪŋ/

比如,要选择 class 为 choose_1 的元素的 所有 前面的兄弟节点,这样写

//*[@class='choose_1']/preceding-sibling::*

XPath也可以选择 文档中当前节点的结束标签之后的所有节点,用这样的语法 following::

比如,要选择 p 元素的结束标签之后的所有 option 节点 //p/following::option

//p/following::option

XPath也可以选择 文档中当前节点的开始标签之前的所有节点,用这样的语法 preceding::

比如,要选择 p 元素的结束标签之前的所有 option 节点 //h4/preceding::option

//h4/preceding::option

而 CSS选择器 目前还没有方法选择 前面的 兄弟节点

要了解更多Xpath选择语法,可以点击这里,打开Xpath选择器参考手册

五、XPath 汇总

1、依靠自己的属性,文本定位

//span[text()='登录'] 
//div[contains(@class,'select_city')]
//input[@type='radio' and @value='1']     多条件
//span[@name='user'][text()='账号'][1]   多条件
//span[@id='user' or text()='账号']  找出多个
//span[text()='账号' or text()='密码']  找出多个

2、依靠父节点定位

//div[@class='x-grid-col-name x-grid-cell-inner']/div
//div[@id='dynamicGridTestInstanceformclearuxformdiv']/div
//div[@id='test']/input

3、依靠子节点定位

//div[div[@id='navigation']]
//div[div[@name='listType']]
//div[p[@name='testname']]

4、混合型

//div[div[@name='listType']]//img
//td[a//font[contains(text(),'Xpath 视频')]]//input[@type='checkbox']

5、进阶部分

//input[@id='test']/following-sibling::input   找下一个兄弟节点
//input[@id='test']/preceding-sibling::span    上一个兄弟节点
//input[starts-with(@id,'test')]               以什么开头
//span[not(contains(text(),'xpath'))]        不包含xpath字段的span

6、索引

//div/input[2]
//div[@id='position']/span[3]
//div[@id='position']/span[position()=3]
//div[@id='position']/span[position()>3]
//div[@id='position']/span[position()<3]
//div[@id='position']/span[last()]
//div[@id='position']/span[last()-1]

7、substring 截取判断

//*[substring(@id,4,5)='Every']/@id  截取该属性 定位3,取长度5的字符
//*[substring(@id,4)='EveryCookieWrap']  截取该属性从定位3 到最后的字符
//*[substring-before(@id,'C')='swfEvery']/@id   属性 'C'之前的字符匹配
//[substring-after(@id,'C')='ookieWrap']/@id   属性'C之后的字符匹配8.通配符
//span[@*='bruce']
//*[@name='bruce']

8、轴

//div[span[text()='测试']]/parent::div    找父节点
//div[span[text()='测试']]/ancestor::div    找祖先节点

9、孙子节点

//div[span[text()='测试']]/descendant::div/span[text()='测试']
//div[span[text()='测试']]//div/span[text()='测试']          两个表达的意思一样

Xpath定位方式的缺点

由于xpath需要遍历页面,所以定位元素的性能要比其它的方式差

不够健壮,xpath会随着页面元素的改变而改变

兼容性不好,在不同的浏览器下对xpath的实现不一样

猜你喜欢

转载自blog.csdn.net/qq_28807911/article/details/132056287