- 1. 介紹XPath和CssSelector
- 2. XPath有哪些方式
- 3. CssSelector有哪些方式
- 4. XPath和CssSelector的選擇
- 5. 定位的一些優化方法
- 6. 參考資料
本文鏈接: https://www.cnblogs.com/hchengmx/p/10755116.html
1. 介紹XPath和CssSelector
XPath: XPath 最初是用來在 XML 文檔中定位 DOM 節點的語言,由於 HTML 也可以算作 XML 的一種實現,所以 Selenium 也可以利用 XPath 這一強大的語言來定位 Web 元素。XPath 在傳統屬性定位之外擴展了諸如“定位第三個多選框”等定位能力,以便應對沒有 ID 或 name 屬性的情況。
CSS (Cascading Style Sheets) 是一種用於渲染 HTML 或者 XML 文檔的語言,CSS 利用其選擇器可以將樣式屬性綁定到文檔中的指定元素,即前端開發人員可以利用 CSS 設定頁面上每一個元素的樣式。所以理論上說無論一個元素定位有多復雜,既然開發人員能夠定位到並設置樣式,那么測試人員同樣應該也能定位繼而操作該元素。
多個 CSS 選擇器還可以用逗號拼接為一個組合選擇器,滿足任意其中一個選擇器的元素都會被該組合選擇器選中,逗號的前后允許出現空白。
所以 從工作機制來講:XPath使用路徑標記在XML文檔層次結構中進行導航,簡單說就是遍歷文檔路徑。Selector則是一種匹配模式,速度上優化於XPath。
2. XPath有哪些方式
2.1. 通過XPath語法
XPath = //tagname[@attribute='value']
- // 目前的節點
- tagname:想要選的節點的tag,input,div,img等, 但也經常被替換為*
- Attribute: 想要選擇節點的屬性
- Value: 屬性的值
用XPath選擇的其他例子:
Xpath=//input[@type='text']
Xpath= //label[@id='message23']
Xpath= //input[@value='RESET']
Xpath=//*[@class='barone']
Xpath=//a[@href='http://demo.guru99.com/']
Xpath= //img[@src='//cdn.guru99.com/images/home/java.png']
補充知識點2: 如何用XPath獲取該元素的父親:
public static IWebElement GetParent(this IWebElement element)
{
return element.FindElement(By.XPath(".."));
}
2.2. Contains關鍵字
適用於某個屬性動態的值變化, 但是其值總是包含什么特定的字符串。
//*[contains(@id,'message')]
2.3. Start-With
可以理解為contains的延申, 選擇某元素的值總是以XXX開頭
Xpath=//label[starts-with(@id,'message')]
2.4. Or和And關鍵字
用Or的話, 兩個條件其中之一為真則為真, 用And的話, 兩個條件均為真則真(個人用And多一點, 用來篩選元素)。
Xpath=//input[@type='submit' and @name='btnLogin']
2.5. Text()
適用於其內的text在頁面唯一的情況, 書寫起來也最簡單;
2.6. 軸方法
軸名稱 | 結果 |
---|---|
ancestor | 選取當前節點的所有先輩(父、祖父等)。 |
ancestor-or-self | 選取當前節點的所有先輩(父、祖父等)以及當前節點本身。 |
attribute | 選取當前節點的所有屬性。 |
child | 選取當前節點的所有子元素。 |
descendant | 選取當前節點的所有后代元素(子、孫等)。 |
descendant-or-self | 選取當前節點的所有后代元素(子、孫等)以及當前節點本身。 |
following | 選取文檔中當前節點的結束標簽之后的所有節點。 |
namespace | 選取當前節點的所有命名空間節點。 |
parent | 選取當前節點的父節點。 |
preceding | 選取文檔中當前節點的開始標簽之前的所有節點。 |
preceding-sibling | 選取當前節點之前的所有同級節點。 |
self | 選取當前節點。 |
eg:
Xpath=//*[@type='text']//following::input
Xpath=//*[@id='java_technologies']//child::li
Xpath=//*[text()='Enterprise Testing']//ancestor::div
Xpath=//*[@id='rt-feature']//parent::div
2.7. 補充知識點
2.7.1. 絕對路徑和相對路徑的區別
絕對路徑:以單斜杠 / 開頭, 表示選擇當前節點, 一般從根節點來選取元素, 通過這樣的XPath表達式特別長:
html/body/div[3]/div/div[2]
相對路徑:以雙斜杠 // 開頭,可以選擇頁面上的任何元素
2.7.2. XPath在不同瀏覽器上的區別
以下來自selenium官方文檔, 原文可以看這里。
從原理上來講, 每個瀏覽器都應該有自己的原生xpath方法,要是沒有的話,才會用selenium提供的方法。
具體區別如下:
Driver | Tag and Attribute Name | Native XPath Support |
---|---|---|
HtmlUnit Driver | Lower-cased | Yes |
Internet Explorer Driver | Lower-cased | No |
Firefox Driver | Case insensitive | Yes |
下面是一個例子:
<input type="text" name="example" />
<INPUT type="text" name="other" />
用代碼
List<WebElement> inputs = driver.findElements(By.xpath("//input"));
用幾個driver分別會找到下面幾個元素
XPath expression | HtmlUnit Driver | Firefox Driver(同chrome) | Internet Explorer Driver |
---|---|---|---|
//input | 1 (“example”) | 2 | 2 |
//INPUT | 0 | 2 | 0 |
3. CssSelector有哪些方式
3.1 類選擇器
語法: tag.class
eg:
div.ibm-alternate-rule
3.2 屬性選擇器
語法: css=tag[attribute=value], 更多包括通配符的例子可以看這里。
eg:
ul[role='tablist']
3.3 后代選擇器
詳細介紹可以看這里
語法:
tag1 tag2 //tag1的所有后代中的tag為tag2的
eg:
div.sidebar a //結合類選擇器使用, 找到屬性為div且class為sidebar的所有tag為a的后代
3.4 子元素選擇器
詳細介紹可以看這里
語義: 如果您不希望選擇任意的后代元素,而是希望縮小范圍,只選擇某個元素的子元素,請使用子元素選擇器
eg:
table.company td > p
上面的選擇器會選擇作為 td 元素子元素的所有 p 元素,這個 td 元素本身從 table 元素繼承,該 table 元素有一個包含 company 的 class 屬性。
3.4 偽類選擇器
動態偽類: 未被訪問/已被訪問/活動/獲得焦點
UI元素狀態偽類: 第n個孩子;
CSS3的:nth選擇器: element 狀態(禁用/啟用/被選中)
可以在這里 查看詳情。
4. XPath和CssSelector的選擇
根據Microsoft的推薦: 也是推薦CssSelector, 理由如下:
- Xpath在不同瀏覽器中會不同(Xpath engines are different in each browser)
- Xpath比較難閱讀(XPath can become complex and therefore more difficult to read)
- Css selector更快(CSS selectors are faster)
- Css是一種基於JQuery的定位策略(CSS is JQuery's locating strategy)
- IE沒有Xpath引擎(Internet Explorer does not have a native XPath engine)
CssSelector的劣勢:
- 無法找到某元素的父親元素(當然這種也很難遇到)
所以個人定位經驗總結:
- 首先考慮這個元素有無唯一的屬性, 比如id/name;
- 查看改元素有無唯一的text, 用CssSelector的text()定位;
- 這個元素是否為多個屬性, 多個屬性用And連接起來是否可能唯一, 用CssSelector的And關鍵字;
- 首選從這個元素的父親元素/祖宗元素, 有無唯一屬性, 善用CssSelector的后代選擇器和子元素選擇器;
- 使用約束, 用findelements(By.CssSelector("")).first(ele => ele.Text == "");
- 再復雜的我目前還沒見過;
5. 定位的一些優化方法
- 盡可能的不要用findelements
List<IWebElement> elements = driver.findelements(By.CssSelector(""));
element = elements.first()
- 盡量減少和服務的通信:
if(driver.findelements(By.CssSelector("li[role='radio']").Count() != 0)
{
driver.findelement(By.CssSelector("li[role='radio']")).click();
}
上面需要和driver通信兩次, 查找元素兩次, 可以考慮替換為下面的代碼。
var element = driver.findelement(By.CssSelector("li[role='radio']"))
if(element!=null)
{
element.click();
}