Selenium 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=utf8from 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代码。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

搜索
«   2019年11月   »
123
45678910
11121314151617
18192021222324
252627282930
最新留言
    标签列表

      Powered By Z-BlogPHP 1.5.2 Zero