有關Selenium的介紹在網上實在是太多了,總結起來就是一個目前在web自動化方面運用最爲廣泛的一個開源自動化測試框架
1、Selenium架構
- client:每個語言都有自己的庫,提供不同的API供用戶去調用完成相關的自動化測試行爲;這裏調用有關web自動化的API到selenium的server
- selenium:用於將接收到的請求傳給瀏覽器的driver,實施調用,實際上selenium就是瀏覽器driver的一個封裝
- driver:針對瀏覽器的一個驅動引擎,每個瀏覽器都有自己的驅動(一般由各個瀏覽器廠商提供),可以通過驅動瀏覽器的API來完成對應操作
- browser:瀏覽器
2、Selenium核心組件
- selenium webdriver client (目前主要使用的,依賴於drivers)
- selenium drivers (瀏覽器驅動,被webdriver client 所依賴)
- selenium1 selenium-rc (已棄用)
- selenium IDE (入門錄製工具-本人不常用,僅瞭解過)
- selenium grid (可操縱瀏覽器集羣,也可操作App)
3、Selenium的安裝
3.1組件安裝:
- 安裝瀏覽器 :web自動化,沒瀏覽器好像說不過去了,先裝瀏覽器是必須的
- 安裝selenium driver,加入環境變量
path
:環境變量,老生常談的問題了 - 安裝selenium-client : 安裝到這步後就可以開始web自動化了,不同語言的根據需要進行安裝,如Java的可以使用
maven
,目前建議使用穩定版本的3.141.59:<dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>3.141.59</version> </dependency>
- 安裝selenium-ide : 新手入門,我在這裏就不去演示了,需要入門瞭解的小夥伴可以查閱資料哈~
3.2 ChromeDriver下載
我這裏主要用的是Chrome瀏覽器,所以就以Chrome爲例
1)先去到selenium官網的下載中心https://www.seleniumhq.org/download/;往下翻,翻到如下圖的位置:
2)進去後找到與你當前Chrome瀏覽器版本對應的driver版本,下載對應系統的driver(需要梯子,如果沒有繼續往下看)
如果你沒有梯子,無法去官網下載driver的話,這裏提供一個淘寶的鏡像,在國內的網絡就可以直接下載
https://npm.taobao.org/mirrors/chromedriver
3)下載完成後解壓到自己指定的路徑即可,別忘了將路徑添加到環境變量中(這裏以Mac爲例)
$ echo 'export PATH=$PATH:/Users/qinzhen/Documents/TestDev/WebAuto/webdrivers/chromedrivers/chrome_77/' >> ~/.bash_profile
$ tail -1 ~/.bash_profile
export PATH=$PATH:/Users/qinzhen/Documents/TestDev/WebAuto/webdrivers/chromedrivers/chrome_77/
4、元素定位
元素定位是做UI自動化最基礎也是最重要的部分之一了,算是web自動化的大門,推開這扇門走進web自動化的世界
4.1 推開大門,到達“犯罪現象”-認識元素
Selenium
的WebDriver
一共提供了九種定位方法,其中最常用的是前八種,先來看看在Java中的對應關係
定位方法 | 對應API | 說明 |
---|---|---|
id | By.id | 通過id號 |
class name | By.className | 通過class屬性值 |
tag name | By.tagName | 通過tag屬性值 |
name | By.name | 通過name屬性值 |
link text | By.linkText | 通過鏈接的文本信息 |
partial link text | By.partialLinkText | 通過部分匹配的鏈接文本信息 |
css | By.cssSelector | 通過CSS |
xpath | By.xpath | 通過xpath |
javascript | ((JavascriptExecutor)driver).executeScript | 通過執行JavaScript定位元素,返回WebElement對象 |
-
如上表所示,web自動化就是靠着HTML的各種標籤、屬性等來定位元素來進行操作,那麼這些定位方式怎麼理解?我們可以參考一個犯罪案例:
警察正在抓捕一名人犯罪嫌疑人,要確認犯罪嫌疑人的身份就可以根據嫌疑人的姓名、別名、指紋、身份證號、手機號等可識別區分的屬性;同樣的,元素自身也有
id
、classname
、tagname
、name
等屬性可用於區分定位;此嫌疑人的反偵察能力比較強,隱藏了自己的身份特徵,無法根據其自身的屬性進行定位,那麼就可以根據其經常出沒的場所來進行定位抓捕,例如去某省某市的某個酒吧裏,去某縣某村某號的一個住所去;同樣的,元素自身也可以通過
Xpath
和CSS
這種標籤的層級位置來定位元素。到目前爲止,嫌煩依然在逃,爲了躲避偵查,曾經的常去場所都不再接觸,高手!這是高手!苦苦的等待,最終辦案民警們終於有了線索(接下來該辦案民警出場講述轉機了~):由於犯罪嫌疑人是個大孝子且十分疼愛自己的妻兒,於是在某個地方偷偷的給父母通了電話,去學校見了妻兒;最終根據其家人提供的信息暴露自己,被定位抓獲!同樣的,元素也可以通過與其相關的元素來進行定位,我們就可以用
CSS
或Xpath
來進行父子,兄弟等節點位置的方式來進行定位了。
4.2 案件告破,案情總結-定位方法的使用
Warning! 下面在介紹各種定位方式的時候還會順便補充CSS的定位方式作爲對比,首次接觸的話可能會因爲看不懂而引起不適,不用擔心,可以先忽略,後面會專門介紹CSS的,待了解了CSS定位方式後再回來學習
4.2.1 By ID——身份證
- 現在我們要定位
testerhome
首頁右上角的歡迎
,如下圖:
- 打開Chrome開發者工具,選中元素進行查看,元素是有id的,可以根據id來定位:
WebDriver driver = new ChromeDriver(); driver.findElement(By.id("cornertip")); driver.findElement(By.cssSelector("#cornertip")); //CSS
小技巧:我們可以在Chrome
的開發者工具中Control+F
搜索框中對我們要定位的元素進行搜索來確認定位是否正確,支持CSS
和xpath
,如上圖所示
4.2.2 By Class Name——別名
- 要定位
testerhome
首頁的搜索框,就可以根據ClassName
,如下圖:
WebDriver driver = new ChromeDriver(); driver.findElement(By.className("form-control")); driver.findElement(By.cssSelector(".form-control")); //CSS
4.2.3 By Name——姓名
- 依然定位首頁的搜索框,可通過
name
和CSS
定位:
WebDriver driver = new ChromeDriver(); driver.findElement(By.className("q")); driver.findElement(By.cssSelector("[name='q']")); //CSS
4.2.4 By Tag Name
- 依然是定位
testerhome
首頁的搜索框,通過tagname
:input
來定位
WebDriver driver = new ChromeDriver(); driver.findElement(By.tagName("input")); driver.findElement(By.cssSelector("input")); //CSS
4.2.5 By Link Text
- 定位testerhome首頁一週最熱的帖子,通過
linktest
和CSS
:
WebDriver driver = new ChromeDriver(); driver.findElement(By.linkText("[深圳][頭條] 招聘測試 leader")); driver.findElement(By.cssSelector("a[title='[深圳][頭條] 招聘測試 leader']")); //CSS
4.2.6 By Partial Link Text
- 定位
testerhome
首頁一週最熱的帖子,通過partialLinkText
和CSS
WebDriver driver = new ChromeDriver();
driver.findElement(By.partialLinkText("[深圳][頭條]"));
driver.findElement(By.cssSelector("[title~='[深圳][頭條]']")); /CSS
4.2.7 Using JavaScript
有時候我們的頁面元素被遮擋導致無法定位,需要滾動屏幕進行可視化,便可以用JS來操作:
((JavascriptExecutor)(driver)).executeScript("window.scroll(0, 1200)");
4.2.8 By Xpath
XPath
是一門在 XML 文檔中查找信息的語言。XPath
可用來在XML
文檔中對元素和屬性進行遍歷,而HTML
又正好可以看做是XML
的一種實現,因此我們便可以用xpath
來定位元素啦
-
問題:一般剛開始學定位的時候很多人都會想,都有了上面那麼多種定位方式了,還要
xpath
幹嗎?感覺還挺複雜的樣子(和其他的定位方式相比卻是要複雜那麼一丟丟)~
答: 那是因爲並不是所有的元素都“如您所願”,就如上面警察抓捕罪犯的例子,有時候元素並不能直接提供給我們想要的定位屬性 -
常用路徑表達式:
表達式 描述 nodename 選取此節點的所有子節點。 / 從根節點選取。 // 從匹配選擇的當前節點選擇文檔中的節點,而不考慮它們的位置。 . 選取當前節點。 … 選取當前節點的父節點。 @ 選取屬性。 -
舉幾個簡單的栗子
1)絕對路徑定位做測試開發或者有編程經驗的小夥伴一定對絕對路徑不陌生,通過絕對路徑就是使用元素在頁面上的完整路徑、
還是以定位一週內的最熱門帖子爲例,在Chrome瀏覽器的開發者工具欄中,找到要定位元素的HTML位置,右擊會出現
Copy full Xpath
,點擊它
然後我們把複製到的內容黏貼後如下:/html/body/div[2]/div[2]/div/div[2]/div[1]/div[2]/div[1]/div/a
寫到代碼裏就是這樣:
WebDriver driver = new ChromeDriver(); driver.findElement(By.xpath("/html/body/div[2]/div[2]/div/div[2]/div[1]/div[2]/div[1]/div/a"));
可以用又臭又長來形容了,那麼細心的小夥伴會發現還有一個
Copy xpath
,複製黏貼後內容如下://*[@id="main"]/div/div[2]/div[1]/div[2]/div[1]/div/a
看起來好像簡化了點,還用上了
xpath
的語法,但是實際上也沒優化多少,依然是通過標籤的層級關係,從最外層一級一級的往下找,也不是很可取;其實不可取的最主要原因還是這種
絕對路徑
的方式在實際自動化過程中很不穩定,界面的位置發生任何一丟丟的變化,那元素的絕對路徑就很可能變了,也就無法準確定位了。因此我們就要用
元素的屬性
或者屬性和層級關係
相結合的方式來定位,這樣就算頁面變化,只要變化不是非常大,依然可以通過元素的屬性和相對的位置來進行定位,受頁面位置變化的影響就要小的多了
2)元素屬性定位
- 定位
testerhome
首頁的歡迎
,利用xpath
語法通過id
來定位:
語法解釋:WebDriver driver = new ChromeDriver(); driver.findElement(By.xpath("//div[@id='c-button']"));
//div
表示從當前頁面的div
標籤開始匹配,@id
表示用id屬性值,=
後面跟着具體的id
值
3)屬性和層級關係定位
上面的通過屬性定位完全可以用WebDriver
的API
或者CSS
搞定,xpath
最大的價值就是上面說的當元素沒有直接可定位的屬性時,它的價值才得以完美體現:
- 現在我們要定位”
七日最熱 Top10
“這個標題,它只有class
屬性,我們按照className
來進行定位會發現如下情況:
沒錯,出現了10個可被定位到的元素,因爲有很多的標題都有相同的classname
,並且沒有其他如id
,name
等屬性了;
沒辦法了,我們就要往上找,我們發現往上2個div
標籤節點,classname
爲”col-md-3 home-side-bar
“的標籤節點是唯一的:
現在我們就利用Xpath
先定位到唯一的那個class
,然後往下找兩層div
,再取兩層後div
中的第一個就可以了
WebDriver driver = new ChromeDriver(); driver.findElement(By.xpath("//*[@class='col-md-3 home-side-bar']/div[1]/div[1]"));
4)使用Xpath運算符定位
Xpath還支持運算符,如果元素的一個屬性無法定位,需要使用多個屬性時可以使用Xpath運算符將多個屬性連接起來一起定位
-
Xpath常用運算符
運算符 描述 實例 返回值 |
計算兩個節點集 //book | //cd
返回所有擁有 book 和 cd 元素的節點集 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。 -
現在需要定位
testhome
社區首頁一篇最新帖子的作者,作者名爲“烏雲烏雲快走開”
如果我們只依靠className
的話會發現有28個相同屬性的元素,如下圖:
繼續觀察會發現還有一個叫做data-name
的屬性,屬性值就是作者的姓名,我們通過and符將兩個屬性連接後便發現可以精準定位到指定元素了:
WebDriver driver = new ChromeDriver(); driver.findElement(By.xpath("//a[@class='user-name' and @data-name='烏雲烏雲快走開']"));
5)使用Xpath函數定位
Xpath還提供了很多函數來供我們更靈活的定位,這裏以我常用的一個contains
函數爲例
- 我們依舊來定位
testerhome
首頁七日最熱貼的首貼“[深圳][頭條] 招聘測試 leader”,通過對DOM的分析可以看到title
屬性的內容就是帖子的標題,我們用此屬性值的一部分來作爲定位條件:
WebDriver driver = new ChromeDriver(); driver.findElement(By.xpath("//*[contains(@title,'[深圳][頭條]')]"));
關於Xpath的語法使用還有很多,包括還有很多函數,具體的可參考W3C進行學習:
https://www.w3school.com.cn/xpath/xpath_syntax.asp
4.2.9 By CSS
Web頁面的樣式通常保存在外部的 .css 文件中。通過僅僅編輯一個簡單的 CSS 文檔,外部樣式表使你有能力同時改變站點中所有頁面的佈局和外觀。因此我們可以利用CSS的選擇器來定位頁面綁定了屬性的元素,從而爲我們的selenium所用
從上面的文章一路看下來的小夥伴應該發現了,在介紹xpath
之前的定位方式時,都另外還寫了一個CSS
的定位方式,沒錯,就是它,沒注意的小夥伴可以返回去看一看;
推薦使用CSS:
CSS
也是我們在Web自動化中最推薦使用的一種方式,原因又如下幾種:
- 例如
id
這種元素在一個頁面中可能並不唯一,並且很有可能是前端的框架自動生成的,研發人員並未對其進行維護,隨時可能變;而CSS
是前端開發最常用的一種維護方式,對於我們開發和維護自動化用例也更爲清晰和方便 - 大部分定位都可以用
CSS
來解決 CSS
的寫法相較於Xpath
要更爲簡潔
常用的CSS選擇器語法:
選擇器 | 例子 | 例子描述 |
---|---|---|
.class | .intro | 選擇 class=“intro” 的所有元素。 |
#id | #firstname | 選擇 id=“firstname” 的所有元素。 |
* | * | 選擇所有元素。 |
element | p | 選擇所有 <p> 元素。 |
element,element | div,p | 選擇所有 <div> 元素和所有 <p> 元素。 |
element element | div p | 選擇 <div> 元素內部的所有 <p> 元素。 |
element>element | div>p | 選擇父元素爲 <div> 元素的所有 <p> 元素。 |
element+element | div+p | 選擇緊接在 <div> 元素之後的所有 <p> 元素。 |
[attribute] | [target] | 選擇帶有 target 屬性所有元素。 |
[attribute=value] | [target=_blank] | 選擇 target="_blank" 的所有元素。 |
[attribute~=value] | [title~=flower] | 選擇 title 屬性包含單詞 “flower” 的所有元素。 |
先將前面已經演示過的CSS
語法在這來個小的彙總:
- 通過
id
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector("#cornertip")); //CSS
- 通過
className
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector(".form-control"));
- 通過
name
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector("[name='q']"));
- 通過
tag name
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector("input"));
- 通過
link text
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector("a[title='[深圳][頭條] 招聘測試 leader']"));
- 通過
partialLinkText
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector("[title~='[深圳][頭條]']"));
- 另外CSS也可以將屬性和層級關係組合在一起進行使用,現在我們以這種組合方式來定位testerhome社區置頂帖的第一篇帖子:
WebDriver driver = new ChromeDriver();
driver.findElement(By.cssSelector(".panel-heading+div>div>div.topic-20857"));
簡要說明:
.panel-heading
:class值爲panel-heading
+div
: 後面緊接着的div
>div
:後面所有子的div
div.topic-20857
:class名爲topic-20857的div標籤
更多細節和用法可參考W3C進行學習:
https://www.w3school.com.cn/cssref/css_selectors.asp
參考文檔:
selenium官網:https://www.seleniumhq.org/docs/03_webdriver.jsp