環(huán)境安裝步驟
1.準(zhǔn)備好python環(huán)境
2.準(zhǔn)備selenium環(huán)境
3.下載瀏覽器對應(yīng)版本的driver,點(diǎn)擊下載chromedriver
4.driver配置環(huán)境變量
5.在python里導(dǎo)入對應(yīng)依賴
selenium IDE 錄制

點(diǎn)擊進(jìn)入擴(kuò)展程序
selenium 用例編寫
python-selenium文檔
selenium常用等待
- 直接等待
time.sleep(3) 等待3秒 - 隱式等待
driver.implicitly_wait(5) 輪訓(xùn)查找(默認(rèn)0.5)元素是否出現(xiàn),如果沒出現(xiàn)就拋出異常 - 顯示等待
from selenium import webdriver
from selenium.webdriver.common.by import By
class TestWebUi:
def setup(self):
self.driver = webdriver.Chrome()
self.driver.get("http://www.baidu.com")
# 隱式等待
self.driver.implicitly_wait(5)
def teardown(self):
self.driver.close()
def test_search(self):
self.driver.find_element(By.ID,'kw').send_keys('騰訊課堂')
self.driver.find_element(By.ID, 'su').click()
self.driver.find_element(By.LINK_TEXT,'騰訊課堂【官方】_騰訊課堂【官方】騰訊課堂官網(wǎng)').click()
#顯示等待
WebDriverWait(self.driver,10).until(expected_conditions.presence_of_all_elements_located((By.LINK_TEXT,'官方')))
web控件定位,操作
- 操作
輸入: self.driver.find_element(By.ID,'kw').send_keys('騰訊課堂')
點(diǎn)擊: self.driver.find_element(By.ID, 'su').click() - 定位-xpath
作用域(appium、selenim)
| 表達(dá)式 | 結(jié)果 |
|---|---|
| /div/input[1] | 取div子元素的第一個(gè)input元素 |
| /div/input[last()] | 取div子元素的最后個(gè)input元素 |
| /div/input[last()-1] | 取div子元素的倒數(shù)第二個(gè)input元素 |
| /div/input[position()<3] | 取div子元素的前兩個(gè)book元素 |
| //div[@class='classname'] | 得到所有div元素,且這些元素?fù)碛兄禐閏lassaname的class屬性 |
| /div/input[price>35] | 得到所有div元素下的所有input,且其中的price元素值大于35,且這些元素?fù)碛兄禐閏lassaname的class屬性 |
| nodename | 選取此節(jié)點(diǎn)的所有子節(jié)點(diǎn) |
| / | 從根節(jié)點(diǎn)選取 |
| // | 匹配選擇當(dāng)前節(jié)點(diǎn),不考慮其位置 |
| . | 選取當(dāng)前節(jié)點(diǎn) |
| .. | 選取當(dāng)前節(jié)點(diǎn)父節(jié)點(diǎn) |
| @ | 選取屬性 |
- 定位-css selector
appium 原生元素不能用 css selector定位
| 表達(dá)式 | 結(jié)果 | 例子描述 |
|---|---|---|
| .class | .intro | 選擇 class = "intro"的所有元素 |
| .id | .idname | 選擇 id= "idname"的所有元素 |
| * | * | 選擇所有元素 |
| element | div | 選擇所有<div>元素 |
| element,element | div,p | 選擇所有<div>元素和所有<p>元素 |
| element element | div p | 選擇<div>元素內(nèi)部的所有<p>元素 |
| element>element | div>p | 選擇父元素為<div>元素的所有<p>元素 |
| element+element | div+p | 選擇緊接在<div>元素之后的所有<p>元素 |

css select f方式
web控件交互
Actions
- 官方文檔
- ActionChains:執(zhí)行鼠標(biāo)點(diǎn)擊、雙擊、右鍵、拖拽事件
- TouchActions: 模擬PC移動端、點(diǎn)擊、滑動、拖拽、多點(diǎn)觸控操作
- 執(zhí)行原理,調(diào)用actionChains方法,不會立即執(zhí)行,而是講所有的操作,按順序放在一個(gè)隊(duì)列里,調(diào)用perform()方法時(shí),隊(duì)列中的事件會依次執(zhí)行
- 基本用法
- 生成一個(gè)動作 action = ActionChains(driver)
- 動作添加方法1 action.方法1
- 調(diào)用perform()方法執(zhí)行(action.perform())
- 寫法
- 鏈?zhǔn)綄懛? ActionChains(driver).move_to_element(element).click(element).perform()
- 分布寫法
action= ActionChains(driver)
action.move_to_element(element)
actions.click(element)
actions.perform()
ActionChains示例
class TestActionChains():
def setup(self):
self.driver = webdriver.Chrome()
self.driver.get("http://sahitest.com/demo/clicks.htm")
self.driver.implicitly_wait(5)
def teardown(self):
self.driver.close()
def test_case_click(self):
element_click = self.driver.find_element(By.XPATH,'//input[@value="click me"]')
element_dbclick = self.driver.find_element(By.XPATH,'//input[@value="dbl click me"]')
element_rclick = self.driver.find_element(By.XPATH,'//input[@value="right click me"]')
action = ActionChains(self.driver)
action.click(element_click)
action.double_click(element_dbclick)# 雙擊操作
action.context_click(element_rclick)# 右擊操作
action.perform()
sleep(3)
def test_move_to(self):
# 光標(biāo)移動到某個(gè)元素
self.driver.get("http://www.baidu.com")
element = self.driver.find_element(By.ID,'s-usersetting-top')
action = ActionChains(self.driver)
action.move_to_element(element)
action.perform()
sleep(2)
def test_dragdrog(self):
self.driver.get("http://sahitest.com/demo/dragDropMooTools.htm")
ele1= self.driver.find_element(By.ID,'dragger')
ele2= self.driver.find_element(By.XPATH,"/html/body/div[2]")
action = ActionChains(self.driver)
action.drag_and_drop(ele1,ele2).perform()
action.click_and_hold(ele1).release(ele2).perform()
action.click_and_hold(ele1).move_to_element(ele2).perform()
sleep(3)
def test_keys(self):
# 模擬鍵盤操作
self.driver.get("http://sahitest.com/demo/label.htm")
ele = self.driver.find_element(By.XPATH,"/html/body/label[1]/input")
ele.click()
action = ActionChains(self.driver)
action.send_keys("username").pause(1)# 添加一秒等待
action.send_keys(Keys.SPACE).pause(1)
action.send_keys("張三").pause(1)
action.send_keys(Keys.BACK_SPACE).perform()
sleep(3)
TouchAction
官方文檔
TouchAction 示例滑動頁面
class TestTouchAction():
def setup(self):
option = webdriver.ChromeOptions()
option.add_experimental_option('w3c', False)
self.driver = webdriver.Chrome(options=option)
self.driver.get("http://baidu.com")
self.driver.implicitly_wait(5)
def teardown(self):
self.driver.close()
def test_scrollbottom(self):
ele_se = self.driver.find_element(By.ID, 'kw')
ele_se.send_keys('selenium測試')
ele_c = self.driver.find_element(By.ID, 'su')
action = TouchActions(self.driver)
action.tap(ele_c)
action.perform()
# 滑動頁面
action.scroll_from_element(ele_se, 0, 1200).perform()
sleep(3)
表單
- 表單定義
- 表單是一個(gè)包含表單元素的區(qū)域
- 表單元素是允許用戶在表單中輸入信息的元素
- 表單使用標(biāo)簽<form>定義
- 操作表單元素步驟
a. 首先要定位到表單元素
b. 然后操作元素(點(diǎn)擊、輸入、清空)
class TestFrom:
def setup(self):
self.driver = webdriver.Chrome()
self.driver.get("http://testerhome.com/account/sign_in")
self.driver.implicitly_wait(5)
def teardown(self):
self.driver.close()
def test_form(self):
self.driver.find_element(By.ID, 'user_login').send_keys('abcdee')
self.driver.find_element(By.ID, 'user_password').send_keys('12312312')
self.driver.find_element(By.XPATH, '//*[text()[contains(.,"記住")]]').click()
self.driver.find_element(By.XPATH, '//*[@id="new_user"]/div[4]/input').click()
sleep(3)
多窗口,frame處理
- selenium 處理多窗口
多個(gè)窗口識別
a. 獲取當(dāng)前窗口句柄:driver。current_window_handle
b. 在獲取所有窗口句柄 driver。window_handles
c. 判斷是否想要操作的窗口,如果是就可以對窗口進(jìn)行操作,如果不是跳轉(zhuǎn)到另外一個(gè)窗口,對另一個(gè)窗口操作 driver.switch_to_window多個(gè)窗口切換
from time import sleep
from selenium.webdriver.common.by import By
from web_ui.base import Base
class TestWindows(Base):
def test_windows(self):
self.driver.get("http://www.baidu.com")
self.driver.find_element(By.LINK_TEXT, '登錄').click()
self.driver.find_element(By.XPATH, '//*[text()[contains(.,"立即注冊")]]').click()
# 獲取當(dāng)前所有窗口
windows = self.driver.window_handles
print(windows)
# 切換到最最新打開的窗口
self.driver.switch_to_window(windows[-1])
self.driver.find_element(By.ID,'TANGRAM__PSP_4__userName').send_keys('username')
self.driver.find_element(By.ID,'TANGRAM__PSP_4__phone').send_keys('13200001234')
sleep(2)
#切換到 最開始的窗口
self.driver.switch_to_window(windows[0])
self.driver.find_element(By.ID,'TANGRAM__PSP_11__footerULoginBtn').click()
self.driver.find_element(By.ID, 'TANGRAM__PSP_11__userName').send_keys('abcdef')
sleep(2)
frame 分類,frameset、frame、iframe
frameset 不會影響正常定位,可以用id、name 定位
frame和iframe 需要特殊操作selenium處理 frame
- 多個(gè)frame識別
有兩種,嵌套的、非嵌套 - 多個(gè)frame之前切換
driver.switch_to.frame() # 根據(jù)ID或者index切換frame
driver.switch_to_default_content() # 切換到默認(rèn)frame
driver.switch_to.parent_frame() # 切換到父級frame
未嵌套iframe
driver.switch_to_frame('frame id')
driver.switch_to_frame('frame-index')無id用索引處理,從0開始
def test_frame(self):
self.driver.get('http://runoob.com/try/try.php?filename=jqueryui-api-droppable')
# 根據(jù) id切換frame
self.driver.switch_to_frame('iframeResult')
print(self.driver.find_element(By.ID, 'draggable').text)
#切換到 父級frame
self.driver.switch_to.parent_frame()
# 切換到默認(rèn)frame
self.driver.switch_to.default_content()
print(self.driver.find_element(By.ID, 'submitBTN').text)
多瀏覽器處理
from selenium import webdriver
import os
class Base():
def setup(self):
browser = os.getenv('browser')
if browser == 'firefox':
self.driver = webdriver.firefox()
elif browser == 'headless':
self.driver = webdriver.PhantomJS()
else:
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(5)
self.driver.maximize_window()
def teardown(self):
self.driver.quit()
執(zhí)行java script
def test_javascript(self):
# 通過js滑動到頁面底部
self.driver.get("http://www.baidu.com")
self.driver.find_element(By.ID,'kw').send_keys('selenium測試')
# 通過 js 獲得元素
ele = self.driver.execute_script("return document.getElementById('su')")
ele.click()
self.driver.execute_script("document.documentElement.scrollTop=100")
sleep(2)
# sleep(1)
print(self.driver.execute_script('return document.title;return JSON.stringify(performance.timing)'))
for code in [
'return document.title','return JSON.stringify(performance.timing)'
]:
print(self.driver.execute_script(code))
- 修改日期
def test_wirte_time(self):
self.driver.get('http://12306.cn/index')
# 執(zhí)行js讓輸入框可編輯
time_ele = self.driver.execute_script('a=document.getElementById("train_date");a.removeAttribute("readonly")')
sleep(3)
# 寫入值
self.driver.execute_script('a=document.getElementById("train_date");a.value = ("2021-08-09")')
# 清楚元素的,readonly屬性
self.driver.execute_script("arguments[0].removeAttribute('readonly')",findElement(self.driver,'xm_cpsj'))
self.driver.execute_script(f"$arguments[0].attr('value','{cpsj}');",findElement(self.driver,'xm_cpsj'))
sleep(2)
# 打印元素 value
print(self.driver.execute_script("return document.getElementById('train_date').value"))
- 文件上傳彈窗處理
# 上傳圖片
def test_upload(self):
self.driver.get("http://www.baidu.com")
self.driver.find_element(By.CLASS_NAME, 'soutu-btn').click()
sleep(2)
self.driver.find_element(By.CLASS_NAME, 'upload-pic').send_keys('x.jpg')
sleep(3)
def test_alter(self):
self.driver.get('http://runoob.com/try/try.php?filename=jqueryui-api-droppable')
self.driver.switch_to_frame('iframeResult')
drag = self.driver.find_element(By.ID,'draggable')
drop = self.driver.find_element(By.ID, 'droppable')
action = ActionChains(self.driver)
action.drag_and_drop(drag,drop).perform()
sleep(2)
print('點(diǎn)擊 alter 確認(rèn)')
self.driver.switch_to_alert().accept()
self.driver.switch_to.default_content()
self.driver.find_element(By.ID,'submitBTN').click()
sleep(3)
PageObject設(shè)計(jì)模式 PageObject原理及六大原則
- 公共方法代表頁面提供的功能
- 不暴露頁面元素信息
- 不在頁面內(nèi)斷言(在業(yè)務(wù)層做斷言)
- 方法應(yīng)該返回別的 PageObject或用于斷言的數(shù)據(jù)
- 不要給整個(gè)頁面建模
- 同樣的行為不同的結(jié)果,應(yīng)建模成不同的方法