<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
option,select{
width: 100px;
}
option{
height: 20px;
}
</style>
<body>
<form action="" method="get">
<input type="text" id="username" name="username" placeholder="username" class='input-text'>
<br />
<input type="password" id="password" name="password" placeholder="password" class="input-password">
<br />
<input type="text" name="password2" placeholder="確認密碼"><br />
</form>
<H8> </H8>
<div id='links'>
<ul>
<li><a>標簽</a></li>
<li><a>Genetic Algorithms in Search, Optimization, and Machine Learning</a></li>
<li>hello</li>
<li>world</li>
</ul>
</div>
<H8> </H8>
<div>
<button id="button" onclick="click()">我是一個按鈕</button>
<span id="click_count">鼠標單擊次數(shù): 0</span>
</div>
<H8> </H8>
<div>
<select name="select" id="select-single">
<option value="1" selected>zhangsan</option>
<option value="2">lisi</option>
<option value="3">wangwu</option>
<option value="4">zhaoliu</option>
<option value="5">tangli</option>
</select>
</div>
<H8> </H8>
<div>
<select name="select" id="select-multiple" multiple>
<option value="1" selected>zhangsan</option>
<option value="2">lisi</option>
<option value="3">wangwu</option>
<option value="4">zhaoliu</option>
<option value="5">tangli</option>
</select>
</div>
</body>
<script>
let click_count = 0
let button = document.getElementById('button')
button.onclick = function click(event) {
click_count++;
document.getElementById('click_count').innerHTML = `鼠標單擊次數(shù): ${click_count}`;
}
</script>
</html>
什么是Selenium
Selenium是一個用于Web應用程序測試的工具,可以直接調(diào)用瀏覽器,它支持所有主流的瀏覽器。
最初是為網(wǎng)站自動化測試而開發(fā)的,但卻被很多爬蟲愛好者發(fā)揚光大
Selenium特點
- 開源軟件:源代碼開放可以根據(jù)需要來增加工具的某些功能
- 跨平臺:linux 、windows 、mac
- 核心功能:就是可以在多個瀏覽器上進行自動化測試
- 多語言:Java、Python、C#、JavaScript、Ruby等
- 成熟穩(wěn)定:目前已經(jīng)被google , 百度, 騰訊等公司廣泛使用
- 功能強大:能夠?qū)崿F(xiàn)類似商業(yè)工具的大部分功能,因為開源性,可實現(xiàn)定制化功能
什么是WebDriver?
Webdriver 是一種用于控制瀏覽器的程序,不同的瀏覽器有不同的 webdriver。
Chrome (ChromeDriver)
IE(InternetExplorerDriver)
Opera(OperaDriver)
Firefox (FirefoxDriver)
safari(SafariDriver)
HtmlUnit (HtmlUnit Driver)
webdriver 提供了對外的接口,其他程序通過這些接口控制 webdriver 與瀏覽器的交互。例如:我們可以寫 python 程序來調(diào)用 webdriver 的接口。實際上從其他程序的角度看,webdriver 就是充當了和瀏覽器交互的一個橋梁。提示:
Firefox、Chrome:對元素定位和操作有良好的支持,同時對JavaScript支持也非常好。
IE: 只能在windows平臺運行,所有瀏覽器中運行速度最慢
HtmlUnit:無GUI(界面)運行,運行速度最快;
Selenium 執(zhí)行過程
python代碼--> selenium 封裝的 python 接口--> WebDriver 提供接口--> 瀏覽器
環(huán)境搭建
基于Python環(huán)境搭建
pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple
注意: 在安裝selenium時,前提是Python3.5以上版本安裝完畢且能正常運行
谷歌瀏覽器驅(qū)動安裝
確認瀏覽器的版本

下載驅(qū)動
下載與瀏覽器版本一致的驅(qū)動版本
國內(nèi)不能直接訪問Chrome官網(wǎng),可以在ChromeDriver倉庫中下載 或者 https://npm.taobao.org/mirrors/chromedriver

WebDriver 元素定位簡單方式
selenium頁面元素定位的方法,是在selenium中可以通過多種方式來定位標簽,返回標簽元素對象:
- 通過 id 屬性定位 : find_element_by_id
- 通過 name 屬性定位 : find_element_by_name
- 通過 class 屬性定位 : find_element_by_class_name
- 通過標簽名定位 : find_element_by_tag_name
- 通過內(nèi)容定位 a 標簽(絕對匹配) : find_element_by_link_text
- 通過內(nèi)容定位 a 標簽(模糊匹配) : find_element_by_partial_link_text
from selenium.webdriver import Chrome
import traceback
from selenium.webdriver.chrome.service import *
from selenium.webdriver.common.by import By
service = Service("./chromedriver")
driver = Chrome(service=service)
# 通過指定chromedriver的路徑來實例化driver對象
# 控制瀏覽器訪問url地址
# file://{本地文件絕對路徑}
driver.get('file://./test.html') # 打開本地 html 文件
try:
print(driver.find_element_by_id('username')) # 通過 id 屬性定位
driver.find_element_by_name('password2') # 通過 name 屬性定位
driver.find_element_by_class_name('input-password') # 通過 class 屬性定位
driver.find_element_by_tag_name('ul') # 通過標簽名定位
driver.find_element_by_link_text('標簽') # 通過內(nèi)容定位 a 標簽(絕對匹配)
driver.find_element_by_partial_link_text('Optimization') # 通過內(nèi)容定位 a 標簽(模糊匹配)
except Exception:
print(traceback.format_exc())
finally:
# 退出瀏覽器
driver.quit()
- Chrome(executable_path='./chromedriver')中executable參數(shù)指定的是下載好的chromedriver文件的路徑
- 要在代碼中盡量保證driver.quit()能夠成功執(zhí)行,進而關(guān)閉driver退出模擬瀏覽器;不然將在操作系統(tǒng)中殘留進程,對系統(tǒng)造成不必要的壓力
- find_element_by_方式已不推薦使用,推薦使用find_element(By_,元素)
xpath 方式
- XPath 即為 XML Path 的簡稱,它是一種用來確定 XML/HTML 文檔中某部分位置的語言。
- XPath文檔:http://www.w3school.com.cn/xpath/index.asp
- HTML 可以看做是 XML 的一種實現(xiàn),所以 Selenium 用戶可以使用這種強大的語言在Web應用中定位元素。
xpath路徑
- html,xml 中的元素可以嵌套其他元素,但是根元素只有一個。我們可以這種嵌套關(guān)系看成路徑。路徑分絕對路徑和相對路徑:
- 絕對路徑:從根元素到指定元素之間所有經(jīng)過元素層級路徑,絕對路徑以 "/" 開始,例如: input 的絕對路徑是: /html/body/form/input
- 相對路徑:從任何元素開始到該元素的路徑,相對路徑以 "http://" 開始,例如: 用戶名輸入框標簽的相對路徑有: //form/input,//body/form/input
xpath 定位
xpath 定位是結(jié)合路徑來進行定位的,分為絕對定位和相對定位。定位過程中還可以結(jié)合元素的屬性值。
定位方法是 find_element_by_xpath
純路徑定位
絕對定位: find_element_by_xpath("/html/body/form/input")
相對定位: find_element_by_xpath("http://div/ul/li/a")
結(jié)合屬性
單個屬性: find_element_by_xpath("http://input[@type='text']")
多個屬性: driver.find_element_by_xpath("http://input[@type='text' and @name='username']")
選擇上一級元素
find_element_by_xpath("http://input/..") 返回的是 form 元素
滿足條件的多個元素,選擇其中一個
driver.find_element_by_xpath("http://ul/li") 有多個 li 滿足條件,選擇其中一個,通過下標來完成,下標從 1 開始
driver.find_element_by_xpath("http://ul/li[1]")
可以結(jié)合特殊方法 last() 從后面開始選擇 ,比如 //ul/li[last()] 選擇最后一個 //ul/li[last()-1] 倒數(shù)第二個
from selenium.webdriver import Chrome
import traceback
# 通過指定chromedriver的路徑來實例化driver對象
driver = Chrome(executable_path='./chromedriver')
# 控制瀏覽器訪問url地址
# file://{本地文件絕對路徑}
driver.get('file:///home/python/code/unit_testing/selenium_code/test.html') # 打開本地 html 文件
try:
print(driver.find_element_by_xpath('/html/body/form/input'))
print(driver.find_element_by_xpath('//div/ul/li'))
print(driver.find_element_by_xpath('//form/input[@name="password"]'))
print(driver.find_element_by_xpath('//form/input[@name="password2" and @type="text"]'))
print(driver.find_element_by_xpath('//li/..'))
print(driver.find_element_by_xpath('//ul/li[1]'))
print(driver.find_element_by_xpath('//ul/li[last()]'))
print(driver.find_element_by_xpath('//ul/li[last()-1]'))
except Exception:
print(traceback.format_exc())
finally:
# 退出瀏覽器
driver.quit()
CSS 方式
CSS 選擇器
在Selenium中也可以使用這種選擇器,通過 find_element_by_css_selector:
- 在selenium中極力推薦CSS定位,因為它比XPath定位速度要快
- CSS 選擇器語法非常強大,在這里我們只學習在測試中常用的幾個
| 選擇器 | 例子 | 描述 |
|---|---|---|
| #id | #userA | id選擇器,選擇id="userA"的所有元素 |
| .class | .telA | class選擇器,選擇class="telA"的所有元素 |
| element | input | 選擇所有input元素 |
| [attribute=value] | [type="password"] | 選擇type="password"的所有元素 |
| element>element | p>input | 選擇所有父元素為p元素的input元素 |
driver.find_element_by_css_selector('#username') # 通過 id
driver.find_element_by_css_selector('.input-text') # 通過 class
driver.find_element_by_css_selector('form') # 通過標簽名
driver.find_element_by_css_selector('input[type="password"]') # 通過標簽屬性
driver.find_element_by_css_selector('div>ul') # 通過父子元素
查詢多個元素
- 通過 id 屬性定位 : find_elements_by_id
- 通過 name 屬性定位 : find_elements_by_name
- 通過 class 屬性定位 : find_elements_by_class_name
- 通過標簽名定位 : find_elements_by_tag_name
- 通過內(nèi)容定位 a 標簽(絕對匹配) : find_elements_by_link_text
- 通過內(nèi)容定位 a 標簽(模糊匹配) : find_elements_by_partial_link_text
- 通過 xpath : find_elements_by_xpath
- 通過 CSS 選擇器: find_elements_by_css_selector
和選擇單個元素的字面區(qū)別就是多了個 s。
調(diào)用這類方法,會返回一個列表,沒有找到元素則返回空列表,查找單個元素的方法會在找不到元素時拋出 NoSuchElementException 異常
driver.find_elements_by_id('#no-exist-id') # 返回空數(shù)組
driver.find_elements_by_tag_name('li') # 返回數(shù)組多個元素
什么是元素等待?
概念:WebDriver定位頁面元素時如果未找到,會在指定時間內(nèi)一直等待的過程。
為什么要設(shè)置元素等待?
當使用腳本定位元素或去驗證程序的運行狀態(tài)時,由于資源受限或網(wǎng)絡(luò)延遲引起的響應速度太慢,導致要定位的元素還未加載到頁面。
例如:頁面是通過 Ajax 發(fā)起請求,但是網(wǎng)絡(luò)有延遲,提交按鈕點擊完后,頁面等待服務器的返回結(jié)果來更新頁面,那么在這期間,測試代碼是不能夠直接去查找預期的元素的。
元素等待類型
顯式等待
隱式等待
顯式等待
概念:使 WebDriver 等待某個條件成立,否則在達到最大時長時拋出超時異常(TimeoutException)
WebDriverWait 類
from selenium.webdriver.support.wait import WebDriverWait
參數(shù):
- driver: webdriver對象
- timeout: 等待多長時間
- poll_frequency: 每次執(zhí)行失敗時休眠多長時間
調(diào)用方法
WebDriverWait.util(method, message=''):
參數(shù)說明:
- method 函數(shù),這個函數(shù)必須定義一個參數(shù),接受 driver 對象。例如: def contain_title(driver)
- message 如果等待失敗,message 作為消息拋出
返回值:如果找到,返回找到元素的對象
from selenium.webdriver import Chrome
import traceback
from selenium.webdriver.support.wait import WebDriverWait
driver = Chrome('./chromedriver')
# 3. 打開網(wǎng)址
# file://{本地網(wǎng)址絕對路徑}
driver.get('http://www.baidu.com')
try:
# time.sleep(2)
# 1. 指定最長的等待時間,指定檢測until函數(shù)的時間
# driver對象,最長等待5s, 如果沒有找到,每隔0.5s, 檢測until()指定的函數(shù),如果5s都沒有找到,拋出異常
wait_driver = WebDriverWait(driver, 5, 0.5)
# WebDriverWait.until(), 需要傳入一個函數(shù)名, 這個函數(shù),參數(shù)為Chrome類型
el = wait_driver.until(lambda temp: temp.find_element_by_tag_name('html'))
print(el)
except Exception as e:
# print(e) # 只打印錯誤信息
print(traceback.format_exc()) # 有錯誤路徑顯示
finally:
# 不管有沒有異常,都保證driver可以關(guān)閉
driver.quit()
隱式等待
隱式等待調(diào)用方法
driver.implicitly_wait(10)
隱式等待執(zhí)行-說明
如果定位某一元素定位失敗,那么就會觸發(fā)隱式等待有效時長,如果在指定時長內(nèi)加載完畢,則繼續(xù)執(zhí)行,否則拋出 NoSuchElementException 異常。
from selenium.webdriver import Chrome
from selenium.webdriver.support.wait import WebDriverWait
import traceback
import time
# 通過指定chromedriver的路徑來實例化driver對象
driver = Chrome(executable_path='./chromedriver')
# 控制瀏覽器訪問url地址
driver.get('https://www.baidu.com')
driver.implicitly_wait(5) # 隱式等待
try:
driver.find_element_by_id('kw')
except Exception as e:
print('type = ', type(e))
# print(traceback.format_exc())
finally:
# 退出瀏覽器
driver.quit()