第一章 Selenium 概述
1.1.Selenium 發展史
Selenium是一系列基於Web的自動化工具,提供一套測試函數,用於支持Web自動化測試。函數非常靈活,能夠完成界面元素定位、窗口跳轉、結果比較。具有如下特點:
- 多瀏覽器支持
- 如IE、Firefox、Safari、Chrome、Android手機瀏覽器等。
- 支持多語言
- 如Java、C#、Python、Ruby、PHP等。
- 支持多操作系統
- 如Windows、Linux、IOS、Android等。
- 開源免費
Selenium框架由多個工具組成,包括:Selenium IDE,Selenium RC,Selenium WebDriver和SeleniumRC。
發展到如今 Selenium 已經發布到了 3.0 版本了,以下是簡單總結發展過程以及一些變化:
- Selenium 1.0
Jason Huggins在2004年發起的 Selenium 項目,使用 JavaScript 編寫的一個類庫,這個 JavaScript 類庫就是Selenium core,同時也是seleniumRC、Selenium IDE的核心組件。Selenium由此誕生。
- Selenium 2.0
因為Selenium和Webdriver的合並,所以,Selenium 2.0由此誕生。
簡單用公式表示為:Selenium 2.0 = Selenium 1.0 + WebDriver
需要強調的是,在Selenium 2.0中主推的是WebDriver,可以將其看作Selenium RC的替代品。因為Selenium為了保持向下的兼容性,所以在Selenium 2.0中並沒有徹底地拋棄Selenium RC。
所以,我們在學習Selenium2.0的時候,核心是學習WebDriver。它的工作原理是這樣的:
-
Selenium 3.0
Selenium 3.0做了一些不大不小的更新:
-
1、終於去掉了RC,簡單用公式表示為:Selenium 3.0 = Selenium 2.0 - Selenium RC(Remote Control)
-
2、Selenium3.0只支持Java8版本以上。
-
3、Selenium3.0中的Firefox瀏覽器驅動獨立了,以前裝完selenium2就可以驅動Firefox瀏覽器了,現在和Chrome一樣,必須下載和設置瀏覽器驅動。
-
4、MAC OS 集成Safari的瀏覽器驅動。默認在/usr/bin/safaridriver 目錄下。
-
5、只支持IE 9.0版本以上。
-
1.2.Selenium WebDriver原理
將 WebDriver 驅動瀏覽器類比成開出租車的場景。
在開出租車時有三個角色:
-
乘客:他/她告訴出租車司機去哪里,大概怎么走。
-
出租車司機:他按照乘客的要求來操控出租車。
-
出租車:出租車按照司機的操控完成真正的行駛,把乘客送到目的地。
在WebDriver中也有類似的三個角色:
- 工程師寫的自動化測試代碼:自動化測試代碼發送請求給瀏覽器的驅動(比如火狐驅動、谷歌驅動)
- 瀏覽器的驅動:它來解析這些自動化測試的代碼,解析后把它們發送給瀏覽器
- 瀏覽器:執行瀏覽器驅動發來的指令,並最終完成工程師想要的操作。
第二章 Selenium 環境搭建
2.1.java 環境
想要通過 java 語言來使用 selenium 框架,前提要完成 jdk 環境的安裝。
詳細安裝教程見:https://blog.csdn.net/shengmer/article/details/78836255
2.2.selenium 環境
簡單 java 工程:
直接導入 selenium的 jar 包就可以了。
jar包下載地址: Selenium各個版本jar下載 , 下載對應的版本即可
maven工程:
在pom文件中引入對應的依賴即可:
maven倉庫:https://mvnrepository.com/
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.4.0</version>
</dependency>
2.3.selenium3 對應瀏覽器驅動下載
當selenium升級到3.0之后,對不同的瀏覽器驅動進行了規范。如果想使用selenium驅動不同的瀏覽器,必須單獨下載並設置不同的瀏覽器驅動。
各瀏覽器下載地址:
-
Firefox瀏覽器驅動:geckodriver
-
Chrome瀏覽器驅動:chromedrivertaobao備用地址
-
IE瀏覽器驅動:IEDriverServer
-
Edge瀏覽器驅動:MicrosoftWebDriver
-
Opera瀏覽器驅動:operadriver
-
PhantomJS瀏覽器驅動:phantomjs
注:部分瀏覽器驅動地址需要梯子。
設置瀏覽器驅動
設置瀏覽器的地址非常簡單。 我們可以手動創建一個存放瀏覽器驅動的目錄,如: C:\driver , 將下載的瀏覽器驅動文件(例如:chromedriver、geckodriver)丟到該目錄下。
我的電腦–>屬性–>系統設置–>高級–>環境變量–>系統變量–>Path,將“C:\driver”目錄添加到Path的值中。
驗證瀏覽器驅動
驗證不同的瀏覽器驅動是否正常使用。
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.edge.EdgeDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.openqa.selenium.opera.OperaDriver;
import org.openqa.selenium.phantomjs.PhantomJSDriver;
WebDriver driver = new ChromeDriver(); //Chrome瀏覽器
WebDriver driver = new FirefoxDriver(); //Firefox瀏覽器
WebDriver driver = new EdgeDriver(); //Edge瀏覽器
WebDriver driver = new InternetExplorerDriver(); // Internet Explorer瀏覽器
WebDriver driver = new OperaDriver(); //Opera瀏覽器
WebDriver driver = new PhantomJSDriver(); //PhantomJS
第三章 Selenium 簡單示例
- 打開百度進行搜索:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
/**
* @Description: 通過selenium操作瀏覽器打開百度進行搜索
* selenium版本:3.12.0; 通過maven管理jar包
* 開發工具:IDEA
* jdk:1.8
* 瀏覽器:chrome 75+
* @Author: ggf
* @Date: 2020/03/22
*/
public class BaiduSearch {
public static void main(String[] args) {
// 1.創建webdriver驅動
WebDriver driver = new ChromeDriver();
// 2.打開百度首頁
driver.get("https://www.baidu.com");
// 3.獲取輸入框,輸入selenium
driver.findElement(By.id("kw")).sendKeys("selenium");
// 4.獲取“百度一下”按鈕,進行搜索
driver.findElement(By.id("su")).click();
// 5.退出瀏覽器
driver.quit();
}
}
第四章 八大元素定位
-
為什么要進行元素定位?
我們必須告訴 selenium 怎么去定位元素,用來模擬用戶的動作,或者查看元素的屬性和狀態,以便於我們可以執行檢查。例如:我們要搜索一個產品,首先要找到搜索框與搜索按鈕,接着通過鍵盤輸入要查詢的關鍵字,最后鼠標單擊搜索按鈕,提交搜索請求。
正如上述的人工操作步驟一樣,我們也希望 selenium 能模擬這樣的動作,然而,selenium 並不能理解類似在搜索框中輸入關鍵字或者點擊搜索按鈕這樣的圖形化的操作。所以需要我們程序化的告訴 selenium 如何定位搜索框和搜索按鈕,從而模擬鍵盤和鼠標的操作。
4.1.定位方式
selenium 提供了8種的定位方式:
- id
- name
- class name
- tag name
- link text
- partial link text
- xpath
- css selector
這8種定位方式在java selenium 中對應的方法為:
方法 | 描述 | 參數 | 示例 |
---|---|---|---|
findElement(By.id()) | 通過元素的 id 屬性值來定位元素 | 對應的id屬性值 | findElement(By.id("kw")) |
findElement(By.name()) | 通過元素的 name 屬性值來定位元素 | 對應的name值 | findElement(By.name("user")) |
findElement(By.className()) | 通過元素的 class 名來定位元素 | 對應的class類名 | findElement(By.className("passworld")) |
findElement(By.tagName()) | 通過元素的 tag 標簽名來定位元素 | 對應的標簽名 | findElement(By.tagName("input")) |
findElement(By.linkText()) | 通過元素標簽對之間的文本信息來定位元素 | 文本內容 | findElement(By.linkText("登錄")) |
findElement(By.partialLinkText()) | 通過元素標簽對之間的部分文本信息來定位元素 | 部分文本內容 | findElement(By.partialLinkText("百度")) |
findElement(By.xpath()) | 通過xpath語法來定位元素 | xpath表達式 | findElement(By.xpath("//input[@id='kw']")) |
findElement(By.cssSelector()) | 通過css選擇器來定位元素 | css元素選擇器 | findElement(By.cssSelector("#kw")) |
同時這8種方法都對應有着返回復數元素的方法,分別在調用的方法findElements(By.id()) 加上一個s:
- findElements(By.id())
- findElements(By.name())
- findElements(By.className())
- findElements(By.tagName())
- findElements(By.linkText())
- findElements(By.partialLinkText())
- findElements(By.xpath())
- findElements(By.cssSelector())
4.2.定位方式的用法
假如我們有一個Web頁面,通過前端工具(如,Firebug)查看到一個元素的屬性是這樣的。
<html>
<head>
<body link="#0000cc">
<a id="result_logo" href="/" onmousedown="return c({'fm':'tab','tab':'logo'})">
<form id="form" class="fm" name="f" action="/s">
<span class="soutu-btn">按鈕</span>
<input id="kw" class="s_ipt" name="wd" value="" maxlength="255" autocomplete="off">
我們的目的是要定位input標簽的輸入框。
- 通過id定位:
driver.findElement(By.id("kw"))
- 通過name定位:
driver.findElement(By.name("wd"))
- 通過class name定位:
driver.findElement(By.className("s_ipt"))
- 通過tag name定位:
driver.findElement(By.tagName("input"))
- 通過xpath定位,xpath定位有N種寫法,這里列幾個常用寫法:
driver.findElement(By.xpath("//*[@id='kw']")) // id定位
driver.findElement(By.xpath("//*[@name='wd']")) // 屬性值定位
driver.findElement(By.xpath("//span[text()='按鈕']")) // 文本定位
driver.findElement(By.xpath("//input[@class='s_ipt']")) // class屬性定位
driver.findElement(By.xpath("/html/body/form/span/input")) // 絕對路徑定位
driver.findElement(By.xpath("//span[@class='soutu-btn']/input")) // 相對路徑定位
driver.findElement(By.xpath("//form[@id='form']/span/input"))
driver.findElement(By.xpath("//input[@id='kw' and @name='wd']")) // 多組合屬性定位
driver.findElement(By.xpath("//span[contains(text(),'按鈕')]")) // 是否包含文本
- 通過css定位,css定位有N種寫法,這里列幾個常用寫法:
driver.findElement(By.cssSelector("#kw") // id定位
driver.findElement(By.cssSelector("[name=wd]") // name屬性值定位
driver.findElement(By.cssSelector(".s_ipt") // class地位
driver.findElement(By.cssSelector("html > body > form > span > input") // css層級定位
driver.findElement(By.cssSelector("span.soutu-btn> input#kw")
driver.findElement(By.cssSelector("form#form > span > input")
接下來,我們的頁面上有一組文本鏈接。
<a class="mnav" href="http://news.baidu.com" name="tj_trnews">新聞</a>
<a class="mnav" href="http://www.hao123.com" name="tj_trhao123">hao123</a>
- 通過linkText定位:
driver.findElement(By.linkText("新聞")
driver.findElement(By.linkText("hao123")
- 通過 partialLinkText 定位:
driver.findElement(By.partialLinkText("新")
driver.findElement(By.partialLinkText("hao")
driver.findElement(By.partialLinkText("123")
4.3.xpath進階-軸定位
- parent::div 上層父節點,你那叫div的親生爸爸,最多有一個;
- child::div 下層所有子節點,你的所有親兒子中叫div的;
- ancestor::div 上面所有直系節點,是你親生爸爸或者你親爹或者你親爹的爸爸中叫div的;
- descendant::div 下面所有節點,你的后代中叫div的,不包括你弟弟的后代;
- following::div 自你以下頁面中所有節點叫div的;
- following-sibling::div 同層下節點,你所有的親弟弟中叫div的;
- preceding::div 同層上節點,你所有的親哥哥以及他們的后代中叫div的;
- preceding-sibling::div 同層上節點,你所有的親哥哥中叫div的;
軸定位詳細操作可參考:https://www.cnblogs.com/wangyi0419/p/11638652.html
xpath 多條件組合查找:https://blog.csdn.net/li575098618/article/details/47853949
關於 xpaht 和 css 的定位比較復雜,請參考: xpath語法、 css選擇器
第五章 Selenium API
5.1.WebDriver 常用 API
WebDriver 提供了一系列的 API 來和瀏覽器進行交互,如下:
方法 | 描述 |
---|---|
get(String url) | 訪問目標 url 地址,打開網頁 |
getCurrentUrl() | 獲取當前頁面 url 地址 |
getTitle() | 獲取頁面標題 |
getPageSource() | 獲取頁面源代碼 |
close() | 關閉瀏覽器當前打開的窗口 |
quit() | 關閉瀏覽器所有的窗口 |
findElement(by) | 查找單個元素 |
findElements(by) | 查到元素列表,返回一個集合 |
getWindowHandle() | 獲取當前窗口句柄 |
getWindowHandles() | 獲取所有窗口的句柄 |
5.2.WebElement 常用 API
通過 WebElement 實現與網站頁面上元素的交互,這些元素包含文本框、文本域、按鈕、單選框、div等,WebElement提供了一系列的方法對這些元素進行操作:
方法 | 描述 |
---|---|
click() | 對元素進行點擊 |
clear() | 清空內容(如文本框內容) |
sendKeys(...) | 寫入內容與模擬按鍵操作 |
isDisplayed() | 元素是否可見(true:可見,false:不可見) |
isEnabled() | 元素是否啟用 |
isSelected() | 元素是否已選擇 |
getTagName() | 獲取元素標簽名 |
getAttribute(attributeName) | 獲取元素對應的屬性值 |
getText() | 獲取元素文本值(元素可見狀態下才能獲取到) |
submit() | 表單提交 |
5.2.1.代碼示例
public class BaiduSearch {
public static void main(String[] args) {
// 1.創建webdriver驅動
WebDriver driver = new ChromeDriver();
// 2.打開百度首頁
driver.get("https://www.baidu.com");
// 獲取搜索框元素
WebElement inputElem = driver.findElement(By.id("kw"));
// clear()方法,清空輸入框內容
inputElem.clear();
// sendKeys()方法,在搜索框中輸入搜索內容
inputElem.sendKeys("selenium");
// 元素是否顯示
boolean displayed = inputElem.isDisplayed();
System.out.println(displayed); // 輸出true
// 元素是否啟用
boolean enabled = inputElem.isEnabled();
System.out.println(enabled); // 輸出true
// 判斷元素是否被選中狀態,一般用在Radio(單選),Checkbox(多選),Select(下拉選)
// 在輸入框中使用無意義
boolean selected = inputElem.isSelected();
System.out.println(selected); // 輸出fasle
// 獲取標簽名
String tagName = inputElem.getTagName();
System.out.println(tagName); // 輸出input
// 獲取屬性名(name屬性)
String name = inputElem.getAttribute("name");
System.out.println(name); // 輸出wd
// 獲取文本值
String text = inputElem.getText();
System.out.println(text); // 輸出selenium
// 通過submit提交
driver.findElement(By.id("su")).submit();
// click()方法,點擊百度一下按鈕
driver.findElement(By.id("su")).click();
// 退出瀏覽器
driver.quit();
}
}
第六章 元素等待機制
在對元素進行定位時,有時候網頁加載時間比較長,元素還沒有加載出來,這個時候去查找這個元素的話程序中就會拋出異常,所以我們在編寫代碼時需要考慮延時問題,在selenium中有幾種延時機制可以使用如下:
6.1.硬性等待
硬性等待就是不管你瀏覽器元素是否加載完成,都要進行等待設置好的時間,利用 java 語言中的線程類 Thread 中的 sleep 方法,進行強制等待。
Thread.sleep(long millis) 該方法會讓線程進行休眠。
如:Thread.sleep(3000) 表示程序執行的線程暫停 3 秒鍾。
這種方法在一定的程度上是可以解決元素加載過慢的情況,但是不建議使用該方法,因為一般情況下我們無法判斷網頁到底需要多長時間加載完成,如果我們設置的時間過長,非常影響效率。
6.2.隱式等待
隱式等待的理解,就是我們通過代碼設置一個等待時間,如果在這個等待時間內,網頁加載完成后就執行下一步,否則一直等待到時間截止。
代碼表示:
driver.manage.timeouts.implicitlyWait(long time, TimeUtil unit);
這種方法相對於硬性等待顯的會靈活一點,但是隱式等待也有個弊端,因為這個設置是全局的,程序需要等待整個頁面加載完成,直到超時,有時候我需要找的那個元素早就加載完成了,只是頁面上有個別其他元素加載比較慢,程序還是會一直等待下去。直到所有的元素加載完成在執行下一步。
6.3.顯式等待
顯示等待是等待指定元素設置的等待時間,在設置時間內,默認每隔0.5s檢測一次當前的頁面這個元素是否存在,如果在規定的時間內找到了元素則執行相關操作,如果超過設置時間檢測不到則拋出異常。默認拋出異常為:NoSuchElementException。推薦使用顯示等待。
代碼表示:
WebDriberWait wait = new WebDriverWait(dirver, timeOutInSeconds);
wait.nutil(expectCondition);
具體使用案例:
1.查找元素是否已經加載出來
WebDriverWait wait = new WebDriverWait(driver, 5);
// 查找id為“kw"的元素是否加載出來了(已經在頁面DOM中存在)
wait.until(ExpectedConditions.presenceOfElementLocated(By.id("kw")));
// 在設定時間內找到后就返回,超時直接拋異常
2.查找元素是否可見
WebDriverWait wait = new WebDriverWait(driver, 5);
// 查找id為"kw"的元素是否可見
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("kw")));
3.查找元素是否可點擊
WebDriverWait wait = new WebDriverWait(driver, 5);
// 查找id為"kw"的元素是否可以點擊
wait.until(ExpectedConditions.elementToBeClickable(By.id("kw")));
4.自定義方法,重寫ExpectedCondition中的apply方法
/*
自定義查找元素的方法,對元素查找方法進行二次封裝,更加的靈活,可以加上自己邏輯。
*/
public WebElement getElement(long timeOutInSecond, By by) {
WebDriverWait wait = new WebDriverWait(driver, timeOutInSecond);
WebElement element = wait.until(new ExpectedCondition<WebElement>() {
@NullableDecl
@Override
public WebElement apply(@NullableDecl WebDriver webDriver) {
return webDriver.findElement(by);
}
});
return element;
}
6.3.1.ExpectedConditions類中常用方法
方法 | 描述 |
---|---|
presenceOfElementLocated(By locator) | 判斷某個元素是否被加到了dom樹里,並不代表該元素一定可見; |
visibilityOfElementLocated(By locator) | 判斷某個元素是否可見(代表元素非隱藏,元素的寬和高都不等於0); |
elementToBeClickable(By locator) | 判斷某個元素中是否可見並且是enable的且可點擊; |
elementToBeSelected(By locator) | 判斷某個元素是否被選中了,一般用在下拉列表; |
alertIsPresent() | 判斷頁面上是否存在alert; |
titleIs(String title) | 判斷當前頁面的title是否精確等於預期; |
titleContains(String title) | 判斷當前頁面的title是否包含預期字符串; |
textToBePresentInElement(By locator, String text) | 判斷某個元素中的text是否包含了預期的字符串; |
textToBePresentInElementValue(By locator, String text) | 判斷某個元素中的value屬性是否包含了預期的字符串; |
invisibilityOfElementLocated(By locator) | 判斷某個元素中是否不存在於dom樹或不可見; |
frameToBeAvailableAndSwitchToIt(By) | 判斷iframe可用,並且切換到iframe中 |
6.4.頁面加載超時設置
通過TimeOuts 對象進行全局頁面加載超時的設置,該設置必須放置get 方法之前。如下代碼:
driver.manage().timeouts().pageLoadTimeout(5, TimeUnit.SECONDS);
driver.get("https://www.baidu.com");
如果百度首頁在超過5秒鍾沒有加載完畢,程序就會拋出異常,如果在 2秒就加載完了,就直接往下執行,如果需要對頁面加載時間有要求的,可以用這個設置進行檢驗。
第七章 特殊元素操作
7.1.彈出框處理(alert、confirm)
操作alert、confirm彈出框,可以通過Alert 對象來進行操作,Alert類包含了確認、取消、輸入和獲取彈出窗內容。
Alert對應屬性和方法:
方法 | 描述 |
---|---|
Alert.getText() | 獲取彈出框內容。 |
Alert.accept() | 接受彈窗的提示,相當於點擊確認按鈕。 |
Alert.dismiss() | 取消提示窗。 |
Alert.sendKeys(String s) | 給彈窗輸入內容。 |
簡單使用示例:
// 首先需要切換到彈出框中,獲取Alert對象。
Alert alert = driver.switchTo().alert();
// 獲取彈窗文本內容
alert.getText();
// 點擊確定按鈕
alert.accept();
// 點擊取消按鈕
alert.dismiss();
注:如果彈出框不是 js 原生的 alert 彈窗,我們還是按照原來的獲取元素的方法。
7.2.iframe 切換
有時候我們定位元素的時候,發現怎么都定位不了。 這時候你需要查一查你要定位的元素是否在iframe里面。
什么是iframe?
iframe 就是HTML 中,用於網頁嵌套網頁的。 一個網頁可以嵌套到另一個網頁中,可以嵌套很多層。
例如:
main.html
<html>
<head>
<title>FrameTest</title>
</head>
<body>
<div id="id1">this is main page's div!</div>
<input type="text" id="maininput" />
<br/>
<iframe id="frameA" frameborder="0" scrolling="no" style="left:0;position:absolute;" src="frame.html"></iframe>
</body>
</html>
frame.html
<html>
<head>
<title>this is a frame!</title>
</head>
<body>
<div id="div1">this is iframes div,</div>
<input id="iframeinput"></input>
</body>
</html>
使用selenium 操作瀏覽器時,如果需要操作iframe中的元素,首先需要切換到對應的內聯框架中。
selenium 給我們提供了三個重載的方法,進行操作iframe;
切換方法:
// 方法一:通過 iframe的索引值,在頁面中的位置
driver.switchTo().frame(index);
// 方法二:通過 iframe 的name 或者id
driver.switchTo().frame(nameOrId);
// 方法三:通過iframe 對應的webElement
driver.switchTo().frame(frameElement);
selenium 代碼:
public static void testIframe(WebDriver driver){
// 在 主窗口的時候
driver.findElement(By.id("maininput")).sendKeys("main input");
// 此時 沒有進入到iframe, 以下語句會報錯
//driver.findElement(By.id("iframeinput")).sendKeys("iframe input");
driver.switchTo().frame("frameA");
driver.findElement(By.id("iframeinput")).sendKeys("iframe input");
// 此時沒有在主窗口,下面語句會報錯
//driver.findElement(By.id("maininput")).sendKeys("main input");
// 回到主窗口
driver.switchTo().defaultContent();
driver.findElement(By.id("maininput")).sendKeys("main input");
}
注:如果已經切換進入了其中的一個 iframe 中,再想對 iframe 外的元素進行操作,需要切換回到默認的頁面中,否則會找不到元素。
// 切換到默認內容頁面
driver.switchTo().defaultContent();
7.3.瀏覽器窗口的切換
有時候后在操作瀏覽器,可能打開了一個新的窗口,這個時候如果要對新窗口的元素進行操作,需要切換到新窗口中去,怎么去切換呢?在 selenium 中有個叫句柄的概念。
什么是句柄,簡單理解就是瀏覽器窗口的一個標識,瀏覽器打開的每個窗口都有唯一的一個標識,也就是句柄,我們可以通過句柄來進行窗口之間的切換,從而來達到我們操作不同窗口的元素。
WebDriver 中提供了兩個 API 來獲取窗口的相關句柄:
// 獲取當前窗口的句柄
String handle = driver.getWindowHandle();
// 獲取所有窗口的句柄,返回一個集合
Set<String> handles = driver.getWindowHandles();
獲取到句柄后,通過對應的方法進行切換:
// 切換到窗口
driver.switchTo.windwo(String handle);
多窗口之間的切換方法:
/**
* 切換窗口的方法
* 通過傳入一個標題來找到我們需要的窗口。
* @param title 窗口的標題
*/
public void switchWindow(String title){
Set<String> handles = driver.getWindowHandles();
// 切換窗口的方式--循環遍歷handles集合
for (String handle : handles) {
//判斷是哪一個頁面的句柄??--根據什么來判斷???title
if(driver.getTitle().equals(title)){
break;
}else{
//切換窗口--根據窗口標識來切換
driver.switchTo().window(handle);
}
}
7.4.select 下拉框處理
如果一個頁面元素是一個下拉框(select),對應下拉框的操作,selenium有專門的類 Select 進行處理。其中包含了單選和多選下拉框的各種操作,如獲得所有的選項、選擇某一項、取消選中某一項、是否是多選下拉框等。
Select類常用的一些方法:
方法 | 說明 |
---|---|
void deselectAll() | 取消所有選擇項,僅對下拉框的多選模式有效,若下拉不支持多選模式,則會拋出異常 UnsupportedOperationException(不支持的操作) |
void deselectByIndex(int index) | 取消指定index的選擇,index從零開始,僅對多選模式有效,否則拋出異常 UnsupportedOperationException(不支持的操作) |
void deselectByValue(String value) | 取消Select標簽中,value為指定值的選擇,僅對多選模式有效,否則拋出異常 UnsupportedOperationException(不支持的操作) |
void deselectByVisibleText(String Text) | 取消項的文字為指定值的項,例如指定值為Bar,項的html為 ,僅對多選模式有效,單選模式無效,但不會拋出異常 |
List
getAllSelectedOptions()
|
獲得所有選中項,單選多選模式均有效,但沒有一個被選中時,返回空列表,不會拋出異常 |
WebElement getFirstSelectedOption() |
獲得第一個被選中的項,單選多選模式均有效,當多選模式下,沒有一個被選中時,會拋出NoSuchElementException異常 |
List
getOptions()
|
獲得下拉框的所有項,單選多選模式均有效,當下拉框沒有任何項時,返回空列表,不會拋出異常 |
boolean isMultiple() |
判斷下拉框是否多選模式 |
void selectByIndex(int index) | 選中指定index的項,單選多選均有效,當index超出范圍時,拋出NoSuchElementException異常 |
void selectByValue(String value) | 選中所有Select標簽中,value為指定值的所有項,單選多選均有效,當沒有適合的項時,拋出NoSuchElementException異常 |
void selectByVisibleText(String text) | 選中所有項的文字為指定值的項,與deselectByValue相反,但單選多選模式均有效,當沒有適合的項時,拋出NoSuchElementException異常 |
示例:2345網址導航首頁的城市省份切換。
1.進入2345.com首頁,點擊頭部【切換】進行城市切換,我們切換省份為北京。
2.HTML頁面DOM結構。
3.代碼編寫,這里需要注意下拉選是在一個iframe中,需要先切換到這個iframe后再操作。
// 創建驅動
WebDriver driver = new ChromeDriver();
// 打開2345網站
driver.get("https://www.2345.com");
// 切換城市
driver.findElement(By.linkText("切換")).click();
// 切換到iframe內聯框架中
driver.switchTo().frame("city_set_ifr");
// 定位到省份下拉框
WebElement province = driver.findElement(By.id("province"));
province.click();
// 創建Select對象
Select select = new Select(province);
// 根據文本來獲取下拉值
select.selectByVisibleText("B 北京");
driver.quit();
7.5.帶 readonly 屬性的元素操作
標簽元素如果帶有 readonly 屬性,表示只讀不能進行編輯,如果我們需要操作這樣的元素,需要把這個 readonly 屬性進行移除后,再進行操作。刪除標簽屬性的話,webdriver 沒有對應的 API,我們使用 JavaScript 腳本來進行操作。
示例:12306 網站購票頁面日期。
selenium 代碼實現:
// 創建驅動
WebDriver driver = new ChromeDriver();
// 打開12306網站
driver.get("https://www.12306.cn/index/");
// 通過js來移除readonly屬性
String removeAttr = "document.getElementById('train_date').removeAttribute('readonly');";
// 執行js
((JavascriptExecutor)driver).executeScript(removeAttr);
// 獲取日期日歷輸入框
WebElement train_date = driver.findElement(By.id("train_date"));
// 清除原來的值
train_date.clear();
// 輸入內容
train_date.sendKeys("2020-03-30");
driver.quit();
7.6.日期控件操作
對於頁面中出現時間控件選擇時,一般分為兩種:
(1)控件沒有限制手動填寫的,我們直接使用 sendKeys() 方法進行賦值即可。
driver.findElement(By).sendKeys("2020-03-30");
(2)控件限制了手動輸入的,只能通過點擊控件時間進行輸入的,我們就需要使用 js 腳本進行操作了。
// 獲取js執行器
JavaScriptExecutor js = (JavaScriptExecutor)driver;
// 對時間輸入框進入賦值
String script = "document.getElementById('xxx').value='2020-03-30';";
// 執行
js.executeScript(script);
注:需要注意的是,不管使用哪種方式進行時間的賦值,一點要注意輸入時間的格式是否符合系統的要求;
7.7.文件上傳
對於通過input標簽實現的上傳功能,可以將其看作是一個輸入框,即通過sendKeys()指定本地文件路徑的方式實現文件上傳。
創建upfile.html文件,代碼如下:
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<title>upload_file</title>
<link href="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<div class="row-fluid">
<div class="span6 well">
<h3>upload_file</h3>
<input type="file" name="file" />
</div>
</div>
</body>
<script src="http://cdn.bootcss.com/bootstrap/3.3.0/css/bootstrap.min.js"></scrip>
</html>
接下來通過sendKeys()方法來實現文件上傳。
import java.io.File;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class UpFileDemo {
public static void main(String[] args) throws InterruptedException {
WebDriver driver = new ChromeDriver();
File file = new File("./HTMLFile/upfile.html");
String filePath = file.getAbsolutePath();
driver.get(filePath);
//定位上傳按鈕, 添加本地文件
driver.findElement(By.name("file")).sendKeys("D:\\upload_file.txt");
Thread.sleep(5000);
driver.quit();
}
}
注:sendKeys 參數為文件的絕對路徑,並且上傳的文件一點要存在,否則會拋異常。
第八章 控制瀏覽器操作
8.1.瀏覽器窗口操作
WebDriver 給我們提供了一個 Window 對象,專門用於對窗口的設置。
對象獲取方法:
Window window = driver.manage().window();
Window 對象的方法有:
方法 | 描述 |
---|---|
window.maximize() | 將瀏覽器窗口最大化。 |
window.getPosition() | 獲取窗口的位置,返回 Point 對象,包含瀏覽器左上角的坐標位置。通過point.x 和point.y 來獲取到。 |
window.setPosition(Point) | 指定瀏覽器窗口左上角的坐標位置,創建一個Point 對象,設置對象的 x 和 y 坐標即可。 |
window.getSize() | 獲取窗口尺寸(寬和高),返回一個 Dimension 對象,通過該對象調用 getHeight() 和 getWidth() 來獲取 高度和寬度。 |
window.setSize(Dimension) | 設置窗口大小,創建一個 Dimension 對象,設置對象的高度和寬度。 |
8.2.瀏覽器導航操作
WebDriver 提供了 Navigation 對象來對瀏覽器進行導航操作,如:前進、后退、刷新等。
Navigation 對象獲取:
Navigation navigate = driver.navigate();
Navigation 對象提供的方法:
方法 | 描述 |
---|---|
navigate.to(url) | 跳轉到指定url,和 webdriver 使用 get 方法是一樣的。 |
navigate.refresh() | 刷新當前頁面。 |
navigate.back() | 瀏覽器回退操作。 |
navigate.forward() | 瀏覽器前進操作。 |
第九章 模擬鼠標鍵盤操作
9.1.模擬鼠標
在WebDriver中,關於鼠標的操作我們可以通過 Actions 類來模擬鼠標右擊、雙擊、懸停、拖動等操作。
Actions 類中鼠標操作常用方法:
方法 | 描述 |
---|---|
contextClick() | 鼠標右擊 |
clickAndHold(WebElement) | 點擊並控制(模擬懸停) |
doubleClick(WebElement) | 鼠標雙擊 |
dragAndDrop(webElement1,webElement2) | 鼠標拖動 |
moveToElement(WebElement) | 鼠標移動到某個元素上 |
perform() | 執行所有Actions中存儲的行為 |
click() | 鼠標單擊(左擊) |
示例:百度首頁設置懸停下拉菜單
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
public class MouseDemo {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
driver.get("https://www.baidu.com/");
// 定位元素
WebElement search_setting = driver.findElement(By.linkText("設置"));
// 創建actions對象
Actions action = new Actions(driver);
// 模擬鼠標懸停
action.clickAndHold(search_setting).perform();
driver.quit();
}
}
其他方法使用:
Actions action = new Actions(driver);
// 鼠標右鍵點擊指定的元素
action.contextClick(driver.findElement(By.id("element"))).perform();
// 鼠標雙擊指定的元素
action.doubleClick(driver.findElement(By.id("element"))).perform();
// 鼠標移到到指定元素上
action.moveToElement(driver.findElement(By.id("element"))).perform();
// 鼠標拖拽動作, 將 source 元素拖放到 target 元素的位置。
WebElement source = driver.findElement(By.name("element"));
WebElement target = driver.findElement(By.name("element"));
action.dragAndDrop(source,target).perform();
// 釋放鼠標
action.release().perform();
9.2.模擬鍵盤
在 selenium 中有個 Keys() 類(枚舉類),提供了幾乎鍵盤上所有按鍵的方法,在使用的過程中,我們可以通過 sendKeys() 方法來模擬鍵盤的輸入,除此之外,我們還可以用它來輸入鍵盤上的按鍵, 甚至是組合鍵, 如 Ctrl+A、 Ctrl+C 等。
以下為常用的鍵盤操作:
-
sendKeys(Keys.BACK_SPACE) 回格鍵(BackSpace)
-
sendKeys(Keys.SPACE) 空格鍵 (Space)
-
sendKeys(Keys.TAB) 制表鍵 (Tab)
-
sendKeys(Keys.ESCAPE) 回退鍵(Esc)
-
sendKeys(Keys.ENTER) 回車鍵(Enter)
-
sendKeys(Keys.CONTROL,'a') 全選(Ctrl+A)
-
sendKeys(Keys.CONTROL,'c') 復制(Ctrl+C)
-
sendKeys(Keys.CONTROL,'x') 剪切(Ctrl+X)
-
sendKeys(Keys.CONTROL,'v') 粘貼(Ctrl+V)
-
sendKeys(Keys.F1) 鍵盤 F1
……
- sendKeys(Keys.F12) 鍵盤 F12
在使用鍵盤按鍵方法前,我們需要先導入 keys 類。
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
public class Keyboard {
public static void main(String[] args)throws InterruptedException {
WebDriver driver = new ChromeDriver();
driver.get("https://www.baidu.com");
// 定位到對應的元素
WebElement input = driver.findElement(By.id("kw"));
//輸入框輸入內容
input.sendKeys("seleniumm");
Thread.sleep(2000);
//刪除多輸入的一個 m
input.sendKeys(Keys.BACK_SPACE);
Thread.sleep(2000);
//輸入空格鍵+“教程”
input.sendKeys(Keys.SPACE);
input.sendKeys("教程");
Thread.sleep(2000);
//ctrl+a 全選輸入框內容
input.sendKeys(Keys.CONTROL,"a");
Thread.sleep(2000);
//ctrl+x 剪切輸入框內容
input.sendKeys(Keys.CONTROL,"x");
Thread.sleep(2000);
//ctrl+v 粘貼內容到輸入框
input.sendKeys(Keys.CONTROL,"v");
Thread.sleep(2000);
//通過回車鍵盤來代替點擊操作
input.sendKeys(Keys.ENTER);
Thread.sleep(2000);
driver.quit();
}
}
記錄:在 Actions 類中也有對應操作鍵盤的方法,例如:keyUp()、keyDown()等,但是我在實際使用中,並沒有生效,不知道為何,從網上資料說是,不能直接對瀏覽器進行操作,只能對頁面的元素進行鍵盤的模擬操作。
第十章 操作javaScript代碼
雖然WebDriver提供了操作瀏覽器的前進和后退方法,但對於瀏覽器滾動條並沒有提供相應的操作方法。在這種情況下,就可以借助JavaScript來控制瀏覽器的滾動條。WebDriver提供了executeScript()方法來執行JavaScript代碼。
用於調整瀏覽器滾動條位置的JavaScript代碼如下:
<!-- window.scrollTo(左邊距,上邊距); -->
window.scrollTo(0,450);
window.scrollTo() 方法用於設置瀏覽器窗口滾動條的水平和垂直位置。方法的第一個參數表示水平的左間距,第二個參數表示垂直的上邊距。其代碼如下:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.JavascriptExecutor;
public class JSDemo {
public static void main(String[] args) throws InterruptedException{
WebDriver driver = new ChromeDriver();
//設置瀏覽器窗口大小
driver.manage().window().setSize(new Dimension(700, 600));
driver.get("https://www.baidu.com");
//進行百度搜索
driver.findElement(By.id("kw")).sendKeys("webdriver api");
driver.findElement(By.id("su")).click();
Thread.sleep(2000);
//將頁面滾動條拖到底部
((JavascriptExecutor)driver).executeScript("window.scrollTo(100,450);");
Thread.sleep(3000);
driver.quit();
}
}
通過瀏覽器打開百度進行搜索,並且提前通過 window().setSize() 方法將瀏覽器窗口設置為固定寬高顯示,目的是讓窗口出現水平和垂直滾動條。然后通過 executeScript() 方法執行JavaScripts代碼來移動滾動條的位置。
將滾動條滾動到某個區域后停止(頁面元素全部加載完成),如下:
//滾動到某一區域
//scrollIntoView(0); 讓元素滾動到可視區域的最下方
//scrollIntoView(); 讓元素滾動到可視區域的最上方
//JavascriptExecutor javascriptExecutor = (JavascriptExecutor)BrowserUtil.driver;
//javascriptExecutor.executeScript("document.getElementById('index_ads').scrollIntoView(0);");
//JavaScript的參數傳遞-selenium和js的交互
//1、先去找到這個元素
WebElement webElement = driver.findElement(By.xpath("element"));
//2、找到的元素作為參數傳入到Js代碼中
JavascriptExecutor javascriptExecutor = (JavascriptExecutor)driver;
javascriptExecutor.executeScript("arguments[0].scrollIntoView(0)",webElement);
頁面元素是通過懶加載方式,需要一直進行滾動的
/**
* 滑動列表找元素並且進行點擊(懶加載)
* @param selectedText 選中元素文本
* @param by 正在加載類似元素的定位表達式
*/
public static void clickElementInList(String selectedText, By by) {
// 滑動之前的頁面源代碼信息
String beforeSource = "";
// 滑動之后的頁面源代碼信息
String afterSource = "";
// 循環條件
// 1、找到了元素,跳出循環
// 2、如果沒有找到元素???怎么跳出循環
while (true) {
WebElement webElement = driver.findElement(by);
// 獲取頁面源代碼
beforeSource = driver.getPageSource();
// 獲取js執行器
JavascriptExecutor javascriptExecutor = (JavascriptExecutor)driver;
// 執行js
javascriptExecutor.executeScript("arguments[0].scrollIntoView(0);", webElement);
// 如果當前頁面有想要的元素,怎么判斷是否有??--getPageSource
if (driver.getPageSource().contains(selectedText)) {
driver.findElement(By.linkText(selectedText)).click();
// 找到元素退出循環,不再滾動。
break;
}
afterSource = driver.getPageSource();
// 頁面元素沒有變化---滑動到了最底部
if (afterSource.equals(beforeSource)) {
// 到達底部,退出。
break;
}
}
}