前言
Selenium是一款可以自動(dòng)化操作瀏覽器的開源項(xiàng)目,最初的目的是瀏覽器功能的自動(dòng)化測試,但是隨著項(xiàng)目的發(fā)展,人們根據(jù)它的特性也用來做一些更多的有意思的功能而不僅僅是UI的自動(dòng)化測試工具。就像Selenium官方網(wǎng)站上描述的那樣,Selenium可以自動(dòng)化操縱瀏覽器。完了!你想用它的能力做什么事情完全取決于你。
使用場景
針對(duì)瀏覽器的自動(dòng)化測試有三個(gè)場景:
- Selenium WebDriver:如果您想創(chuàng)建健壯的、基于瀏覽器的回歸自動(dòng)化套件和測試、在許多環(huán)境中擴(kuò)展和分發(fā)腳本,那么您需要使用 Selenium WebDriver,它是一組特定于語言的綁定來驅(qū)動(dòng)瀏覽器——這就是它的本意驅(qū)動(dòng)的
- Selenium IDE:如果您想創(chuàng)建快速的錯(cuò)誤重現(xiàn)腳本,創(chuàng)建腳本以幫助自動(dòng)化輔助探索性測試,那么您想使用 Selenium IDE; Chrome、Firefox 和 Edge 插件,可以對(duì)與瀏覽器的交互進(jìn)行簡單的記錄和回放
- Selenium Grid:如果您想通過在多臺(tái)機(jī)器上分發(fā)和運(yùn)行測試來擴(kuò)展并從一個(gè)中心點(diǎn)管理多個(gè)環(huán)境,從而可以輕松地針對(duì)大量瀏覽器/操作系統(tǒng)組合運(yùn)行測試,那么您需要使用 Selenium Grid
原理
早期的Selenium目的是實(shí)現(xiàn)web應(yīng)用的UI自動(dòng)化測試,實(shí)現(xiàn)方式是通過三方的服務(wù)器注入js達(dá)到控制瀏覽器行為的目的,核心的組件叫Selenium-RC(Remote Control)
包含兩個(gè)部分:
- 客戶端側(cè)的編寫控制瀏覽器邏輯的庫
- 實(shí)現(xiàn)控制瀏覽器啟動(dòng)和關(guān)閉的服務(wù)器
架構(gòu)如下

這種架構(gòu)被證明是復(fù)雜的,而且有諸多限制,比如:
- 復(fù)雜的架構(gòu)
- 執(zhí)行測試腳本非常耗時(shí),因?yàn)?Selenium RC 使用 JavaScript 命令作為瀏覽器的指令。這會(huì)導(dǎo)致性能下降
- API不太面向?qū)ο?/li>
- 不支持 Headless HTMLUnit 瀏覽器(不可見的瀏覽器)
Selenium RC 的局限性導(dǎo)致了新的自動(dòng)化框架 Selenium WebDriver 的開發(fā)。在 2006 年引入 WebDriver 后,RC 中出現(xiàn)的復(fù)雜問題可以得到解決和解決
Selenium 結(jié)合WebDriver簡化了瀏覽器的控制行為,將中間環(huán)節(jié)的服務(wù)器去掉,直接在系統(tǒng)層級(jí)本地化控制瀏覽器,優(yōu)化后的架構(gòu)如下:

環(huán)境準(zhǔn)備
如果你不想在編碼層實(shí)現(xiàn)你的功能,可以下載Selenium IDE插件,支持錄制回放,過程腳本導(dǎo)出。

如果需要通過代碼實(shí)現(xiàn)更多靈活自定義功能,建議使用python,環(huán)境準(zhǔn)備
python3、pip3
brew install python3
selenium
pip3 install selenium
install browser drivers
設(shè)置您的系統(tǒng)以允許瀏覽器自動(dòng)化。
通過 WebDriver,Selenium 支持市場上所有主流瀏覽器,例如 Chrome/Chromium、Firefox、Internet Explorer、Edge、Opera 和 Safari。在可能的情況下,WebDriver 使用瀏覽器的內(nèi)置自動(dòng)化支持來驅(qū)動(dòng)瀏覽器

開發(fā)
First Script
通過webdriver實(shí)現(xiàn)控制瀏覽器自動(dòng)訪問功能
def test_eight_components():
driver = webdriver.Chrome()
driver.get("https://google.com")
title = driver.title
assert title == "Google"
driver.implicitly_wait(0.5)
search_box = driver.find_element(by=By.NAME, value="q")
search_button = driver.find_element(by=By.NAME, value="btnK")
search_box.send_keys("Selenium")
search_button.click()
search_box = driver.find_element(by=By.NAME, value="q")
value = search_box.get_attribute("value")
assert value == "Selenium"
driver.quit()
WebDriver API
webDriver操縱瀏覽器的API大致可以分為兩個(gè)部分,控制瀏覽器行為的比如,打開、關(guān)閉、前進(jìn)、后退、刷新等和控制頁面元素的如,點(diǎn)擊、輸入、獲取元素內(nèi)容等
瀏覽器
獲取瀏覽器信息
// title
driver.getTitle();
// url
driver.getCurrentUrl();
導(dǎo)航
//打開
driver.get("https://selenium.dev");
//跳轉(zhuǎn)
driver.navigate().to("https://selenium.dev");
// 后退
driver.navigate().back();
// 前進(jìn)
driver.navigate().forward();
// 刷新
driver.navigate().refresh();
彈框
//根據(jù)條件找到頁面中的彈框并點(diǎn)擊
driver.findElement(By.linkText("See an example alert")).click();
//等待彈框展示并保存到變量中
Alert alert = wait.until(ExpectedConditions.alertIsPresent());
//獲得彈框內(nèi)容文本
String text = alert.getText();
//點(diǎn)擊確定按鈕
alert.accept();
Alert、Confirm、Prompt功能類似
Cookies
可以支持cookies的添加刪除操作
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
public class addCookie {
public static void main(String[] args) {
WebDriver driver = new ChromeDriver();
try {
driver.get("http://www.example.com");
// Adds the cookie into current browser context
driver.manage().addCookie(new Cookie("key", "value"));
} finally {
driver.quit();
}
}
}
Frames
支持針對(duì)Frames內(nèi)元素的獲取及操作
Windows
WebDriver 不區(qū)分窗口和選項(xiàng)卡。如果您的站點(diǎn)打開一個(gè)新選項(xiàng)卡或窗口,Selenium 將允許您使用窗口句柄來處理它。每個(gè)窗口都有一個(gè)唯一標(biāo)識(shí)符,該標(biāo)識(shí)符在單個(gè)會(huì)話中保持不變。您可以使用以下方法獲取當(dāng)前窗口的窗口句柄:
driver.getWindowHandle();
元素
識(shí)別和使用DOM中的元素
大多數(shù)人的 Selenium 代碼大部分都涉及使用 Web 元素。這部分功能和寫前端代碼的document.getElementById作用差不多,思想比較簡單,就是找到頁面中的元素然后執(zhí)行模擬用戶行為的操作
支持絕對(duì)定位和相對(duì)定位的策略,針對(duì)復(fù)雜頁面ID,Tag,Class不好定位的情況可以使用xPath方式,非常靈活,其實(shí)也不用死記硬背,當(dāng)某元素不好定位時(shí),可以去官網(wǎng)查API的方式去實(shí)現(xiàn)
相對(duì)定位

def relative():
# Above
email_locator = locate_with(By.TAG_NAME, "input").above({By.ID: "password"})
# Below
password_locator = locate_with(By.TAG_NAME, "input").below({By.ID: "email"})
# Left of
cancel_locator = locate_with(By.TAG_NAME, "button").to_left_of({By.ID: "submit"})
# Right of
submit_locator = locate_with(By.TAG_NAME, "button").to_right_of({By.ID: "cancel"})
# Near
email_locator = locate_with(By.TAG_NAME, "input").near({By.ID: "lbl-email"})
# Chaining relative locators
submit_locator = locate_with(By.TAG_NAME, "button").below({By.ID: "email"}).to_right_of({By.ID: "cancel"})
傳統(tǒng)定位
<ol id="vegetables" style="margin-top: 20px">
<li class="potatoes">potatoes</li>
<li class="onions">onions</li>
<li class="tomatoes"><span>Tomato is a Vegetable</span></li>
</ol>
<ul id="fruits">
<li class="bananas"></li>
<li class="apples"></li>
<li class="tomatoes"><span>Tomato is a Fruit</span></li>
</ul>
def finders():
# Evaluating entire DOM
vegetable = driver.find_element(By.CLASS_NAME, "tomatoes")
print(vegetable)
# Evaluating a subset of the DOM
fruits = driver.find_element(By.ID, "fruits")
fruit = fruits.find_elements(By.CLASS_NAME, "tomatoes")
print(fruit)
# Optimized locator
fruit = driver.find_element(By.CSS_SELECTOR, "#fruits .tomatoes")
fruit2 = driver.find_element(By.CSS_SELECTOR, "ul .tomatoes")
print(fruit == fruit2) # True
# All matching elements
plants = driver.find_elements(By.TAG_NAME, "li")
print(plants)
# Get all the elements available with tag name 'p'
elements = driver.find_elements(By.TAG_NAME, 'span')
for e in elements:
print(e.text)
def xPath():
ol = driver.find_element(By.XPATH, "/html/body/div/div/ol[1]")
ol2 = driver.find_element(By.XPATH, "http://ol[1]")
ol3 = driver.find_element(By.XPATH, "http://ol[@id='vegetables']")
print(ol == ol2) # True
print(ol == ol3) # True
onions = driver.find_element(By.XPATH, "http://ol[1]/li[2]")
print(onions.text)
交互
5種基本命令:
- click(任意元素)
- send keys(僅用于文本塊和內(nèi)容可編輯元素)
- clear(同上)
- submit (form 元素)
- select (選擇列表元素)
獲取元素信息

總結(jié)
本次分享介紹了Selenium使用場景,簡單原理和一些的基礎(chǔ)用法。并列舉了一個(gè)小例子。掌握以上內(nèi)容,你已經(jīng)可以實(shí)現(xiàn)基本的UI自動(dòng)化測試了。另外可以做一些爬蟲和自動(dòng)化操縱瀏覽器的工具需求就需要根據(jù)個(gè)人場景化定制了,只要你有“懶”的天性,相信一定會(huì)找到挺多有意思場景使用去使用它。
參考
https://www.selenium.dev/
https://www.browserstack.com/guide/selenium-rc-tutorial