使用selenium中元素定位相关知识总结

目录

元素定位接口

Python

JAVA

xpath和css定位技术

xpath

xpath基础知识

xpath语法

CSS选择器定位


 

使用selenium做web页面自动化时,最重要的工作的就是进行元素的定位,只有定位到元素才能进行后续的操作,例如点击一个按钮前,你必须先要知道这个按钮在哪里。

 

元素定位接口

Python

selenium为单个元素定位,提供了8个API:

selenium选择器接口
接口名称功能说明返回值
find_element_by_id根据页面元素的Id,寻找元素

 

能找到则返回一个代表这个元素的WebElement对象,否则抛出NoSuchElementException异常。 即使有多一个元素符合条件,仅返回最先发现的那个元素的对象。

find_element_by_name根据页面元素的name,寻找元素同上
find_element_by_class_name根据页面元素的class name,寻找元素同上

find_element_by_xpath

根据页面元素的xpath,寻找元素同上

find_element_by_css_selector

根据页面元素的css,寻找元素同上

find_element_by_tag_name

根据页面元素的tag名字,寻找元素。很少用,同一类元素都有相同的唐名字同上

find_element_by_link_text

根据页面元素的完整的链接字符串,寻找元素同上

find_element_by_partial_link_text

根据页面元素的部分链接字符串,寻找元素,模糊查找同上

上面的接口返回的是单个元素,还有一组类似的接口,返回的是元素符合条件的元素对象列表:

find_elements_by_id返回值是一个列表或空列表
find_elements_by_name同上
find_elements_by_name同上
find_elements_by_xpath同上
find_elements_by_css_selector同上
find_elements_by_tag_name同上
find_elements_by_link_text同上
find_elements_by_partial_link_text同上

实际上上面2组接口都是调用find_element和find_elements实现的,这2个接口是私有的,不过你也可以调用的(因为python中没啥东西真的私有滴)

from selenium import webdriver
from selenium.webdriver.common.by import By


driver = webdriver.Chrome("C:\\selenium\\chromedriver.exe")
driver.get("http://www.baidu.com")
pp = driver.find_elements(By.ID, "adsfasd")

 

JAVA

Java中定位接口更简练些,只有find_element和find_elements




 

 

 

xpath和css定位技术

通过对上面元素定位接口的研究,我们知道我们可以用来进行定位的有 id,name, class name, tag name, link text, partial link text, xpath 和 css。 

在实际使用中,有时候id,name, class name, tag name, link text, partial link text,可能不存在,或者可能会发生变化,又或者肯能存在重复的问题,这时候我们就需要更复杂的定位手段了。 他们就是xpath和css,但是相对的这个2个定位方法学习起来更难一些,所以在这里对这2中方法进行详细的介绍。

xpath

xpath是XML中的一种定位语言,因为HTML可以说是XML规范的一种实现,所以xpath也可以用在HTML中元素的定位。除了通过绝对路径进行定位,xpath还支持相对定位等待。

工具: 

通过Firefox的FirePath插件可以方便的获取到xpath值. 由于最新版火狐不在支持FireBug等开发工具,可以通过https://ftp.mozilla.org/pub/firefox/releases/ 下载49版本以下的火狐就可以增加Firebug等扩展了。

我使用的chrome版本是75.0.3770.100,通过右击页面,选择 检查, 或通过 更多工具-开发者工具, 都可以打开debug工具,点中工具左上角的箭头图标,然后选择要定位的元素,在工具里会显示元素的信息,右击元素 -》 copy- 》 copy xpath

 

xpath基础知识

术语解释

<?xml version="1.0" encoding="UTF-8"?>

<bookstore>
  <book>
    <title lang="en">Harry Potter</title>
    <author>J K. Rowling</author>
    <year>2005</year>
    <price>29.99</price>
  </book>
</bookstore>

上面例子中:

<bookstore> 为文档节点,也称为根节点

<author>J K. Rowling</author>   为元素节点

lang=“en” 为属性节点

“en” 和J K. Rowling 被称为基本值

 

book 是 title,author, year,price的父节点-----parent

title,author, year,price 是 book的子节点-----Children

title,author, year,price 是兄弟节点------Sibling

title的先辈是book和bookstore--------Ancestor

bookstore的后代则是 book, title,author, year,price ------ Descendant

 

xpath语法

1. 使用路径表达式定位节点

路径分为绝对路径和相对路径:

绝对路径从根节点开始,使用 / 开头, 代表从根一直到当前节点      

相对路径以 // 开头   根据要定位的元素的特征来进行定位

 

节点之间关系的表示:

当前节点用单个点 . 表示 

当前节点的父节点用 2个点 .. 表示

 

2. 使用谓语来定位节点

当单纯的路径表达式无法准确定位时,我们可以使用谓语来进一步定位。 谓语被置于中括号内。

//*[@id="u1"]/a[2]  根据索引进行元素定位(下标从1开始)

//*[@id="u1"]/a[last()] 根据索引进行元素定位,我们可以获得最后一个元素

//*[@id="u1"]/a[last() -1] 根据索引进行元素定位,我们可以获得倒数第二个元素

//*[@id="u1"]/a[position()<3] 根据索引进行元素定位,我们可以获得前2个元素

//*[@id="u1"]/a[@name]  目标元素要具有指定的属性

//*[@id="u1"]/a[@name="news"] 目标元素不仅需要包含属性name,而且属性的值必须是news

//*[@id="u1"]/a[text()="news"] 通过标签的文本来定义节点 也可以写成//*[@id="u1"]/a[.="news"], 用这个方法时,标签必须有文本才行

//*[@id="u1"]/a[contains(text(),"news")]   这是一种模糊查找, 只要那个a标签的文本包含news,就符合条件

//*[@id="u1"]/a[contains(@name,"news")]    与上面相同,这是一种模糊查找, 只要那个a标签的name属性的值包含news,就符合条件



通过标签的文本来定义节点   也可以写成//*[@id="u1"]/a[.="news"]

 

 

3. 通配符

用来获取哪些未知的节点元素

* 可以用来代表任何元素节点     //*[@id="head"]/div/*

@* 可以用来标识任何属性   //*[@id="head"]/div/div[@*]        代表目标div必须有至少有一个属性

  

4. 一次获取多个节点元素

这多个元素通常没有什么关联性

//*[@id="head"]/div | //*[@id="form"]/span[1]   可以定位2个不相关的元素

 

5. 轴定位

就是靠节点间的父子关系来定位,适合用于相对位置较为固定的节点结构

语法规则: 当前节点/关系类型::目标节点特征

关系类型包括:父节点(parent)、子节点(child)、祖先节点(ancestor)、子孙节点(descendant)、后节点(following)前节点(preceding)、后兄弟节点(following-sibling)、前兄弟节点(preceding-sibling)

 

<html><head></head><body>
        
    

    <div>  #div1
            <input>
        	<a>big</a>
        	<img name="haha">
    		<button></button>
                <div>1</div>   #div4
        </div>
    
    <div> #div2
                <input>
        	<a>small</a>
        	<img name="haha2">
    		<button></button>
                <div>2</div>   #div5
    </div>
    
    <div> #div3
                <input>
        	<a>large</a>
        	<img name="haha3">
    		<button></button>
                <div>3</div>   #div6
    </div>

    
</body></html>

 

参考上图,举例说明各个关系是怎么运用的:

/html/body/div[1]/img/parent::*/input   以img为当前节点,获取它的parent(因为只有一个parent,所以可以用星号),然后定位到parent下的input节点

/html/body/div[1]/child::img   以div1为当前节点,获取它的所有子节点,从这些子节点中找到img节点

 

/html/body/div[1]/img/ancestor::body  以img为当前节点, 获取它的所有先辈节点(div1,body 和html),然后定位到body节点

/html/body/descendant::img[@name="haha"]  以body为当前节点,获取所有的子孙节点,从中定位到name属性为哈哈的img节点

 

/html/body/div[1]/following::div[2] 以div1为当前节点,获取与div1同级的后面所有节点及其所有子孙节点,从中定位第二个div。主要注意的是如果后面节点中存在多层结构,每层结构中都有div, 索引是从上到下,而与层级没有关系,本例中第二个div是上图中那个div5

/html/body/div[3]/preceding::div[1]    以div3为当前节点,获取与div3同级的前面所有节点及其所有子孙节点,从中定位我们要定位的元素。 主要最后的div[1]定位的是div5,索引是从下到上的

 

/html/body/div[1]/following-sibling::div[1]   以div1位当前节点, 获取与div1同级的后面的所有兄弟节点(不包含兄弟节点的子孙节点), 从中定位一个我们要的元素。   注意最后一个div[1] 定位的是div2

/html/body/div[3]/preceding-sibling::div[1]   以div3位当前节点,获取与div2同级的前面的所有兄弟节点,从中定位div2, 注意此处的索引是从下向上的。

 

6. 使用辅助函数进行定位

其实我们前边已经用过了,就是那个contains函数,能够支持的函数如下:

starts-with: 定位属性或文本以指定字符开头的节点

/html/body/div/a[starts-with(text(),"b")]     定位到 <a>big</a>

/html/body/div/img[starts-with(@name,"haha")]    会定位到3个img节点

contains: 定位属性或文本中包含指定字符串的节点

/html/body/div/img[contains(@name,"haha")]   会定位到3个img节点

text:获取节点的文本,可以用 . 代替

last:获取定位到一组节点的最后一个节点的索引

not:取反操作

/html/body/div/a[ not(contains(.,"s"))]   会选中big和large 这个2个节点

 

7. 运算符

这些运算符用于谓语中,构建过滤条件

+, -, *, div,mod: 算数运算, 加减乘除和取余,主要用来计算索引值

=, !=, >=,  <=, >, <: 比较运算符,建立过滤条件   //div[. > 1]    就会定位到div5

or, and: 逻辑运算符,连接多个条件构成过滤条件   //div[. = 1 or . = 2]   会选定div4 和div5

 

 

 

CSS选择器定位

其实如果会用xpath,也可以不学css了,不过技多不压身嘛! 但是,我如果太久不用定位,就经常弄混css和xpath的语法,哎

先弄一个例子,所有的操作都是针对这个例子的

<html><head></head><body>
        
    

    <div>  #div1
            <input id="test1" class="sweet1">
        	<a>big</a>
        	<img name="haha">
    		<button></button>
                <div>1</div>   #div4
        </div>
    
    <div> #div2
                <input id="test2" class="sweet2">
        	<a>small</a>
        	<img name="haha2">
    		<button  class="abc efg hhh" name="ddd eee fff"></button>
                <div>2</div>   #div5
    </div>
    
    <div> #div3
                <input id="test3" class="sweet3">
        	<a>large</a>
        	<img name="haha3">
    		<button class="abc-efg-hhh" name="ddd-eee-fff"></button>
                <div>3</div>   #div6
    </div>

    
</body></html>

我们从简单到复杂,一步一步来

一:使用单个属性进行定位

1. 使用id进行定位

    #test1       定位到第一个input节点, 这里#有特殊意义,其后是id的值,作用类似于xpath中的 [@id="test1"]

    .sweet3    定位到第三个input节点, 注意第一个字符是个点(.), 其后是class属性的值, 作用类似xpath中  [@class="sweet3"]

    input        会搜索到3个input节点, 这个就是仅仅根据标签名进行定位

    [name]     仅仅id和class属性有上面的特殊书写方式,其他属性就没这个权利了。 这个会搜索到所有包含name属性的节点

    [name=haha] 或者 [name="haha"]      会定位到第一个input节点,注意haha可以带引号也可以不带,但xpath是需要给属性值加引号的,另外xpath中属性名前要加@

 

二. 使用多个属性组合来进行定位

input.sweet3                              代表要找的是,class属性是sweet3的input标签

input#test1                                代表要找的是,id属性是test1的input标签

input[name=haha]                     代表要找的是,name属性是haha的input标签

input[name]                               代表要找的是,拥有name属性的input标签

input[id=test1][class=sweet1]   代表要找的是,id是test1, class是sweet1的input标签, 后边2个中括号是and的关系

 

三. 使用模糊匹配来进行定位

当属性的值中包含多个由空格隔开的字符串时,可以用其中一个字符串进行定位

button[name~=ddd]     button[name~=eee]   button[name~=fff]

 

属性的值中包含多个空格隔开的字符串时,无法用整个属性值定位,通常只有class的值才会有空格间隔

button[name=”ddd eee fff”]     

 

当属性的值中包含多个空格隔开的字符串时,可以用来搜索class中开始位置是abc的节点

button[class^=abc]      button[class^=ab]     button[class^=a]

 

当属性的值中包含多个由空格隔开的字符串时,可以用来搜索class中结尾位置是hhh的节点

button[class$=hhh]     button[class$=hh]     button[class$=h] 

 

当属性值中包含 -(短横杠)时,可以匹配其中一部分,但是每一部分都要精确填写

button[class|=abc-efg-hhh]      button[class|=abc-efg]      button[class|=abc]

 

四. 多个class值进行定位

button.abc.efg.hhh    当一个节点的class值为多个由空格分隔的字符串时,可以用这种方式进行定位

 

五. 通过层级进行定位

1. 父元素>子元素

div>input[id=test1]          div>input会搜索到所有div下的input节点,然后再通过id进行限定

2. 父元素 子孙元素      

body *                             代表body的所有子元素以及子元素的子元素。。。。

body input                      代表body的所有子孙元素中的标签为input的元素

body input[id=test3]        代表body的所有子孙元素中的标签为input,且id是test3的元素

 

3. 通过下标定位

:nth-child(n)              理解了这个,下面的就好理解了

:nth-last-child(n)       当n为1时,表示最后一个child

:first-child                 相当于nth-child(1)

:last-child                 相当于nth-last-child(1)

:only-child                定位到的元素的父节点只有一个子节点时,才符合要求,后面有个例子

这些用法很难理解,查了很多地方,没搞明白,通过做实验观察结果,来总结它的用法。我们重写一个html来做实验

<html><head></head><body>
        
    

    <div>  #1
            
                <input id="test" class="sweet">   #num1
                <input id="test" class="sweet">   #num2
        	<a>big</a>
        	<img name="haha">
    		<button></button>
                <p>
                    <a>test</a> 
                </p>
                   
    </div>
    
    <div> #2
                <input id="test" class="sweet">   #num3
        	<a>small</a>
                <img></img>
                <button></button>
                <div>2</div>   #4
                <p>
                    <a>test</a> 
                    <a>test</a>
                </p>
    </div>
    
    <div> #3
                <input id="test" class="sweet">   #num4
                <a>small</a>
                <img></img>
                <button></button>
                <div>3</div>   #5
    </div>

    

 </body></html>

 

谁的孩子??

.sweet:nth-child(1)     

我们选中的是什么呢? 选中的是#num1,#num3,#num4, 这个不是很好理解,.sweet:nth-child(2)选中的是#num2, 可以理解。 但是.sweet:nth-child(3) 或者比3更大的值,就选不到东西了,明明.sweet能搜到4个节点,这是为什么呢?

我的理解是:.sweet:nth-child(n)  这个表达式的意思是, .sweet所定位的所有元素中,属于同一个父节点的子元素中的第n个元素。

这样,上面的结果我们是不是就可以理解了呢。 不过这是我的推测,如果不正确的地方请指正。

 

男孩还是女孩??

body:nth-child(1)

能理解上面那个表达式了,但是马上就遇到问题了,body:nth-child(1) 这个选不到任何元素。 但是用head:nth-child(1)可以定位到head元素,为什么呢?

我的理解是:body定位到元素body,body节点的父节点是html,html的第一个子元素是head,但是head节点的标签并不是我们所需的body标签,所以没有定位的任何元素。  这里的关键点是,body节点的父节点的子节点可能是各种类型的,但我们最终要定位的是body类型。

为了验证我的猜测,body:nth-child(2) 这个表达式时可以定位的body标签的。

 

不同辈分的孩子怎么寻找父亲??

div:nth-child(1)

我们已经知道了,理解的关键是要找到目标元素的父节点。 但是这里div能定位到的节点在不同的层级中,它能搜索到5个div节点。div:nth-child(1) 对一个的是#1, div:nth-child(2)对应的是#2, div:nth-child(3)对应的是#3, div:nth-child(4)就定位不到任何元素,div:nth-child(5)对应到了#4和#5。

我的理解是:除了处于不同节点集的元素有不同的父节点, 在同一节点集中不同层次的元素也会有不同的父节点。 所以这就好解释了。

当n为1时,

               对于父节点body来说,它定位到的是div是#1

               对于父节点是#2来说,它定位到的将是#num3,但这个元素是个input,不是我们要找的div

               对于父节点是#3来说,它定位到的将是#num4,但这个元素是个input,不是我们要找的div

所以当n为1时,我们能定位一个元素,他就是#1

n为2和3时,处理过程与1相似。

当n为4时,

               对于父节点body来说,它没有第四个child

               对于父节点是#2来说,它定位到的这个元素是个button,不是我们要找的div

               对于父节点是#3来说,它定位到的这个元素是个button,不是我们要找的div

当n为5时,

               对于父节点body来说,它没有第5个child

               对于父节点是#2来说,它定位到的这个元素是#4

               对于父节点是#3来说,它定位到的这个元素是#5

 

寻找要独生子女

div>p>a:only-child

这个仅仅会定位到#1中p下面的test,因为#2中p下面有2个child,不符合独生子女的要求。

 

 

参考文档:

https://selenium-python.readthedocs.io

https://www.runoob.com/xpath/xpath-syntax.html

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值