前面咱们学习了CSS选择元素。css
你们能够发现很是灵活、强大。html
还有一种灵活、强大的选择元素的方式,就是使用Xpath表达式。web
XPath (XML Path Language) 是由国际标准化组织W3C指定的,用来在XML和HTML文档中选择节点的语言。chrome
目前主流浏览器 (chrome、firefox,edge,safari) 都支持XPath语法,xpath有1和2两个版本,目前浏览器支持的是xpath 1的语法。api
既然已经有了CSS,为何还要学习Xpath呢?由于浏览器
有些场景用 css选择web元素很麻烦,而xpath却比较方便。框架
另外Xpath还有其余领域会使用到,好比爬虫框架Scrapy,手机App框架Appium。学习
html代码:spa
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h3 style="color: brown">select框</h3> <h4 style="color: rgb(22, 118, 173)">单选</h4> <p>姓名:</p> <select class="single_choice" > <option value="小江老师">小江老师</option> <option value="小雷老师">小雷老师</option> <option value="小凯老师" selected="selected">小凯老师</option> </select> <hr> <h4 style="color: rgb(22, 118, 173)">多选</h4> <p>课程:</p> <select class="multi_choice" multiple> <option value="小江老师">小江老师</option> <option value="小雷老师">小雷老师</option> <option value="小王老师">小王老师</option> <option value="小凯老师" selected="selected">小凯老师</option> </select> <hr> <div> <p style="color: brown; font-weight: bold;"> 城市选择 </p> <div id="china"> <p id="beijing" class='capital huge-city'> 北京 </p> <p id="shanghai" class='huge-city'> 上海 </p> </div> <div id="us"> <span id="west" style="color:darkgreen"> <p id="newyork"> 纽约 </p> <p id="huston"> 休斯顿 </p> </span> <span id="east" style="color:darkred"> <p id="chigaco"> 芝加哥 </p> </span> </div> </div> </body> </html>
按F12打开调试窗口,点击 Elements标签。firefox
要验证Xpath语法是否能成功选择元素,也能够像验证CSS语法那样,按组合键Ctrl + F ,就会出现搜索框。
xpath语法中,整个HTML文档根节点用‘/’表示,若是咱们想选择的是根节点下面的html节点,则能够在搜索框输入。
/html
若是输入下面的表达式:
/html/body/div
这个表达式表示选择html下面的body下面的div元素。
注意/有点像CSS中的> , 表示直接子节点关系。
从根节点开始的,到某个节点,每层都依次写下来,每层之间用/分隔的表达式,就是某元素的绝对路径。
上面的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")
有的时候,咱们须要选择网页中某个元素,无论它在什么位置。
好比,选择示例页面的全部标签名为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_css_selector("div p")
若是,要选择全部的div元素里面的直接子节点p,xpath,就应该这样写了//div/p
若是使用CSS选择器,则为div > p>。
若是要选择全部div节点的全部直接子节点,可使用表达式//div/*。
* 是一个通配符,对应任意节点名的元素,等价于CSS选择器div > *。
代码以下:
elements = driver.find_elements_by_xpath("//div/*") for element in elements: print(element.get_attribute('outerHTML'))
Xpath能够根据属性来选择元素。
根据属性来选择元素是经过这种格式来的[@属性名='属性值']
注意:
属性名注意前面有个@
属性值必定要用引号, 能够是单引号,也能够是双引号
选择id为west的元素,能够这样//*[id='west'] 。
选择全部 select 元素中 class为 single_choice 的元素,能够这样//select[@class='single_choice']。
若是一个元素class 有多个,好比:
<p id="beijing" class='capital huge-city'> 北京 </p>
若是要选它,对应的xpath就应该是//p[@class="capital huge-city"]。
不能只写一个属性,像这样//p[@class="capital"]则不行。
一样的道理,咱们也能够利用其它的属性选择。
好比选择具备multiple属性的全部页面元素,能够这样//*[@multiple]。
要选择style属性值包含color字符串的页面元素,能够这样//*[@contains(@style,'color')]。
要选择style属性值以color字符串开头的页面元素,能够这样//*[@starts-with(@style,'color')]
要选择style属性值以某个字符串结尾的页面元素,你们能够推测是//*[@ends-with(@style,'color')], 可是,很遗憾,这是xpath 2.0的语法,目前浏览器都不支持。
前面学过css表达式能够根据元素在父节点中的次序选择,很是实用。
xpath也能够根据次序选择元素。语法比css更简洁,直接在方括号中使用数字表示次序。
要选择p类型第2个的子元素,就是
//p[2]
注意,选择的是p类型第2个的子元素,不是第2个子元素,而且是p类型。
还有,要选择父元素的div中的p类型第2个子元素。
//div/p[2]
也能够选择第2个子元素,无论是什么类型,采用通配符。
好比选择父元素为div的第2个子元素,无论是什么类型。
//div/*[2]
固然也能够选取倒数第几个子元素
例如:
选取p类型倒数第1个子元素
//p[last()]
选取p类型倒数第2个子元素
//p[last()-1]
选择父元素为div中p类型倒数第二个子元素
//div/p[last()-2]
xpath还能够选择子元素的次序范围。
例如:
选取option类型第1到2个子元素
//option[position()<=2]
或者
//option[position()<3]
选择class属性为multi_choice的前3个子元素
//*[@class='multi_choice']/*[position()<=3]
选择class属性为multi_choice的后3个子元素
//*[@class='multi_choice']/*[position()>=last()-2]
为何不是last()-3呢?由于
last() 自己表明最后一个元素
last()-1 自己表明倒数第2个元素
last()-2 自己表明倒数第3个元素
css有组选择,能够同时使用多个表达式,多个表达式选择的结果都是要选择的元素。
css 组选择,表达式之间用逗号隔开。
xpath也有组选择,是用竖线隔开多个表达式。
好比,要选全部的option元素和全部的h4元素,可使用
//option | //h4
等同于CSS选择器
option , h4
好比,要选全部的class为single_choice和class为multi_choice的元素,可使用
//*[@class='single_choice'] | //*[@class='multi_choice']
等同于CSS选择器
.single_choice , .multi_choice
xpath能够选择父节点,这是css作不到的。
某个元素的父节点用/..表示
好比,要选择id为china的节点的父节点,能够这样写//*[@id='china']/..。
当某个元素没有特征能够直接选择,可是它的子节点有特征,就能够采用这种方法,先选择子节点,在指定父节点。
还能够继续找上层父节点,好比//*[@id='china']/../../..。
前面学过css选择器,要选择某个节点的后续兄弟节点,用波浪线。
xpath也能够选择后续兄弟节点,用这样的语法forllowing-sibling::。
好比,要选择class为single_choice的元素的全部后续兄弟节点//*[@class='single_choice']/forllowing-sibling::*。
等同于CSS选择器.single_choice ~ *
若是,要选择后续节点中的div节点,就应该这样写//*[@class='single_choice']/forllowing-sibling::div。
xpath还能够选择前面的兄弟节点,用这样的语法preceding-sibling::。
好比,要选择class为single_choice的元素的全部后续兄弟节点//*[@class='single_choice']/preceding-sibling::*。
而CSS选择器目前尚未选择前面的兄弟节点。
要了解更多Xpath选择语法,能够这里,打开Xpath选择器参考手册。
咱们来看一个例子
咱们的代码:
先选择示例网页中,id是china的元素。
而后经过这个元素的WebElement对象,使用find_elements_by_xpath,选择里面的p元素。
# 先寻找id是china的元素 china = wd.find_element_by_id('china') # 再选择该元素内部的p元素 elements = china.find_elements_by_xpath('//p') # 打印结果 for element in elements: print('----------------') print(element.get_attribute('outerHTML'))
运行发现,打印的 不单单是china内部的p元素,而是全部的p元素。
要在某个元素内部使用xpath选择元素,须要在xpath表达式最前面加个点。
像这样
elements = china.find_elements_by_xpath('.//p')