第一章 Selenium 概述
1.1.Selenium 發展史
Selenium是一系列基于Web的自動化工具,提供一套測試函數,用于支援Web自動化測試。函數非常靈活,能夠完成界面元素定位、視窗跳轉、結果比較。具有如下特點:
- 多浏覽器支援
- 如IE、Firefox、Safari、Chrome、Android手機浏覽器等。
- 支援多語言
- 如Java、C#、Python、Ruby、PHP等。
- 支援多作業系統
- 如Windows、Linux、IOS、Android等。
- 開源免費
- 官網:http://www.seleniumhg.org/
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為 Bar,僅對多選模式有效,單選模式無效,但不會抛出異常 |
List | 獲得所有選中項,單選多選模式均有效,但沒有一個被選中時,傳回空清單,不會抛出異常 |
WebElement | 獲得第一個被選中的項,單選多選模式均有效,當多選模式下,沒有一個被選中時,會抛出NoSuchElementException異常 |
| 獲得下拉框的所有項,單選多選模式均有效,當下拉框沒有任何項時,傳回空清單,不會抛出異常 |
boolean | 判斷下拉框是否多選模式 |
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中存儲的行為 |
滑鼠單擊(左擊) |
示例:百度首頁設定懸停下拉菜單
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鍵(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);
//通過Enter鍵盤來代替點選操作
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;
}
}
}