我們在做Web自動化測試時,最根本的就是操作頁面上的元素。因此我們對元素的定位是最基礎的工作,只有準確的定位到對應元素,才能進行後續的自動化控制,也就時操作這些元素。
我們之前用了好幾篇文章,介紹在Selenium中如何進行元素的定位:
- 基本元素定位:https://www.cnblogs.com/liuyuelinfighting/p/14925556.html
- By類定位:https://www.cnblogs.com/liuyuelinfighting/p/14952281.html
- XPath定位:https://www.cnblogs.com/liuyuelinfighting/p/14943233.html
- CSS選擇器定位:https://www.cnblogs.com/liuyuelinfighting/p/14950596.html
這也同時說明了在自動化測試中,元素定位是非常重要且必須掌握的技能。那麼本篇文章是對Selenium中進行元素定位的歸納總結。
1、Selenium中8種基本元素定位方式
提示:基本元素定位方式,可以結合前面文章【Selenium基本元素定位】一起看,有詳細說明。
(1)單數形式
# webdriver提供的基本元素定位方法。
# 1. 通過元素的id屬性進行定位。
find_element_by_id("id屬性值")
# 2. 通過元素的name屬性進行定位。
find_element_by_name("name屬性值")
# 3. 通過元素的class屬性進行定位。
find_element_by_class_name("class屬性值")
# 4.通過元素標籤進行定位。
find_element_by_tag_name("標籤名")
# 5. 通過超連結中全部文字定位超連結。
find_element_by_link_text("完整超連結文字")
# 6. 通過超連結中部分連續文字定位超連結。
find_element_by_partial_link_text("部分超連結文字")
# 7. 通過XPath定位元素。
find_element_by_xpath("XPath路徑表示式")
# 8. 通過css選擇器定位元素。
find_element_by_css_selector("css選擇器定位策略")
(2)複數形式
# webdriver提供的基本元素定位方法。
# 1. 通過元素的id屬性進行定位。
find_elements_by_id("id屬性值")
# 2. 通過元素的name屬性進行定位。
find_elements_by_name("name屬性值")
# 3. 通過元素的class屬性進行定位。
find_elements_by_class_name("class屬性值")
# 4.通過元素標籤進行定位。
find_elements_by_tag_name("標籤名")
# 5. 通過超連結中全部文字定位超連結。
find_elements_by_link_text("完整超連結文字")
# 6. 通過超連結中部分連續文字定位超連結。
find_elements_by_partial_link_text("部分超連結文字")
# 7. 通過XPath定位元素。
find_elements_by_xpath("XPath路徑表示式")
# 8. 通過css選擇器定位元素。
find_elements_by_css_selector("css選擇器定位策略")
2、By類定位的8種定位方式
提示:By類定位元素,可以結合前面文章【使用Seleniun中的By類定位元素】一起看,有詳細說明。
(1)單數形式
# 1. 通過元素的id屬性進行定位。
# ("id"," ")
find_element(By.ID, "id屬性值")
# 2. 通過元素的name屬性進行定位。
# ("name", " ")
find_element(By.NAME, "name屬性值")
# 3. 通過元素的class屬性進行定位。
# ("class name", " ")
find_element(By.CLASS_NAME, "class屬性值")
# 4.通過元素標籤進行定位。
# ("tag name", " ")
find_element(By.TAG_NAME, "標籤名")
# 5. 通過超連結中全部文字定位超連結。
# ("link text", " ")
find_element(By.LINK_TEXT, "完整超連結文字")
# 6. 通過超連結中部分連續文字定位超連結。
# ("partial link text", " ")
find_element(By.PARTIAL_LINK_TEXT, "部分超連結文字")
# 7. 通過XPath定位元素。
# ("xpath", " ")
find_element(By.XPATH, "XPath路徑表示式")
# 8. 通過css選擇器定位元素。
# ("css selector", " ")
find_element(By.CSS_SELECTOR, "css選擇器定位策略")
(2)複數形式
# 1. 通過元素的id屬性進行定位。
# ("id"," ")
find_elements(By.ID, "id屬性值")
# 2. 通過元素的name屬性進行定位。
# ("name", " ")
find_elements(By.NAME, "name屬性值")
# 3. 通過元素的class屬性進行定位。
# ("class name", " ")
find_elements(By.CLASS_NAME, "class屬性值")
# 4.通過元素標籤進行定位。
# ("tag name", " ")
find_elements(By.TAG_NAME, "標籤名")
# 5. 通過超連結中全部文字定位超連結。
# ("link text", " ")
find_elements(By.LINK_TEXT, "完整超連結文字")
# 6. 通過超連結中部分連續文字定位超連結。
# ("partial link text", " ")
find_elements(By.PARTIAL_LINK_TEXT, "部分超連結文字")
# 7. 通過XPath定位元素。
# ("xpath", " ")
find_elements(By.XPATH, "XPath路徑表示式")
# 8. 通過css選擇器定位元素。
# ("css selector", " ")
find_elements(By.CSS_SELECTOR, "css選擇器定位策略")
3、XPath定位總結
提示:
- 使用XPath定位元素,可以結合前面文章【XPath路徑表示式介紹】、【Selenium中使用XPath定位元素】、【XPath軸定位詳解】一起看,有詳細說明。
- 關於更多的XPath定位內容,請檢視XPath的文件:http://www.w3school.com.cn/xpath/index.asp。
頁面程式碼片段:
<bookstore id='zc'>
<book id='b1'>
<title lang="eng">Harry Potter</title>
<price>29.99</price>
</book>
<book id='b2'>
<title lang="eng">Learning XML</title>
<price>39.95</price>
</book>
</bookstore>
(1)基礎定位語法
XPath 使用路徑表示式在 XML 文件中選取節點。節點是通過沿著路徑或者 step
(步) 來選取的。
下面列出了最常用的路徑表示式:
表示式 | 描述 |
---|---|
nodename |
選取此節點的所有子節點。 |
/ |
從根節點選取。 |
// |
從匹配選擇的當前節點選擇文件中的節點,而不考慮它們的位置。 |
. |
選取當前節點。 |
.. |
選取當前節點的父節點。 |
@ |
選取屬性。 |
示例:
路徑表示式 | 說明 |
---|---|
bookstore |
選取 bookstore 元素的所有子節點。 |
/bookstore |
選取根元素 bookstore 。註釋:假如路徑起始於正斜槓(/ ),則此路徑始終代表到某元素的絕對路徑! |
bookstore/book |
選取屬於 bookstore 的子元素的所有 book 元素。 |
//book |
選取所有 book 子元素,而不管它們在文件中的位置。 |
bookstore//book |
選擇屬於 bookstore 元素的後代的所有 book 元素,而不管它們位於 bookstore 之下的什麼位置。 |
//@lang |
選取名為 lang 的所有屬性。 |
(2)屬性定位語法
路徑表示式 | 說明 |
---|---|
//標籤名[@屬性值=屬性名] |
語法格式說明 |
//title[@lang] |
選取所有擁有名為 ang 的屬性的 title 元素。 |
//title[@lang='eng'] |
選取所有 title 元素,且這些元素擁有值為 eng 的 lang 屬性。 |
(3)層級定位語法
路徑表示式 | 說明 |
---|---|
//父標籤名[@父標籤屬性名='屬性值']/子標籤 |
最終定位的是子標籤 |
//book[@id='b1']/title |
定位id 屬性為b1 的book 標籤下的title 標籤 |
//bookstore[@id='zc']/book[@id='b1']/title |
以此類推,可以增加多層 |
(4)索引定位語法
路徑表示式 | 說明 |
---|---|
//bookstore/book |
定位到bookstore 標籤下所有book 子節點 |
//bookstore/book[1] |
選取屬於bookstore 子元素的第一個book 元素。 |
//bookstore/book[last()] |
選取屬於 bookstore 子元素的最後一個book 元素。 |
//bookstore/book[last()-1] |
選取屬於bookstore 子元素的倒數第二個book 元素。 |
//bookstore/book[last()-n] |
選取屬於bookstore 子元素的倒數第n個book 元素。 |
//bookstore/book[position()=2] |
定位到結果集中第n個節點。 |
//bookstore/book[position()<3] |
選取最前面的兩個屬於bookstore 元素的子元素的book 元素。 |
//bookstore/book[position()>3] |
定位到結果集中索引大於n的節點。 |
(6)邏輯定位語法
XPath可以支援定位條件的與(and
)、或(or
)、非(not
)。(我們絕大部分都使用and
)
路徑表示式 | 說明 |
---|---|
//標籤名[@屬性名1='屬性值1'and@屬性名2=屬性值2] |
使用多屬性定位元素 |
input[@type='text'and@name='user'and@class='login-test'] |
and 表示多定位條件同時匹配 |
input[@name='user'or@class='login-test'] |
or 表示定位條件有一個匹配即可 |
//book[not(@id='b1')] |
not() 方法表示條件取反 |
//input[@type='submit' and not(contains(@name,'fuck'))] |
not() 方法練習 |
(6)模糊定位語法
XPath 萬用字元可用來選取未知的 XML 元素。
萬用字元 | 描述 |
---|---|
* |
匹配任何元素節點。 |
@* |
匹配任何屬性節點。 |
node() |
匹配任何型別的節點。 |
示例:
在下面的表格中,我們列出了一些路徑表示式,以及這些表示式的結果:
路徑表示式 | 說明 |
---|---|
//bookstore/* |
選取 bookstore 元素的所有子元素。 |
/* |
匹配絕對路徑最外層元素 |
//* |
選取頁面中的所有元素。 |
//title[@*] |
選取所有帶有屬性的 title 元素。 |
//*[@*] |
匹配所有有屬性的節點(屬性模糊查詢使用很少) |
/bookstore/node()/title |
匹配bookstore 節點所有孫子輩的title節點,代表任意節點名。 |
(7)其他定位語法
1)其他常用定位
路徑表示式 | 說明 |
---|---|
//*[text()=“xxx”] |
標籤之間的文字內容是xxx的元素 |
//*[contains(@attribute,’xxxxx’)] |
屬性值中含有xxx的元素 |
//*[starts-with(@attribute,’xxx’)] |
屬性值以xxx開頭的元素 |
2)選取若干路徑
通過在路徑表示式中使用|
運算子,您可以選取若干個路徑。
例項:
路徑表示式 | 結果 |
---|---|
//book/title | //book/price |
選取book 元素的所有 title 和 price 元素。 |
//title | //price |
選取文件中的所有 title 和 price 元素。 |
/bookstore/book/title | //price |
選取屬於 bookstore 元素的 book 元素的所有 title 元素,以及文件中所有的 price 元素。 |
3).
和..
路徑表示式 | 說明 |
---|---|
/bookstore/book/title/./.. |
使用.定位到title 本身,再使用..定位到title的父節點book |
/bookstore/book/title/./../price |
上邊過程後,再定位到price 子節點 |
4)XPath 表示式中的運算子
運算子 | 描述 | 示例 | 返回值 |
---|---|---|---|
| |
計算兩個節點集 | //book | //cd |
返回所有擁有 book 和 cd 元素的節點集 |
+ |
加法 | 6 + 4 |
10 |
- |
減法 | 6 - 4 |
2 |
* |
乘法 | 6 * 4 |
24 |
div |
除法 | 8 div 4 |
2 |
= |
等於 | price=9.80 |
如果 price 是 9.80,則返回 true。如果 price 是 9.90,則返回 false。 |
!= |
不等於 | price!=9.80 |
如果 price 是 9.90,則返回 true。如果 price 是 9.80,則返回 false。 |
< |
小於 | price<9.80 |
如果 price 是 9.00,則返回 true。如果 price 是 9.90,則返回 false。 |
<= |
小於或等於 | price<=9.80 |
如果 price 是 9.00,則返回 true。如果 price 是 9.90,則返回 false。 |
> |
大於 | price>9.80 |
如果 price 是 9.90,則返回 true。如果 price 是 9.80,則返回 false。 |
>= |
大於或等於 | price>=9.80 |
如果 price 是 9.90,則返回 true。如果 price 是 9.70,則返回 false。 |
or |
或 | price=9.80 or price=9.70 |
如果 price 是 9.80,則返回 true。如果 price 是 9.50,則返回 false。 |
and |
與 | price>9.00 and price<9.90 |
如果 price 是 9.80,則返回 true。如果 price 是 8.50,則返回 false。 |
mod |
計算除法的餘數 | 5 mod 2 |
1 |
用於XPath定位中的示例:
路徑表示式 | 說明 |
---|---|
/bookstore/book[price>35.00] |
選取 bookstore 元素的所有 book 元素,且其中的 price 元素的值須大於 35.00。 |
/bookstore/book[price>35.00]/title |
選取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值須大於 35.00。 |
4、CSS選擇器定位總結
提示:
- CSS選擇器定位元素,可以結合前面文章【使用CSS選擇器定位元素】一起看,有詳細說明。
- 關於更多的CSS選擇器定位內容,請檢視CSS選擇器文件:https://www.w3school.com.cn/cssref/css_selectors.asp。
(1)屬性定位
CSS選擇器策略 | 示例 | 說明 |
---|---|---|
#id |
#telA |
選擇id="telA" 的所有元素。 |
.class |
.telA |
選擇 class="telA” 的所有元素。 |
[屬性名=屬性值] |
[name=telA] |
除了id 和class 屬性,其他屬性的定位格式 |
[attribute] |
[target] |
選擇帶有target 屬性所有元素。 |
* |
* |
選擇所有元素。 |
(2)屬性值模糊匹配定位
CSS選擇器策略 | 示例 | 說明 |
---|---|---|
[attribute^=value] |
a[src^="https"] |
選擇其src 屬性值以"https”開頭的每個<a> 元素。 |
[attribute$=value] |
a[src$=".pdf"] |
選擇其src屬性以".pdf“結尾的所有<a> 元素。 |
[attribute*=value] |
a[src*="abc"] |
選擇其src 屬性中包含“abc"子串的每個<a> 元素。 |
[attribute~=value] |
a[title~=flower] |
定位標籤屬性title值中有獨立flower詞彙的節點 |
[attribute|=value] |
a[lang|=en] |
用於選取帶有以指定值開頭的屬性值的元素。 |
注意:
[attribute|=value]
該值必須是整個單詞,比如
lang="en"
,或者後面跟著連字元,比如lang="en-us"
。
(3)標籤定位
CSS選擇器策略 | 示例 | 說明 |
---|---|---|
element |
p |
定位所有<p> 元素。 |
標籤名[屬性名=屬性值] |
input#telA |
定位id 屬性值為telA 的所有<input> 元素 |
(4)層級關係定位
CSS選擇器策略 | 示例 | 說明 |
---|---|---|
element,element |
div,p |
選擇所有<div> 元素和所有 <p> 元素。 |
element element |
div p |
選擇 <div> 元素內部的所有 <p> 元素。包括子孫後代。 |
element>element |
div>p |
選擇父元素為 <div> 元素的所有 <p> 元素。只包括子代。 |
element+element |
div+p |
選擇緊接在 <div> 元素之後的所有 <p> 元素。同輩元素。 |
示例:
CSS選擇器策略 | 示例 | 說明 |
---|---|---|
需要使用 > 或 空格表示層級關係 | 此行為語法說明 | |
父標籤名[父標籤屬性名=屬性值]>子標籤名 |
p#p1>input |
定位id 屬性值為p1 的<input> 元素 |
父標籤名[父標籤屬性名=屬性值] 子標籤名 |
p#p1 input |
同上 |
(5)索引定位
CSS選擇器策略 | 示例 | 說明 |
---|---|---|
:only-child |
p:only-child |
選擇屬於其父元素的唯一子元素的每個 <p> 元素。 |
:nth-child(n) |
p:nth-child(2) |
選擇屬於其父元素的第二個子元素的每個 <p> 元素。 |
:nth-last-child(n) |
p:nth-last-child(2) |
同上,從最後一個子元素開始計數。 |
:nth-of-type(n) |
p:nth-of-type(2) |
選擇屬於其父元素第二個 <p> 元素的每個 <p> 元素。 |
:nth-last-of-type(n) |
p:nth-last-of-type(2) |
同上,但是從最後一個子元素開始計數。 |
(6)邏輯運算定位
CSS選擇器策略 | 示例 | 說明 |
---|---|---|
標籤名[屬性名1=屬性值1][屬性名2=屬性值2] |
input[type='telA'][placeholder='電話A'] |
同時匹配多個屬性,無需寫and 關鍵字 |
(7)元素狀態定位
CSS選擇器策略 | 示例 | 說明 |
---|---|---|
:empty |
p:empty |
選擇沒有子元素的每個 <p> 元素(包括文字節點)。 |
:target |
#news:target |
選擇當前活動的 #news 元素。 |
:enabled |
input:enabled |
選擇每個啟用的 <input> 元素。 |
:disabled |
input:disabled |
選擇每個禁用的 <input> 元素 |
:checked |
input:checked |
選擇每個被選中的 <input> 元素。 |
:not(selector) |
:not(p) |
選擇非 <p> 元素的每個元素。 |
5、總結
-
如果元素有明確
id
,name
,class
屬性時,使用對應的基本定位方法。 -
如果沒有
id
,name
,class
屬性時,或id
,name
,class
屬性是動態/不唯一的時候,使用XPath
和CSS Selector
定位。 -
定位頁面超連結使用
link_text
和partial_link_text
定位 -
可使用
XPath
和CSS Selector
定位的時候,優先使用CSS Selector
。CSS Selector
定位的速度和效率比XPath
高。 -
沒有最好的,只有最精簡的,怎麼簡單怎麼來。
擴充套件:為什麼
CSS Selector
定位的速度和效率比XPath
高?
結論:因為你無論用那種方式定位,最終都會轉換到CSS Selector
進行元素定位。
我們可以在PyCharm中,安裝ctrl
點選對應的方法,進行檢視原始碼,最終都會定位到如下程式碼:
def find_element(self, by=By.ID, value=None):
"""
Find an element given a By strategy and locator. Prefer the find_element_by_* methods when
possible.
:Usage:
element = driver.find_element(By.ID, 'foo')
:rtype: WebElement
"""
if self.w3c:
if by == By.ID:
by = By.CSS_SELECTOR
value = '[id="%s"]' % value
elif by == By.TAG_NAME:
by = By.CSS_SELECTOR
elif by == By.CLASS_NAME:
by = By.CSS_SELECTOR
value = ".%s" % value
elif by == By.NAME:
by = By.CSS_SELECTOR
value = '[name="%s"]' % value
return self.execute(Command.FIND_ELEMENT, {
'using': by,
'value': value})['value']
說明:可以看到上面程式碼中的if語句中,所有用到的定位方式,最後都轉為對應的
CSS Selector
定位。
提示:我們也可以通過
js
和jQuery
進行元素的定位,但推薦用以上總結的方式進行元素定位。