环境安装步骤
1.准备好python环境
2.准备selenium环境
3.下载浏览器对应版本的driver,点击下载chromedriver
4.driver配置环境变量
5.在python里导入对应依赖
selenium IDE 录制
点击进入扩展程序
selenium 用例编写
python-selenium文档
selenium常用等待
- 直接等待
time.sleep(3) 等待3秒 - 隐式等待
driver.implicitly_wait(5) 轮训查找(默认0.5)元素是否出现,如果没出现就抛出异常 - 显示等待
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,'腾讯课堂【官方】_腾讯课堂【官方】腾讯课堂官网').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('腾讯课堂')
点击: self.driver.find_element(By.ID, 'su').click() - 定位-xpath
作用域(appium、selenim)
表达式 | 结果 |
---|---|
/div/input[1] | 取div子元素的第一个input元素 |
/div/input[last()] | 取div子元素的最后个input元素 |
/div/input[last()-1] | 取div子元素的倒数第二个input元素 |
/div/input[position()<3] | 取div子元素的前两个book元素 |
//div[@class='classname'] | 得到所有div元素,且这些元素拥有值为classaname的class属性 |
/div/input[price>35] | 得到所有div元素下的所有input,且其中的price元素值大于35,且这些元素拥有值为classaname的class属性 |
nodename | 选取此节点的所有子节点 |
/ | 从根节点选取 |
// | 匹配选择当前节点,不考虑其位置 |
. | 选取当前节点 |
.. | 选取当前节点父节点 |
@ | 选取属性 |
- 定位-css selector
appium 原生元素不能用 css selector定位
表达式 | 结果 | 例子描述 |
---|---|---|
.class | .intro | 选择 class = "intro"的所有元素 |
.id | .idname | 选择 id= "idname"的所有元素 |
* | * | 选择所有元素 |
element | div | 选择所有<div>元素 |
element,element | div,p | 选择所有<div>元素和所有<p>元素 |
element element | div p | 选择<div>元素内部的所有<p>元素 |
element>element | div>p | 选择父元素为<div>元素的所有<p>元素 |
element+element | div+p | 选择紧接在<div>元素之后的所有<p>元素 |
css select f方式
web控件交互
Actions
- 官方文档
- ActionChains:执行鼠标点击、双击、右键、拖拽事件
- TouchActions: 模拟PC移动端、点击、滑动、拖拽、多点触控操作
- 执行原理,调用actionChains方法,不会立即执行,而是讲所有的操作,按顺序放在一个队列里,调用perform()方法时,队列中的事件会依次执行
- 基本用法
- 生成一个动作 action = ActionChains(driver)
- 动作添加方法1 action.方法1
- 调用perform()方法执行(action.perform())
- 写法
- 链式写法 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):
# 光标移动到某个元素
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)
表单
- 表单定义
- 表单是一个包含表单元素的区域
- 表单元素是允许用户在表单中输入信息的元素
- 表单使用标签<form>定义
- 操作表单元素步骤
a. 首先要定位到表单元素
b. 然后操作元素(点击、输入、清空)
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 处理多窗口
多个窗口识别
a. 获取当前窗口句柄:driver。current_window_handle
b. 在获取所有窗口句柄 driver。window_handles
c. 判断是否想要操作的窗口,如果是就可以对窗口进行操作,如果不是跳转到另外一个窗口,对另一个窗口操作 driver.switch_to_window多个窗口切换
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()
# 获取当前所有窗口
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
- 多个frame识别
有两种,嵌套的、非嵌套 - 多个frame之前切换
driver.switch_to.frame() # 根据ID或者index切换frame
driver.switch_to_default_content() # 切换到默认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')
# 根据 id切换frame
self.driver.switch_to_frame('iframeResult')
print(self.driver.find_element(By.ID, 'draggable').text)
#切换到 父级frame
self.driver.switch_to.parent_frame()
# 切换到默认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()
执行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')
# 执行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('点击 alter 确认')
self.driver.switch_to_alert().accept()
self.driver.switch_to.default_content()
self.driver.find_element(By.ID,'submitBTN').click()
sleep(3)
PageObject设计模式 PageObject原理及六大原则
- 公共方法代表页面提供的功能
- 不暴露页面元素信息
- 不在页面内断言(在业务层做断言)
- 方法应该返回别的 PageObject或用于断言的数据
- 不要给整个页面建模
- 同样的行为不同的结果,应建模成不同的方法