selenium框架
一、 Selenuim简介
1.1 什么是Selenuim
selenium是企业主流应用广泛web自动化测试框架
selenium的三大组件:
1、selenium IDE 浏览器插件:实现脚本录制
2、WebDriver 实现对浏览器的各种操作(API包)
3、Grid 分布式执行,用例同时在多个浏览器同时执行,提搞测试效率
1. 开源软件:源代码开放可以根据需要来增加工具的某些功能
2. 跨平台:Linux、Windows、Mac
3. 支持多种浏览器:Firefox、Chrome、IE
4. 支持多种语言:Python、Java、C#、JavaScript、Ruby、PHP等
5. 成熟稳定:目前已经被谷歌、百度、腾讯等公司广泛使用
6. 功能强大:支持商业化大部分功能,由于开源,可定制化功能
二、Python + Selenuim 环境搭建
pip install selenium
常见浏览器:chrome浏览器、IE浏览器、Firefox浏览器
谷歌浏览器驱动:chromedriver.exe
IE浏览器驱动:ieserverdriver.exe
Firefox浏览器驱动:geckodirver.exe
打开浏览器-->右上角三个点-->设置-->关于浏览器
浏览器的版本是129...,所以 chromedriver.exe 的版本也需要是 129...
下载后放置到Python的目录
三、Selenuim操作原理
3.1 web自动化测试第一个脚本
from selenium import webdriver # 指令1:打开浏览器 driver = webdriver.Chrome() # 指令2:加载项目地址 driver.get("https://www.baidu.com") # 不断发送其他指令:不同指令操控浏览器做不同的事情 driver.find_element() driver.close()
driver = webdriver.Chrome()结合selenium源码讲解selenium的原理:
1、启动浏览器驱动(chromedriver.exe)服务
2、selenium脚本与浏览器驱动建立连接,再selenium脚本发送指令(基于http通信)(发送指令给浏览器驱动,浏览器驱动控制浏览器操作)
打开链接 https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol
这里面就是各种指令包(API包):JsonWireProtocol( JWP)
和源码中的各种操作相对应。
driver.get("https://www.baidu.com") response = self.execute(Command.NEW_SESSION, parameters) # 指定请求地址http://ip:端口号/路径+请求方式+请求参数 response = self.command_executor.execute(driver_command, params)
四、Selenuim常用操作
4.1 浏览器操作
import time from selenium import webdriver driver = webdriver.Chrome() driver.get("http://www.baidu.com") # 浏览器最小化 # driver.minimize_window() # 现在不存在这个功能了 # 浏览器最大化 driver.maximize_window() time.sleep(3) # 指定窗口大小 driver.set_window_size(1000, 600) # 浏览器前进后退 driver.back() time.sleep(3) driver.forward() time.sleep(3) # 浏览器标题以及url及页面资源(断言) print(driver.title) # 百度一下,你就知道 print(driver.current_url) # https://www.baidu.com/ print(driver.page_source) # 页面的HTML # 截图(有错误的时候基于当前的界面进行截图) driver.get_screenshot_as_file("./baidu.png") # 关闭浏览器当前窗口 driver.close() # 关闭浏览器的服务 driver.quit()
from selenium import webdriver driver = webdriver.Chrome() driver.get("http://www.baidu.com")
el_select = driver.find_element(By.ID,"kw") ## type: WebElement # el_select = driver.find_element_by_id("kw") ## type: WebElement 以前使用方式 print(el_select) # <selenium.webdriver......> # find_elements、 find_elements_by_id # 返回的是列表
el_select = driver.find_element(By.NAME,"wd") ## type: WebElement # el_select = driver.find_element_by_name("wd") ## type: WebElement 以前使用方式 print(el_select) # <selenium.webdriver.remote....> # find_elements、 find_elements_by_name # 返回的是列表
el_select = driver.find_element(By.TAG_NAME, "input") # el_select = driver.find_element_by_tag_name("input") 以前使用方式 print(el_select) # input标签太多,无法定位到我们选择的那个,所以一般不用,都是组合使用 # find_elements、 find_elements_by_tag_name # 返回的是列表
el_select = driver.find_element(By.CLASS_NAME, "s_ipt") ## type: WebElement # el_select = driver.find_element_by_class_name("s_ipt") ## type: WebElement 以前使用方式 print(el_select) # <selenium.webdriver.remote......> # find_elements、 find_elements_by_class_name # 返回的是列表
# 精确匹配超链接 el_xinwen = driver.find_element(By.LINK_TEXT,"新闻") # el_xinwen = driver.find_element_by_link_text("新闻") # 以前使用方式 el_xinwen.click() # 点击新闻 # find_elements、 find_elements_by_link_text # 返回的是列表
# 模糊匹配超链接 el_xinwen = driver.find_element(By.PARTIAL_LINK_TEXT, "新") # el_xinwen = driver.find_element_by_partial_link_text("新") # 以前使用方式 el_xinwen.click() # 点击新闻 # find_elements、 find_elements_by_partial_link_text # 返回元素列表[] element多了一个s
如果要定位的元素没有id、name、class属性,该如何进行定位? 使用xpath。
xPath是XML Path的简称,是一门在XML文档中查找元素信息的语言
XML是一种标记语言。
● 本质是一种查询语言
●支持逻辑运算、函数
● 实现非常强大的功能
● 可以用于APP自动化测试
import time from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get("http://www.baidu.com") time.sleep(3) # 1. 通过绝对路径定位(不要用) 不只是为了定位这个元素,考虑脚本的稳定 通过/从页面开始标签一直导航到目标标签 ele = driver.find_element(By.XPATH, "/html/body/div[1]/div[2]/div[5]/div[1]/div/form/span[1]/input") # 2. 通过相对路径定位 // 开头 ele = driver.find_element(By.XPATH, '//form/span/input') # 3. 通过标签 + 索引 --> 定位目标标签 ele = driver.find_element(By.XPATH, '//form/span[1]/input[1]') # 4. 通过 唯一定位标签 + 属性 --> 定位目标标签 ele = driver.find_element(By.XPATH, '//form[@id="form"]/span[1]/input[@id="kw"]') # 5. 通过 唯一定位标签+多个属性 使用 and ele = driver.find_element(By.XPATH, '//form[@id="form" and @name="f"]/span[1]/input[1]') # 6. 通过 标签 + 部分属性 s_ipt # substring截取子字符串函数, @class代表取类, 3 代表第三个字符开始 , 截取的结果是 ipt # contains 包含 # start-with 以 ... 字符开头 # text() 内容 ele = driver.find_element(By.XPATH, '//form/span[1]/input[substring(@class,3)="ipt"]') ele = driver.find_element(By.XPATH, '"//form/span[1]/input[contains(@id,"kw")]') ele = driver.find_element(By.XPATH, '//form/span[1]/input[starts‐with(@id,"k")]') ele = driver.find_element(By.XPATH, '//div[@id="s‐top‐left"]/a[text()="新闻"]') # 通过页面符号直接复制过来, 可能会存在定位不够准确 # ele = driver.find_element(By.XPATH, '//*[@id="kw"]') # 元素操作, 输入 ele.send_keys("王勇") time.sleep(3) driver.close() driver.quit()
import time from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get("http://www.baidu.com") driver.maximize_window() # 1. 通过绝对路径定位,一般不用 没有索引操作 ele = driver.find_element(By.CSS_SELECTOR, "html body div div div div div form span input") ele = driver.find_element(By.CSS_SELECTOR, "html>body>div>div>div>div>div>form>span>input") # 2. 通过 id定位 #id值 ele = driver.find_element(By.CSS_SELECTOR, "#kw") # 3. 通过class定位 .class值 ele = driver.find_element(By.CSS_SELECTOR, ".s_ipt") # 4. 通过其他属性定位,并且可以多个属性定位 ele = driver.find_element(By.CSS_SELECTOR, "[autocomplete='off']") ele = driver.find_element(By.CSS_SELECTOR, "[autocomplete='off'][class='s_ipt']") # 5. 通过标签定位 标签名+属性/id/class进行定位 组合定位 ele = driver.find_element(By.CSS_SELECTOR, "input#kw") ele = driver.find_element(By.CSS_SELECTOR, "input.s_ipt") ele = driver.find_element(By.CSS_SELECTOR, "input[autocomplete='off']") # 6. 通过层级定位 层级之间通过>或者空格隔开 相对路径 ele = driver.find_element(By.CSS_SELECTOR, "form#form>span>input.s_ipt") # 7. 通过兄弟节点定位 """ # 场景:同一个元素下面多一个相同的元素 多胞兄弟 # 第一个元素 标签:first‐child # 第二个元素 标签:nth‐child(n) # 最后元素 标签:last‐of‐type """ # ele = driver.find_element(By.CSS_SELECTOR, "div#s‐top‐left>a:first‐child") # ele = driver.find_element(By.CSS_SELECTOR, "div#s‐top‐left>a:nth‐child(2)") # ele = driver.find_element(By.CSS_SELECTOR, "div#s‐top‐left>a:last‐of‐type") # ele.click() ele.send_keys("王勇") time.sleep(3) driver.close() driver.quit() # 定位多个 find_elements, find_elements_by_css_selector
定位方式 XPath CSS 元素名 //input input id //input[@id=‘userA’] #userA class //*[@class=‘telA’] .telA 属性 1.//*[text()==“xxx”] 2.//input[starts-with(@attribute,‘xxx’)] 3.//input[contains(@attribute,‘xxx’)] 1.input[type^=‘p’] 2.input[type$=‘d’ 3.input[type*=‘w’]
1、定位语句不对
2、是否加等待
3、元素嵌套在iframe/frame元素标签中(切换frame)多层嵌套frame/iframe
4、要定位的元素非当前窗口(切换句柄)
4.2 四大操作
ele.send_keys("王勇")
drive.click()
ele.text()
el1.get_attribute("属性名")
import time from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get("http://www.baidu.com") driver.maximize_window() time.sleep(5) # 输入 ele = driver.find_element(By.ID, "kw") ele.send_keys("王勇") # 点击 ele.click() # 获取文本内容 ele = driver.find_element(By.LINK_TEXT, "新闻") print("文本内容", ele.text) # 获取属性值 ele = driver.find_element(By.ID, "kw") print("属性值", ele.get_attribute("autocomplete")) time.sleep(5) driver.close() driver.quit()
4.3 三大切换
import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC """ 切换窗口, 新窗口的元素可能尚未渲染出来,所以需要等待 元素等待 1. 强制等待 time.sleep(秒数) 停留 2. 智能等待 (隐式等待) driver.implicitly_wait(秒数) 给页面上所有的元素设置全局等待时间 3. 显示等待 等待当前需要操作的元素 给予多种条件 + 等待元素 多种条件: 等待元素可见、等待url跳转、等待新窗口出现 ... from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions 自动化测试框架脚本等待优先级: 显示等待 > 只能等待 > 强制等待 """ driver = webdriver.Chrome() # 智能等待 # driver.implicitly_wait(10) driver.get("http://www.baidu.com") driver.maximize_window() # 输入搜索内容 ele1 = driver.find_element(By.ID, "kw") ele1.send_keys("王勇") # 点击百度一下 ele2 = driver.find_element(By.ID, "su") ele2.click() # 显示等待, 等待元素存在, 最大15s, 每隔0.5s检索一次 loc = (By.XPATH, "//div[@id='content_left']/div[1]/div[@class='c-container']/div[1]/h3[1]/a") WebDriverWait(driver, 15, 0.5).until(EC.presence_of_all_elements_located(loc)) # 点击搜索的内容 # ele3 = driver.find_element(By.XPATH, "//div[@id='content_left']/div[1]/div[@class='c-container']/div[1]/h3[1]/a") ele3 = driver.find_element(*loc) ele3.click() # 新打开的窗口里面定位元素 需要切换窗口, 获取浏览器窗口列表 最早打开的窗口放到list的最前面 wins = driver.window_handles # 获取当前的窗口个数 print(wins) # 切换最后打开的窗口 driver.switch_to.window(wins[-1]) # 切换到最后打开的窗口 ele4 = driver.find_element(By.LINK_TEXT, "登录") ele4.click() time.sleep(5) driver.close() driver.quit()
在Web开发中,iframe和frame元素用于在当前HTML文档中嵌入另一个HTML文档。它们允许你在页面的一个区域内显示一个独立的文档,
这个文档可以是来自同一源(域名、协议和端口)的,也可以是跨域的(取决于浏览器的同源策略和安全设置)。
import time from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() # 智能等待 # driver.implicitly_wait(10) driver.get("http://www.baidu.com") driver.maximize_window() # 切换 iframe 方式一: id值 driver.switch_to.frame("id值") # 切换 iframe 方式二: 索引值,从 0 开始 driver.switch_to.frame(3) # 切换 iframe 方式三:找到iframe元素 driver.switch_to.frame(driver.find_element(By.XPATH, "")) # 切换当前 iframe/frame 上一级 iframe/frame # driver.switch_to.parent_frame() # 返回到第一代 iframe/frame # driver.switch_to.default_content() # 再定位元素 driver.find_element(By.LINK_TEXT,"帐号密码登录").click() time.sleep(5) driver.close() driver.quit()
<!-- page.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div class="box" onclick="a()">绑定点击事件后可以完成点击交互</div> <script> function a(){ alert("box标签被点击了") } </script> </body> </html>import time from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get(r"D:\SoftwareTest\Code\web_auto\page.html") driver.maximize_window() ele = driver.find_element(By.CLASS_NAME, "box") ele.click() time.sleep(2) # 弹窗进行处理 alert = driver.switch_to.alert print(alert.text) # 点击确认 alert.accept() # 点击取消 # alert.dismiss() time.sleep(2) driver.close() driver.quit()
4.4 各种操作
<!-- page.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <select class="list"> <option value="val1">列表项1</option> <option value="val2">列表项2</option> <option value="val3">列表项3</option> </select> </div> <input type="submit" value="提交"> </body> </html>import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.select import Select driver = webdriver.Chrome() driver.get(r"D:\SoftwareTest\Code\web_auto\page.html") driver.maximize_window() # 定位到当前下拉框 ele = driver.find_element(By.CLASS_NAME, "list") # 获取下拉框所有的元素对象 select = Select(ele) # # 展示下拉框所有选项内容显示 print("展示下拉框所有选项内容显示", select.options) time.sleep(2) # 实现选择下拉框选项选择 有三种方式 索引 value 选项内容 # 1. 根据索引 选择第 2 个, 索引从 0 开始 select.select_by_index(1) time.sleep(2) # 2. 根据value值选择第 3 个 select.select_by_value("val3") time.sleep(2) # 3. 根据 text 值选择第 1 个 select.select_by_visible_text("列表项1") time.sleep(2) time.sleep(2) driver.close() driver.quit()
import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome() driver.get("http://www.baidu.com") driver.maximize_window() # 键盘输入 driver.find_element(By.ID, "kw").send_keys("王勇") time.sleep(2) # 键盘输入 ctrl + a 全选 driver.find_element(By.ID, "kw").send_keys(Keys.CONTROL, "a") time.sleep(2) # 键盘输入 ctrl + c 复制 driver.find_element(By.ID, "kw").send_keys(Keys.CONTROL, "c") time.sleep(2) # 键盘输入 ctrl + x 剪切 driver.find_element(By.ID, "kw").send_keys(Keys.CONTROL, "x") time.sleep(2) # 键盘输入 ctrl + v 粘贴 driver.find_element(By.ID, "kw").send_keys(Keys.CONTROL, "v") time.sleep(2) driver.close() driver.quit()
import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver import ActionChains """ 鼠标操作 ActionChains 动作链 可以把多个鼠标操作按照顺序连贯的统一执行 """ driver = webdriver.Chrome() driver.get("http://www.baidu.com") driver.maximize_window() time.sleep(2) # 百度首页的设置选项 ele_set = driver.find_element(By.ID, "s-usersetting-top") # 第一种写法 perform() 相当于操作去执行 # ActionChains(driver).move_to_element(ele_set).perform() # 第二种写法 action = ActionChains(driver) action.move_to_element(ele_set) action.perform() time.sleep(2) # 点击高级搜索 ele_gjselect = driver.find_element(By.LINK_TEXT, "高级搜索") ele_gjselect.click() # print("元素的位置", ele_gjselect.location) time.sleep(2) driver.close() driver.quit() """ ActionChains 常用的鼠标操作方法 鼠标常用操作: 滑块操作 click_and_hold 点击鼠标左键不松开 context_click 鼠标右击 double_click 双击 drag_and_drop 从一个元素拖到鼠标到另外一个元素 drag_and_drop_by_offset 拖到某个坐标松开 move_by_offset 鼠标从当前位置移动到某个坐标 move_to_element 移动到元素位置 move_to_element_with_offset 移动到距某个元素(左上角坐标)多少距离的位置 pause 停留 release 释放鼠标 """
只读控件(readonly)的日期输入,不能直接输入内容, 使用 javascript来实现。
曾经的12306的时间是只读,现在不是了,使用12306进行简单测试import time from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get("https://www.12306.cn/index/") driver.maximize_window() time.sleep(2) # 获取时间控件元素(假设是只读元素) ele_data = driver.find_element(By.ID, "train_date") # 如果存在的话,去掉 readonly 属性, 通过 js 操作元素 # argument 把 execute_script 后面的第二个或者第三个或者到第n个参数放在arguments # 也就是 execute_script后面除了 js 之后的参数可能还有很多参数, *args, # 当前场景只处理一个 ele_data, 所以 arguments[0] js = "var ele = arguments[0]; ele.removeAttribute('readonly')" # 执行js脚本,去掉readonly属性 driver.execute_script(js, ele_data) # 清除日期控件默认值 ele_data.clear() time.sleep(2) ele_data.send_keys("2024-09-23") print("时间控件设置的时间: ", ele_data.get_attribute("value")) time.sleep(2) driver.close() driver.quit()
import time from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() driver.get("http://www.baidu.com") driver.maximize_window() time.sleep(2) # 输入框输入王勇并点击 ele_input = driver.find_element(By.ID, "kw") ele_input.send_keys("京东") ele_button = driver.find_element(By.ID, "su") ele_button.click() time.sleep(2) # 显示的网页内容较多,需要的是拉去滚动条往后的数据 # 1. 元素不一定可见,存在即可的情况 # 显示等待 presence_of_element_located不一定元素可见,只要存在即可 loc = (By.XPATH, "//div[@id='11']/div/div/h3/a") WebDriverWait(driver, 15).until(EC.presence_of_all_elements_located(loc)) ele = driver.find_element(*loc) ele.click() time.sleep(5) # 切换页面 wins = driver.window_handles # 获取当前的窗口个数 driver.switch_to.window(wins[-1]) # 2. 懒加载/慢加载 必须把元素移动可见区域,才会实现加载 --> 滚动条操作 # 实现滚动条从顶部到底部 0 --> Height driver.execute_script("scrollTo(0,document.body.scrollHeight)") time.sleep(2) # 实现滚动条从浏览器底部到顶部 Height --> 0 driver.execute_script("scrollTo(document.body.scrollHeight,0)") time.sleep(2) # 操作哪个元素,滚动条移动到元素附近(元素与页面的顶部对齐,元素与页面的底部对齐) js2 = "arguments[0].scrollIntoView(false);" # scrollIntoView(false): 底部对齐 scrollIntoView(): 顶部对齐 _path = "//div[@id='J_fs_col3']/div[@id='J_user']/div[@class='userv4_container normal_bg']/div[4]/a[1]" ele = driver.find_element(By.XPATH, _path) driver.execute_script(js2, ele) time.sleep(5) ele.click() time.sleep(2) driver.close() driver.quit()
<!-- page.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <input type="file" id="file"> </div> </body> </html>import time import win32gui import win32con from selenium import webdriver from selenium.webdriver import ActionChains from selenium.webdriver.common.by import By driver = webdriver.Chrome() driver.get(r"D:\SoftwareTest\Code\web_auto\page.html") driver.maximize_window() time.sleep(3) # 类型一、 直接文件输入 ele_file = driver.find_element(By.ID, "file") ele_file.send_keys(r"D:\SoftwareTest\Code\web\wei.jpg") time.sleep(3) print("方式一 文件上传成功!") # 类型二、不可以直接输入,只能选择 """ 如何定位windows窗口及窗口的元素? 1. 定位工具(失败window窗口及元素)‐‐‐winSpy 2. 第三方库 pywin32 pip install pywin32 import win32gui import win32con 如何定位到上传输入框: #32770‐ComboBoxEx32 ‐ComboBox ‐Edit 打开按钮:#32770‐Button """ ele_file = driver.find_element(By.ID, "file") ActionChains(driver).move_to_element(ele_file).click().perform() def upload(file_path, browser_type="Chrome"): if browser_type == "Chrome": title = "打开" else: title = "文件上传" # 32770‐ComboBoxEx32 ‐ComboBox ‐Edit 上传文件选项框 dialog = win32gui.FindWindow("#32770", title) # 一级窗口 ‘打开窗口’ ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, "ComboBoxEx32", None) # 二级 ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, "ComboBox", None) # 三级 edit = win32gui.FindWindowEx(ComboBox, 0, "Edit", None) # 四级 # 32770‐Button 打开按钮 button = win32gui.FindWindowEx(dialog, 0, "Button", None) # 二级 # 往文件名编辑框中输入文件路径 # 上传操作 win32gui.SendMessage(edit, win32con.WM_SETTEXT, None, file_path) time.sleep(1) win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button) # 点击打开按钮 path = r"D:\SoftwareTest\Code\web\wei.jpg" time.sleep(5) upload(path) print("方式二 文件上传成功!") time.sleep(5) driver.close() driver.quit()