Selenium XPath选择元素

3.4.7 通过 XPath 选择

XPath(XML Path Language)W3C定义的用来在XML文档中选择节点的语言。主流浏览器(Chrome、Firefox,Edge,Safari)也支持XPath语法。XPath1.x2.x两个版本,支持的主要是XPath 1.X的版本,2.X的版本目前几乎不支持。

对于浏览器原生支持XPath的,Selenium尽量使用原生的XPath实现,有些浏览器也支持通过XPath来访问。我们推荐尽量使用CSS选择,而不是用XPath,因为CSS方式通畅速度更快,而且相对更容易理解。使用XPath定位的一个主要场景是。XPath有从当前节点选择父节点的功能,这是CSS selector所不具备的。如果我们要选择一个子节点(比如子节点有id,方便定位)的父节点,可以使用XPath。就比较方便。 另外,我们后面学习的 移动App 自动化里面没有css选择元素,只有xpath选择,所以我们有必要也去了解一下Xpath

大家看下面这段html代码:


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>定位网页元素</title>

<style>
    p,button {color: red;}
</style>

</head>

<body>
    <div style="">
      <h3>This is a heading</h3>
      <p>This is a paragraph.</p>
    </div>

    <button name='button'>按钮1</button>
    <button name='button'>按钮2</button>

    <div class="cheese"><span>Cheddar</span></div>
    <div class="cheese"><span>Gouda</span></div>

    <a href="http://www.baidu.com" id="baidulink">转到百度</a>

    <div id="food" style="margin-top:10px">
        <span class="vegetable good">黄瓜</span>
        <span class="meat">牛肉</span>
        <p class="vegetable">黄瓜pp</p>
        <p class="vegetable">青菜</p>
    </div>

    <div id="food2" style="margin-top:10px">
        <span class="vegetable">黄瓜2</span>
        <span class="meat">牛肉3</span>
    </div>

    <select id="choose_car">
        <option value="volvo">沃尔沃</option>
        <option value="corolla">卡罗拉</option>
        <option value="fiat">菲亚特</option>
        <option value="audi">奥迪</option>
    </select>

    <footer>
        <div>
            <p>test1</p>
        </div>
    </footer>

    <p>test2</p>
    <div id="many">
        <div>
            <p class="special" name="p1">one</p>
            <p>two</p>
            <p class="special3">three</p>
        </div>
    </div>

    <p spec="len">test3</p>
    <p spec="len2">test4</p>
    <p spec="len2 len3">test5</p>


</body>
</html>

可以在 element tab 中输入 //option也可以在 console tab验证。

html文档被看成 文件系统一样的 树状结构, 文件系统树的根节点用 / 表示,那么html的根节点是什么console输入$x('/')点击 后发现, 高亮显示的元素,对应整个html文档,如果我们想选择的是根节点下面的html节点console输入$x('/html'),如果要继续选择html下面的一层层节点console输入$x('/html/body/p'),大概等价于css中的html >body>p,假如路径以正斜杠(/)开始,表示从根节点开始,则此路径始终代表到某元素的绝对路径!很像Linux里面的绝对路径的概念,我们的Selenium代码 也 可以用这样的xpath来查找元素。

比如:

eles = driver.find_element_by_xpath("/html/body/p")

我们怎么表示 整个文档中的所有的option(选项)节点,不管它在什么位置? 就像css 中的option这样呢?xpath 需要前面加// , //表示 从当前节点往下寻找所有的后代元素,不管它在什么位置。 既然开始的时候,当前节点是根节点, 如果以//开头就表示从根节点 开始, 往下寻找所有的后代元素,不管它在什么位置,比如:

//option

表示 从当前节点往下寻找所有的后代元素中名字为option的。

当然 // 符号 也可以继续加在后面。

//div//p

表示选择 所有 的 div 元素里面的所有p元素 , 不管div 在什么位置, 不管 p 元素在 div 下面的什么位置。就等于 css 选择器的div p

如果我们要找某个元素下面的直接子节点,而不是所有的后代节点呢?比如body节点下面直接的p节点, 而不是它所有的后代节点p节点那就是:

//body/p

就等于 css 选择器的body > pcss 一样 xpath 也有通配符 * 比如选择所有的节点:

//div/*

选择 div 下面所有的 直接子元素。

3.4.8 XPath 根据属性和属性的值选择

比如:选择所有具有style属性的元素,注意前面必须有个@

//*[@style]

又比如:选择所有具有 spec 值为 len2p元素。

//p[@spec='len2']

注意: css 中 如果 属性值 没有空格 可以不加引号。但是 xpath必须要引号,单双引号都可以。

如果我们要想根据id选择, 因为id也是一个属性 可以:

//div[@id="food"]

要想根据class选择, 因为 class 也是一个属性 可以:

//div[@class="cheese"]

3.4.9 子元素选择

注意在cssXPath中索引是从1开始的,和python中不一样,在xpath中 第几个某类型的子元素 直接用:

//p[2] 

表示 选择属于其父元素的第2p类型的子元素(不一定在所有的元素中排第2个)等价于 css 中的:

p:nth-of-type(2) 

比如:

 //*[@id="food"]/p[1]   

等价于 css 中的:

 #food > p:nth-of-type(1) 

那么,如果是表示 其父元素的所有的元素中 第几个呢, 而不是像上面这样, 某种类型的第几个,该这样写:

//*[@id="food"]/*[1]

因为*表示所有的类型的元素。


xpath中 倒数第几个p类型子元素用:

//p[last()-1]   

表示 属于其父元素的倒数第二个 p 类型的子元素,等价于 css 中的:

p:nth-last-of-type(2)

倒数第一呢? 当然就是:

p[last()]

等价于css中的:

p:nth-last-of-type(1)

比如:选择 倒数第1span类型元素:

//*[@id="food"]/span[last()]

等价于 css 中的:

#food > span:nth-last-of-type(1)

同样的道理, 如果是表示 其父元素的所有的元素中 倒数第几个,就是这样:

 //*[@id="food"]/*[last()-1]

因为 * 表示所有的类型的元素。


如果我们要表示的是 属于其父元素的所有类型元素的 第二个子元素,在xpath中,除了上面说的用 *[2],还有一种方法用 *[position()=2] 试一下,比如:

//*[@id="food"]/*[position()=2]

等价于 css 中的:

*:nth-child(2)

比如:

//*[@id="food"]/*[position()=3]   

等价于 css 中的:

#food > *:nth-child(3)

那么既然下面的写法都可以,后者还更麻烦,用它有什么好处呢?


image.png

因为 position 函数还支持其他的 比较操作符, 可以多选元素,比如:

//*[@id="food"]/*[position()< 3]
//*[@id="food"]/*[position()<= 3]
//*[@id="food"]/*[position()>=3]

这个我们需要选择第几个以后的元素的时候, 就方便多了。

//*[@id='food']/*[position()>1][position()<3]

注意,这种情况用css比较麻烦,难懂,这里就是xpath表达式的长处了,倒数第几个元素也是类似同样的方法,我们除了可以用:

//*[@id="food"]/*[last()-1]

也可以:

//*[@id="food"]/*[position()=last()-1]
#//body/*[position()=last()-1]

当然, 使用position函数的最大好处是可以多选, 比如:

//*[@id="food"]/*[position() > last()-3]

从倒数第3个开始 选择所有的。


css 有组选择,可以 同时选择多个元素,逗号隔开,比如 p,button 选择所有的 pbutton 那么xpath对应多个选择是怎么做的呢?用竖线隔开//p | //button

xpath 还有很多其他的选择语法, 我们可以看,css中选择兄弟节点,xpath 还有很多其他的选择语法。

css中选择兄弟节点:
打开html 尝试一下#food ~ div 选择 idfood 的元素后面的所有 div 兄弟节点,xpath中 相邻兄弟选择器 following-sibling 和 preceding-sibling

#food ~ div

等价于 注意是两个冒号

//*[@id="food"]/following-sibling::div

如果我们要选择 选择 idfood 的元素 前面 的所有 div 兄弟节点 css 就没有办法了,但是 xpath 有:

//*[@id="food"]/preceding-sibling::div

也可以根据次序来找,写1表示紧挨着前面的第一个,写2就是第二个

//*[@id="food"]/preceding-sibling::div[1]

css#food + div ,选择紧接着 后面的的那个兄弟节点,xpath可以这样

//*[@id='food']/following-sibling::div[1]      
//*[@id='food']/following-sibling::div[position()>=1]

css 选择不能用的, 而 xpath 可以的, 还有选择父节点 直接用 .. 表示
比如 //*[@id='food']/..就选择了body节点,那么这个到底有什么用处呢?有的时候我们最终想选择的元素 不好定位(没有id,父节点也没有id, 没有唯一好定位的属性), 但是它的子节点好定位,比如有id,看下

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>定位网页元素</title>
</head>

<body>

    <div >
        <div>
            #8765#
            <span id="beef" price="20">牛肉</span>
        </div>
        <div>
            #8766#
            <span id="pork" price="50">猪肉</span>
        </div>
        <div>
            #8767#
            <span id="sammon" price="70">三文鱼</span>
        </div>

    </div>

</body>
</html>

如果我们想 验证 其中猪肉前面的代码(当前网页是8766), 该怎么做? 因为代码在猪肉 那个span节点的父节点。

最好的方式是根据其idporkspan子节点来定位器父节点。这时可以用XPath的选择器,代码如下

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

这样就得到父元素对应的webelement了, 再获取其text属性,去掉#就可以了对应的代码是:

# coding=utf8
from selenium import webdriver

driver = webdriver.Chrome(r"d:\tools\webdrivers\chromedriver.exe")

driver.get('file:///D:/gsync/workspace/sq/selenium/samples_selenium/wd/lesson05/xpath.html')



ele = driver.find_element_by_xpath("//*[@id='pork']/..")
print (ele.text.split('#')[1])

# eles = driver.find_elements_by_xpath("//*[@id='beef']/../..//span[@price>20]")
# for ele in eles:
#     print(ele.text)

driver.quit()

还可以继续找上层,比如

//span[@id='pork']/../../../..

补充讲解:
这是一个特别要注意的小技巧对xpath来说,如果是从当前webelement调用find_element_by_xpath,需要前面加个点 比如:

food = driver.find_element_by_id("food")
eles = food.find_elements_by_xpath('//p')


for ele in eles:
    print('----------')
    print(ele.get_attribute('outerHTML'))

就不对,应该是

food = driver.find_element_by_id("food")

eles = food.find_elements_by_xpath('.//p')

for ele in eles:
    print('----------')
    print(ele.get_attribute('outerHTML'))

更多的语法大家可以去W3c去看:http://www.w3school.com.cn/xpath/xpath_axes.asp

3.4.10 通过 JavaScript 选择

我们还可以通过让浏览器执行 JavaScript 代码来选择 web 元素。只要我们给浏览器执行的js代码最后返回一个DOM Element对象。

from selenium import webdriver

driver = webdriver.Chrome('E:\ChromDriver\chromedriver.exe')

driver.get('http://www.baidu.com')

kw = driver.execute_script("return $('#kw')[0]")

kw.send_key('测试')

driver.quit()

driver.execute_script方法让浏览器执行我们制定的js代码。

通过执行我们自己定义的JavaScript,给了我们极大的灵活性,不仅可以用在测试方面,甚至可以修改web页面里面的内容,达到各种目的。当然这需要js开发的基础。有兴趣的同学可以自行深入研究。

本章就到这里了,喜欢麻烦点个赞!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • 3.4 通过CSS选择器选择 W3C的CSS是定义HTML页面样式的语言。它决定页面元素显示的效果,比如一段文本的...
    自如_阅读 1,922评论 0 5
  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,727评论 1 92
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,421评论 1 45
  • xpath:树型结构 1. 基本概念 使用方法:find_element_by_xpath("...") 根节点:...
    残阳夕露阅读 989评论 0 7
  • 我这样说,是因为,中国目前这种乌烟瘴气的环境,配不上方先生。 放眼望去,普天之下,“过江名士多于鲫”,但方舟子却只...
    幽明轩笔记阅读 303评论 0 0