前面咱們學習了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')