3.元素定位、规避监控、APP自动化测试(Appium)等

news/2024/9/22 15:39:37

元素定位

我们通过webdriver打开一个网络页面,目的是为了操作当前页面已完成浏览器中的一些UI测试步骤,所以必然需要操作网页。而网页的内容组成是由HTML标签(element,也叫元素),所以基于selenium操作网页实际上本质就是操作元素。那么要操作元素就必须先获取元素对象。selenium中关于元素的获取也叫元素的定位,提供了8种元素定位操作可以让测试人员获取一个或多个HTML元素。

定位类型低版本代码新版本代码描述
xpath driver.find_element_by_xpath(“xpath”)<br>driver.find_elements_by_xpath(“xpath”) driver.find_element(By.XPATH, “xpath”)<br>driver.find_elements(By.XPATH, “xpath”) 基于xpath路径表达式对HTML元素进行提取操作
selector driver.find_element_by_css_selector(“css_selector”)<br>driver.find_elements_by_css_selector(“css_selector”) driver.find_element(By.CSS_SELECTOR, “css_selector”)<br>driver.find_elements(By.CSS_SELECTOR, “css_selector”) 基于css选择器对HTML元素进行提取操作
id driver.find_element_by_id(“id”) driver.find_element(By.ID,“id”) 基于HTML元素的id属性对元素进行提取操作
class driver.find_element_by_class_name(class_name")<br>driver.find_elements_by_class_name(class_name") driver.find_element(By.CLASS_NAME, “class_name”)<br>driver.find_elements(By.CLASS_NAME, “class_name”) 基于HTML元素的class属性对元素进行提取操作
tag driver.find_element_by_tag_name(“tag_name”)<br>driver.find_elements_by_tag_name(“tag_name”) driver.find_element(By.TAG_NAME, “tag_name”)<br>driver.find_elements(By.TAG_NAME, “tag_name”) 基于HTML元素的标签名对元素进行提取操作
link_text driver.find_element_by_link_text(“link_text”)<br>driver.find_elements_by_link_text(“link_text”) driver.find_element(By.LINK_TEXT,“link_text”)<br>driver.find_elements(By.LINK_TEXT,“link_text”) 基于HTML元素的超链接文本内容对元素进行提取操作
name driver.find_element_by_name(“name”)<br>driver.find_elements_by_name(“name”) driver.find_element(By.NAME, “name”)<br>driver.find_elements(By.NAME, “name”) 基于HTML元素的name属性对元素进行提取操作,常用于表单元素
partial_link_text driver.find_element_by_partial_link_text(“partial_link_text”)<br>driver.find_elements_by_partial_link_text(“partial_link_text”) driver.find_element(By.PARTIAL_LINK_TEXT, “partial_link_text”)<br>driver.find_elements(By.PARTIAL_LINK_TEXT, “partial_link_text”) 基于HTML元素的部分超链接对元素进行提取操作
基于xpath、css selector与class属性值获取元素
import timefrom selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import Byservice = Service(executable_path="./chromedriver.exe")
driver = webdriver.Chrome(service=service)# 打开一个页面
driver.get("https://www.luffycity.com")# 基于xpath路径获取元素
element = driver.find_element(By.XPATH, '//*[@id="__layout"]/div/div[2]/div/img[1]')# # 基于css选择符获取元素
# element = driver.find_element(By.CSS_SELECTOR, '#__layout &gt; div &gt; div.mbox &gt; div &gt; img.close')# # 基于class属性值来获取元素
# element = driver.find_elements(By.CLASS_NAME, 'close')
# # 如果使用find_elements获取多个元素,返回结果是一个列表,需要通过下标来选择操作的是哪一个?
# element = element[0]# 等待3秒以后点击(这个等待不是必须的,而是为了方便查看而已)
time.sleep(3)
print(element.click())# 等待10秒退出,如果当前窗口只有一个浏览器页面,则表示退出当前浏览器
time.sleep(10)
driver.close()
import timefrom selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import Byoption = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])  # 规避网站监测
option.add_experimental_option('useAutomationExtension', False)  # 去掉开发者警告
service = Service("chromedriver.exe")
driver=webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{'source':'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'}) # 规避网站监测# 打开一个页面
driver.get("https://www.baidu.com")# 基于xpath路径获取元素
element = driver.find_element(By.ID, 'kw')
# 往输入框元素中通过键盘录入数据使用 send_keys()
element.send_keys("路飞学城")# 找到提交按钮并点击
element = driver.find_element(By.ID, 'su')
element.click()time.sleep(3)
# 从搜索结果找到有路飞学城的链接内容,并点击
element = driver.find_element(By.LINK_TEXT, '路飞学城')
element.click()
"""
错误提示:
NoSuchElementException: Message: no such element: Unable to locate element: {"method":"link text","selector":"路飞学城"}
异常,没有这样的一个元素:基于  {"method":"link text","selector":"路飞学城"} 查找不到元素(本地元素不可达)
原因是百度在用户搜索内容以后,采用了ajax进行异步刷新页面数据的,所以会导致selenium代码在元素时,百度服务器有可能没有返回数据结果,没有数据结果则没有该结果连接,因此报错
"""# 等待10秒退出,如果当前窗口只有一个浏览器页面,则表示退出当前浏览器
time.sleep(10)
driver.close()

基于tag获取元素,往往用于获取iframe内嵌框架页中的元素。

import timefrom selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import Byoption = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])  # 规避网站监测
option.add_experimental_option('useAutomationExtension', False)  # 去掉开发者警告
service = Service("chromedriver.exe")
driver = webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{'source':'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'}) # 规避网站监测# 打开一个页面
driver.get("https://mail.163.com")iframe_list = driver.find_elements(By.TAG_NAME, 'iframe')
form_iframe = iframe_list[0]
# 切换窗口到指定iframe
driver.switch_to.frame(form_iframe)driver.find_element(By.NAME, 'email').send_keys('moooluo2022')
time.sleep(3)
driver.find_element(By.NAME, 'email').clear()# 等待10秒退出,如果当前窗口只有一个浏览器页面,则表示退出当前浏览器
time.sleep(10)
driver.close()

小练习:在上面的163邮箱登陆表单中,新增一段代码,实现自动输入密码操作。

import timefrom selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import Byoption = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])  # 规避网站监测
option.add_experimental_option('useAutomationExtension', False)  # 去掉开发者警告
service = Service("chromedriver.exe")
driver = webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{'source':'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'}) # 规避网站监测# 打开一个页面
driver.get("https://mail.163.com")iframe_list = driver.find_elements(By.TAG_NAME, 'iframe')
form_iframe = iframe_list[0]
# 切换窗口到指定iframe
driver.switch_to.frame(form_iframe)driver.find_element(By.NAME, 'email').send_keys('moooluo2022')
# time.sleep(3)
# driver.find_element(By.NAME, 'email').clear()driver.find_element(By.NAME, 'password').send_keys('123456')driver.find_element(By.ID, 'dologin').click()# 等待10秒退出,如果当前窗口只有一个浏览器页面,则表示退出当前浏览器
time.sleep(10)
driver.close()
元素操作
操作描述
click() 点击当前元素
send_keys() 给当前表单元素输入文本内容
clear() 给当前表单元素清空内容
submit() 点击提交按钮,提交表单,要使用submit提交表单则按钮必须有form表单才行,如果ajax提交的不行。
get_attribute() 获取元素的指定属性值
value_of_css_property() 获取元素的CSS样式的指定属性的属性值,不准确.
is_displayed() 查看元素是否显示可见
is_enabled() 查看表单元素是否启用
is_selected() 查看元素是否被选择,一般判断表单元素,如radio单选框或checkbox多选框
size 获取元素的尺寸大小
text 获取元素的文本内容
模拟登陆操作

代码:

import time
from getpass import getpass
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import Bydef get_driver():# 初始化一个谷歌浏览器实例对象service = Service("chromedriver.exe")driver = webdriver.Chrome(service=service)return driverdef task(username, password):# 打开一个网址driver.get("https://www.luffycity.com")time.sleep(3)  # 可以不用,这句代码的作用主要是便于观察# 关闭广告driver.find_element(By.XPATH, '//*[@id="__layout"]/div/div[2]/div/img[1]').click()# 点击登陆driver.find_element(By.CLASS_NAME, 'signin').click()time.sleep(3)# 往账号输入框输入账号element = driver.find_element(By.XPATH, '//*[@id="__layout"]/div/div[2]/div/div[2]/div[1]/div[1]/input')element.send_keys(username)# 往密码输入框输入密码element = driver.find_element(By.XPATH, '//*[@id="__layout"]/div/div[2]/div/div[2]/div[1]/div[2]/input')element.send_keys(password)element = driver.find_element(By.XPATH, '//*[@id="__layout"]/div/div[2]/div/div[2]/button')element.click()time.sleep(5)driver.quit()if __name__ == '__main__':username = input("账号: ")# python的getpass会与pycharm内置的run终端形成阻塞,# 所以使用了getpass,则需要改成cmd或pycharm的Terminal终端来运行python脚本password = getpass("密码:")driver = get_driver()task(username, password)
查看操作元素的相关属性
import time
from getpass import getpass
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By# 初始化一个谷歌浏览器实例对象
service = Service("chromedriver.exe")
driver = webdriver.Chrome(service=service)# 打开一个网址
driver.get("http://localhost:63342/code/7.html?_ijt=gom325r5bev2q5u5q3uelkchje")# # 查看元素的显示模式,是否是可见
# element = driver.find_element(By.NAME, 'access_token')
# display = element.is_displayed()
# print(display)
#
# # 查看元素的属性值
# print(element.get_attribute("value"))
# outline = element.value_of_css_property('border')
# print(outline)# element = driver.find_element(By.XPATH, '/html/body/form/input[4]')
# enabled = element.is_enabled()
# print(enabled)# # 提交表单
# element = driver.find_element(By.XPATH, '/html/body/form/input[5]')
# element.submit()element = driver.find_element(By.XPATH, '/html/body/h1')
print(element.text)time.sleep(5)
driver.quit()
规避监测

现在不少网站有对selenium采取了监测机制。这些监测机制会导致我们使用selenium访问网站时出现各种拦截机制,如出现验证码等。

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Serviceservice = Service("chromedriver.exe")
driver=webdriver.Chrome(service=service)driver.get("https://www.baidu.com")driver.find_element(By.ID, "kw").send_keys("路飞学城")
driver.find_element(By.ID, "su").click()time.sleep(3)
driver.quit()

解决方案:

import time
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Serviceoption = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])  # 规避网站监测
option.add_experimental_option('useAutomationExtension', False)  # 去掉开发者警告service = Service("chromedriver.exe")
driver = webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {'source':'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'}) # 规避网站监测driver.get("https://www.baidu.com")driver.find_element(By.ID, "kw").send_keys("路飞学城")
driver.find_element(By.ID, "su").click()time.sleep(5)
driver.quit()
鼠标事件

在上面的selenium操作中,我们获取元素可以直接调用click方法实现鼠标点击效果。但是,如果要进行更加复杂多样的鼠标操作,如鼠标右键、鼠标移动、拖动等等,则需要依赖于 ActionChains (动作链) 模块提供的鼠标操作来完成。

from selenium.webdriver.common.action_chains import ActionChains

基本使用

import time
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.action_chains import ActionChains# 初始化一个谷歌浏览器实例对象
option=ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])
option.add_experimental_option('useAutomationExtension', False)
service = Service("chromedriver.exe")
driver=webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{'source':'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'})# 打开一个网址
driver.get("https://www.luffycity.com")# 关闭广告
element = driver.find_element(By.XPATH, '//*[@id="__layout"]/div/div[2]/div/img[1]')
element.click()time.sleep(5)
# 定位元素,定位到顶部导航菜单的"题库"上面
element = driver.find_element(By.XPATH, '//*[@id="__layout"]/div/header/div/div/nav/a[6]')
# move_to_element 把鼠标悬停在指定元素上面
# context_click 执行鼠标右键
# 动作链在设置动作以后,不会自动执行,所以需要在动作链的末尾,调用perform执行整个动作链
ActionChains(driver).move_to_element(element).context_click().perform()time.sleep(5)
driver.quit()

ActionChains动作链可以保存1个或多个连贯的鼠标操作,但是最终执行鼠标操作需要调用perform()方法。常用鼠标操作:

操作描述
double_click(element) 鼠标双击
context_click(element) 鼠标右击
drag_and_drop(source, target) 鼠标拖动(将一个元素移动到另一个元素位置)
drag_and_drop_by_offset(source, xoffset, yoffset) 鼠标拖动(将一个元素移动到指定坐标位置)
move_to_element(element) 鼠标移动并悬放到指定元素的上方
move_by_offset(xoffset, yoffset) 将鼠标从当前位置移动到指定坐标处

测试页面:

&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;&lt;meta charset="UTF-8"&gt;&lt;title&gt;Title&lt;/title&gt;&lt;style&gt;.box{width: 100px;height: 100px;background: red;}.box:hover{background: blue;}&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;&lt;div class="box"&gt;&lt;/div&gt;&lt;script&gt;var box = document.querySelector(".box")box.ondblclick = function(){box.style.background = "yellow";}&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

测试双击与鼠标选放

import timefrom selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.action_chains import ActionChainsservice = Service("chromedriver.exe")
driver=webdriver.Chrome(service=service)# 打开一个网址
driver.get("C:/Users/Administrator/Desktop/code/11-测试页面.html")element = driver.find_element(By.CLASS_NAME, 'box')
ActionChains(driver).move_to_element(element).perform()
time.sleep(1)
ActionChains(driver).double_click().perform()
time.sleep(3)
driver.quit()

拖拽元素

import time
from selenium import webdriver
from selenium.webdriver import ChromeOptions, ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.keys import Keysoption=ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])
option.add_experimental_option('useAutomationExtension', False)
service = Service("chromedriver.exe")
driver=webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{'source':'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'})# 设置浏览器窗口最大化
driver.maximize_window()# 进入页面
driver.get('https://www.jq22.com/yanshi10850')iframe = driver.find_element(By.TAG_NAME, "iframe")
driver.switch_to.frame(iframe)element1 = driver.find_element(By.XPATH, '//*[@id="bar"]/li[1]')
element2 = driver.find_element(By.XPATH, '//*[@id="foo"]')
time.sleep(3)
ActionChains(driver).drag_and_drop(element1, element2).perform()time.sleep(10)
driver.quit()
键盘事件

前面我们在元素操作中使用了send_keys()方法来模拟键盘输入,而针对复杂的组合键盘操作,webdriver提供了键盘上几乎所有的按键方法,使用前导入Keys类即可。

from selenium.webdriver.common.keys import Keys
方法名描述
send_keys(Keys.ENTER) 回车键Enter
send_keys(Keys.BACK_SPACE) 删除键BackSpace
send_keys(Keys.SPACE) 空格键(Space)
send_keys(Keys.TAB) 制表键(Tab)
send_keys(Keys.ESCAPE) 复位键Esc
send_keys(Keys.CONTROL,‘a’) 全选Ctrl+A
send_keys(Keys.CONTROL,‘c’) 复制Ctrl+C
send_keys(Keys.CONTROL,‘x’) 剪切Ctrl+X
send_keys(Keys.CONTROL,‘v’) 粘贴Ctrl+V
send_keys(Keys.F1) 键盘F1
…… ……
send_keys(Keys.F12) 键盘F12
   
基本使用

页面:

&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;&lt;meta charset="UTF-8"&gt;&lt;title&gt;Title&lt;/title&gt;&lt;style&gt;&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;textarea name="content" id="" cols="30" rows="10"&gt;hello!EveryBody!&lt;/textarea&gt;
&lt;/body&gt;
&lt;/html&gt;

代码:

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.keys import Keysservice = Service("chromedriver.exe")
driver = webdriver.Chrome(service=service)
driver.get("C:/Users/Administrator/Desktop/code/12-测试页面.html")
time.sleep(3)
element = driver.find_element(By.TAG_NAME, "textarea")
element.send_keys(Keys.CONTROL, 'a')
element.send_keys(Keys.BACK_SPACE)time.sleep(3)
element.send_keys("2012年9月25日,辽宁舰正式交付中国海军;2019年12月17日,山东舰入列,中国海军进入双航母时代;2022年6月17日,福建舰来了,我们有三艘航母了。")time.sleep(5)
driver.quit()

回车键等操作

import time
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.keys import Keysoption=ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])
option.add_experimental_option('useAutomationExtension', False)
service = Service("chromedriver.exe")
driver=webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{'source':'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'})# 设置浏览器窗口最大化
driver.maximize_window()
# driver.minimize_window()  # 最小化
# 进入页面
driver.get('https://www.baidu.com/')
# 定位输入框
element = driver.find_element(By.ID, "kw")
# 向输入框中输入内容
element.send_keys("路飞学城")
time.sleep(2)
# 删除上一步中多输入的文字
element.send_keys(*[Keys.BACK_SPACE for i in range(2)])
element.send_keys("在线教育")time.sleep(2)
# 使用回车代替点击按钮
element.send_keys(Keys.ENTER)
time.sleep(2)
屏幕截图

在selenium中,截取网页的图片有多种方式,一般常用的有2种方式:截取可见区域和截取指定区域。

截取可见区域

主要是通过driver.save_screenshot来完成。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver import ChromeOptions
from selenium.webdriver.chrome.service import Service# 初始化一个谷歌浏览器实例对象option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
option.add_experimental_option('useAutomationExtension', False)
service = Service("chromedriver.exe")
driver = webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{'source': 'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'})driver.get('https://www.luffycity.com')# 关闭广告
element = driver.find_element(By.XPATH, '//*[@id="__layout"]/div/div[2]/div/img[1]')
element.click()# 调用浏览器驱动对象的save_screenshot方法就可以实现截图
driver.save_screenshot('./luffycity.png')  # 图片必须保存为 png 格式
driver.quit()

save_screenshot使用过程中,需要注意2点:

  1. save_screenshot方法保存的图片格式必须是png格式,否则不行。
  2. save_screenshot保存图片的目录,必须是已经存在的,否则无法保存图片。
截取指定区域

通过先获取HTML文档中的元素对象,再通过元素对象调用screenshot 来进行截取。

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver import ChromeOptions
from selenium.webdriver.chrome.service import Service# 初始化一个谷歌浏览器实例对象
option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
option.add_experimental_option('useAutomationExtension', False)
service = Service("chromedriver.exe")
driver = webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{'source': 'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'})driver.get('https://www.luffycity.com')# 关闭广告
element = driver.find_element(By.XPATH, '//*[@id="__layout"]/div/div[2]/div/img[1]')
element.click()# 点击登陆
driver.find_element(By.CLASS_NAME, 'signin').click()
time.sleep(3)# 往账号输入框输入账号
element = driver.find_element(By.XPATH, '//*[@id="__layout"]/div/div[2]/div/div[2]/div[1]/div[1]/input')
element.send_keys("13928835901")# 往密码输入框输入密码
element = driver.find_element(By.XPATH, '//*[@id="__layout"]/div/div[2]/div/div[2]/div[1]/div[2]/input')
element.send_keys("123")element = driver.find_element(By.XPATH, '//*[@id="__layout"]/div/div[2]/div/div[2]/button')
element.click()time.sleep(2)
element = driver.find_element(By.XPATH, '//*[@id="__layout"]/div/div[2]/div')
# 通过元素的 screenshot 方法直接保存图片
element.screenshot('./login_result.png')
time.sleep(3)
driver.quit()
等待机制

针对一些通过ajax局部刷新或延时显示的数据,在selenium使用过程中如果没有等待数据显示就直接执行后续代码就会有问题。

import time
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Serviceoption=ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])
option.add_experimental_option('useAutomationExtension', False)
service = Service("C:/Users/Administrator/Desktop/test/测试自动化-day04/素材/chromedriver.exe")
driver=webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{'source':'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'})driver.get("http://www.baidu.com")driver.find_element(By.ID, "kw").send_keys("路飞学城")
driver.find_element(By.ID, "su").click()
# time.sleep(3)
driver.find_element(By.PARTIAL_LINK_TEXT, "路飞学城").click()
time.sleep(3)
driver.quit()

上面虽然使用了time.sleep(3)让selenium强制等待了3秒,但是这种操作不够灵活,因为数据加载有时候不需要3秒就显示出来了,而程序并没有办法知道而导致最终呆呆的等待了3秒才继续执行。当然,也有可能3秒后数据还没有出来,那么程序则依然报错。所以开发中针对上述问题,我们是不能使用time.sleep来草草了事的,而是要使用selenium提供的另外两种等待机制。

显式等待
import time
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditionsoption=ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])
option.add_experimental_option('useAutomationExtension', False)
service = Service("chromedriver.exe")
driver=webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{'source':'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'})driver.get("http://www.baidu.com")driver.find_element(By.ID, "kw").send_keys("路飞学城")
driver.find_element(By.ID, "su").click()
# 使用time.sleep这种机械化的强制等待,实际上是有可能出问题的。即便没有问题,也会存在着让测试代码浪费等待时间的情况。
# time.sleep(3)
# driver.find_element(By.PARTIAL_LINK_TEXT, "路飞学城").click()# 显式等待
WebDriverWait(driver=driver, timeout=60, poll_frequency=0.5, ignored_exceptions=None).until(expected_conditions.presence_of_element_located((By.PARTIAL_LINK_TEXT, '路飞学城'))).click()time.sleep(3)
driver.quit()

selenium提供了 WebDriverWait类实现显式等待机制,WebDriverWait类接收4个参数来指定等待机制。

  • driver,浏览器驱动对象
  • timeout,最长超时等待时间,单位(秒)
  • poll_frequency,轮询检测等待条件的时间,也就是每隔多长时间检测一次条件,默认是0.5秒
  • ignored_exceptions,timeout超时后的异常信息,默认抛出NoSuchElementException

基本使用:

WebDriverWait(driver=driver, timeout=10, poll_frequency=0.5, ignored_exceptions=None)

WebDriverWait类提供了两个方法来完成等待条件的检测实现:

  • until(self, method, message=‘’),method为等待检测条件的判断方法,until表示直到返回True,用的较多。
  • until_not(self, method, message=‘’),method为等待检测条件的判断方法,until_not表示直到返回False。

上面代码用到的method指定为expected_conditions模块并调用其presence_of_element_located方法判断指定元素是否存在。

expected_conditions模块提供了各种判断:

  • presence_of_element_located判断某个元素是否存在于HTML文档中。
  • presence_of_elements_located 判断是否至少有1个元素存在HTML中。只要有1个元素存在,则该方法就返回True。

显式等待的另一种写法,首先实例化一个显式等待对象,这样可以在各个地方灵活的调用:

import time
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditionsoption=ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])
option.add_experimental_option('useAutomationExtension', False)
service = Service("chromedriver.exe")
driver=webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{'source':'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'})# 1. 先创建一个显式等待对象
wait = WebDriverWait(driver=driver, timeout=60, poll_frequency=0.5, ignored_exceptions=None)driver.get("http://www.baidu.com")driver.find_element(By.ID, "kw").send_keys("路飞学城")
driver.find_element(By.ID, "su").click()
# 使用time.sleep这种机械化的强制等待,实际上是有可能出问题的。即便没有问题,也会存在着让测试代码浪费等待时间的情况。
# time.sleep(3)
# driver.find_element(By.PARTIAL_LINK_TEXT, "路飞学城").click()# 2. 显式等待对象调用判断等待方法
wait.until(expected_conditions.presence_of_element_located((By.PARTIAL_LINK_TEXT, '路飞学城'))).click()time.sleep(3)
driver.quit()
隐式等待

也叫全局等待。我们可以直接通过浏览器驱动对象driver调用隐式等待,并且用法也相对简单:

import time
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditionsoption=ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])
option.add_experimental_option('useAutomationExtension', False)
service = Service("chromedriver.exe")
driver=webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{'source':'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'})
# 设置隐式等待
driver.implicitly_wait(time_to_wait=10)  # 只需要一个等待超时时间参数driver.get("https://www.baidu.com")driver.find_element(By.ID, "kw").send_keys("路飞学城")
driver.find_element(By.ID, "su").click()driver.find_element(By.PARTIAL_LINK_TEXT, "路飞学城").click()time.sleep(3)
driver.quit()

implicitly_wait等待时间单位为秒,如上例所示,我们指定了10秒。需要注意的是,隐式与显式等待有明显的区别,隐式等待应用于全局,每当使用driver驱动找某个元素时,隐式等待机制就会被触发(导致测试代码的运行速度变慢),如果元素存在,则继续执行,否则,它将以轮询的方式判断元素是否定位成功,直至等待超时,抛出错误NoSuchElementException。而显式等待则只是指定某(些)个元素是否存在时执行。

在等待机制的选择上,我们可以在三种等待机制中灵活选择:

  • 普通(静态页面较多)网页,强制等待和显式等待可以相互搭配,提高效率。适用于前后端不分离的UI场景测试。
  • 动态页面较多的时候,则可以全局设置隐式等待。适用于前后端分离的UI场景测试
窗口切换

在测试客户端时,往往存在有些功能流程需要点击打开并操作多个窗口页面的情况。此时就需要使用selenium在多个窗口中相互切换操作了。selenium中提供了三个方法给测试开发人员完成窗口切换操作。

方法名描述
driver.switch_to.window 切换普通窗口
driver.switch_to.frame 切换进入iframe窗口
driver.switch_to.default_content 切换退出iframe窗口
driver.window_handles 窗口数组
切换普通窗口
import time
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.support.wait import WebDriverWait  # 等待页面加载某些元素
from selenium.webdriver.support import expected_conditionsoption = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
option.add_experimental_option('useAutomationExtension', False)
service = Service("chromedriver.exe")
driver = webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{'source': 'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'})wait = WebDriverWait(driver, 10)try:driver.get("https://www.baidu.com")driver.find_element(By.ID, "kw").send_keys("路飞学城")driver.find_element(By.ID, "su").click()wait.until(expected_conditions.presence_of_element_located((By.LINK_TEXT, '路飞学城'))).click()# 查看当前浏览器中打开的窗口列表print(driver.window_handles)time.sleep(3)# 根据数组下标索引切换窗口driver.switch_to.window(driver.window_handles[0])time.sleep(3)driver.find_element(By.LINK_TEXT, '百度百科').click()print(driver.window_handles)  # 此时应该有3个窗口了time.sleep(3)driver.switch_to.window(driver.window_handles[1]) # 切换到路飞窗口
finally:time.sleep(3)driver.quit()
切换iframe窗口

两个方法:

  • switch_to.frame(iframe),进入窗口
  • switch_to.default_content(),退出窗口
import time
import getpass
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Servicedef get_driver():"""获取浏览器驱动对象"""option = ChromeOptions()option.add_experimental_option('excludeSwitches', ['enable-automation'])option.add_experimental_option('useAutomationExtension', False)service = Service("chromedriver.exe")driver = webdriver.Chrome(service=service, options=option)driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument",{'source': 'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'})# 设置隐式等待driver.implicitly_wait(10)return driverdef task(url, username, password, to, theme):"""发送邮件:param url  打开站点地址:param username 登陆账号:param password 登陆密码:param to 收件人邮箱账号:param theme 邮件的主体"""driver.get(url)iframe = driver.find_elements(By.TAG_NAME, 'iframe')driver.switch_to.frame(iframe[0])driver.find_element(By.CLASS_NAME, 'dlemail').send_keys(username)driver.find_element(By.CLASS_NAME, 'dlpwd').send_keys(password)driver.find_element(By.ID, 'dologin').click()# 登陆以后刷新了页面了,所以需要重新获取driver浏览器驱动对象,否则无法进行后续操作driver.switch_to.window(driver.window_handles[0])driver.find_element(By.ID, '_mail_component_149_149').click()driver.find_element(By.CLASS_NAME, 'nui-editableAddr-ipt').send_keys(to)driver.find_elements(By.CLASS_NAME, 'nui-ipt-input')[2].send_keys(theme)content_iframe = driver.find_element(By.CLASS_NAME, 'APP-editor-iframe')driver.switch_to.frame(content_iframe)driver.find_element(By.TAG_NAME, "p").send_keys("这是通过selenium添加的邮件内容!!!")driver.switch_to.default_content()# 发送邮件driver.find_elements(By.CLASS_NAME, 'nui-btn-text')[2].click()if __name__ == '__main__':url = 'https://mail.163.com'theme = '一份测试邮件'to = '649641514@qq.com'content = '测试邮件内容.................................'# username = input('用户名: ').strip()username = "moooluo2022"# pycharm中直接运行python脚本会导致getpass进入阻塞,所以需要使用终端命令行运行python脚本password = getpass.getpass(prompt="密码: ")driver = get_driver()try:task(url, username, password, to, content)except Exception as e:print(f"发送邮件出错:{e}")finally:time.sleep(20)driver.quit()
执行js代码

实际上,我们之前有提到关于selenium实际上操作浏览器都是通过webdriver完成对应的功能操作的,而webdriver实际上是通过js代码来控制浏览器的。因此针对如果selenium本身如果没有提供的操作,则我们可以使用js代码来完成一些窗口操作。例如:滚动条。

import time
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Serviceoption = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])  # 规避网站监测
option.add_experimental_option('useAutomationExtension', False)  # 去掉开发者警告service = Service("chromedriver.exe")
driver = webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {'source':'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'}) # 规避网站监测driver.get("https://www.baidu.com")# # 执行没有返回的值的js代码
# driver.execute_script('confirm("hello, luffycity!")')
#
# # 关闭alert弹窗
# time.sleep(3)
# # 让driver浏览器驱动对象,切换焦点(切换上下文)到弹窗
# alert = driver.switch_to.alert
# # 点击确定,以达到关闭弹窗的效果
# # alert.accept()
# alert.dismiss()   # 关闭弹窗,相当于点击了取消"""让浏览器执行js代码并获取代码的返回值""""""例如:获取cookie"""
# result = driver.execute_script('return document.cookie')
# cookies = result.split(";")
# cookies_dict = {i[0]:i[1] for i in [item.split("=") for item in cookies]}
# print(cookies_dict.get("BIDUPSID"))
# 有了cookie以后,以后就可以跳过登陆测试其他的功能操作了。"""例如:获取本地存储中的token"""
result = driver.execute_script("return localStorage")
print(result) #
time.sleep(5)
driver.quit()

操作滚动条

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Serviceservice = Service("chromedriver.exe")
driver = webdriver.Chrome(service=service)driver.get("https://www.luffycity.com")# 关闭广告
element = driver.find_element(By.XPATH, '//*[@id="__layout"]/div/div[2]/div/img[1]')
element.click()num = 0
while num &lt;= driver.execute_script("""return parseInt(getComputedStyle(document.querySelector('.main'))["height"])"""):num += 1driver.execute_script(f"window.scrollTo(0, {20*num})")time.sleep(0.01)time.sleep(3)
driver.quit()
无头浏览器

所谓的无头浏览器(Headless),实际上就是不需要打开浏览器去操作浏览器完成对应UI效果。

import time
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import Byoption = ChromeOptions()
option.add_experimental_option('excludeSwitches',['enable-automation'])  # 规避网站监测
option.add_experimental_option('useAutomationExtension', False)  # 去掉开发者警告# 开启浏览器的无头模式
option.add_argument('--headless')
option.add_argument('--disable-gpu')  # 允许在无GPU的环境下运行,可选
option.add_argument('--window-size=1920x1080')  # 建议设置service = Service("chromedriver.exe")
driver = webdriver.Chrome(service=service, options=option)
driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {'source':'Object.defineProperty(navigator,"webdriver",{get:()=&gt;undefind})'}) # 规避网站监测
# 设置隐式等待
driver.implicitly_wait(time_to_wait=10)  # 只需要一个等待超时时间参数# 打开网页
driver.get("https://www.baidu.com")
# 搜索内容
driver.find_element(By.ID, "kw").send_keys("路飞学城")
driver.find_element(By.ID, "su").click()# 点击搜索结果
driver.find_element(By.PARTIAL_LINK_TEXT, "路飞学城").click()# 调用浏览器驱动对象的save_screenshot方法就可以实现截图
driver.save_screenshot('./baidu_search_result.png')  # 图片必须保存为 png 格式driver.quit()

使用无头浏览器,在运行一些经过验证的测试脚本时,可以达到节约系统资源的优点,而且少了浏览器的UI效果,UI测试脚本的运行速度会加快。

APP自动化测试

APP移动端测试是指对移动端应用进行的测试,测试应用功能是否满足特定的需求。移动端测试一般分3类:APP功能测试、APP自动化测试、APP安全测试。其中常用的APP自动化测试工具有:Robtium、macaca、Appium、UiAutomator、Monkey、MonkeyRunner、Instrumentation、Athrun等等。

工具支持语言跨平台跨应用 
Robotium Java Android 不支持  
Macaca Java、Python、node.js Android、IOS 支持 可以作为简洁版的Appium工具
Appium Java、c#、Python、PHP、Perl、Ruby、node.js Android、IOS、H5 支持  

Appium

基本介绍

Appium由Sauce labs公司(是美国的一家提供自动化的软件测试服务公司)基于node.jsexpress框架开发http server,是一个开源、跨平台的移动端自动化测试框架,可以用来测试原生及混合的移动端应用。Appium支持IOS、Android及H5等移动端应用。Appium使用WebDriver的json wire协议来驱动Apple系统的UIAutomation库(由苹果官方提供的自动化测试库)、Android系统的UIAutomator框架(由Android官方提供的自动化测试库)。

img

与selenium的关系

appium继承了selenium的webdriver,也就是selenium2.0,所以appium在调试中实际上也调用了selenium的某些功能。

appium起到了一个电脑连接移动端的桥梁,然后我们可以在电脑上调用selenium工具来调试移动端应用。

appium原理

appium本质上就是一个使用node.js编写的http server(Http服务器),它对外暴露了一系列REST API接口提供给测试开发人员进行调用。

这个http server的功能其实很简单:监听一个端口,然后接收由client发送来的command。翻译这些command,把这些command转成移动设备可以理解的形式发送给移动设备,然后移动设备执行完这些command后把执行结果返回给httpserver,http server再把执行结果返回给client。

在这里client其实就是发起command的设备,一般来说就是我们编写代码执行的机器,执行appium测试代码的机器。狭义点理解,可以把client理解成是代码,当然这些代码可以是java/ruby/python/js的,只要它实现了webdriver标准协议就可以。

这样的设计思想带来了一些好处:

  • 可以带来多语言的支持;
  • 可以把server放在任意机器上,哪怕是云服务器都可以;(是的,appium和webdriver天生适合云测试)

img

安装步骤

安装java环境

目前,java环境普遍来说使用的都是java8,所以我们直接下载安装1.8版本的sdk即可(jdk是Java语言的软件开发工具包,是整个java开发的核心,它包含了JAVA的运行环境,JAVA工具和JAVA基础的类库)。

下载地址:https://www.oracle.com/java/technologies/downloads/

鼠标右键安装(注意,不要把它安装到有中文的路径下,所以最好默认路径即可),一路点击确定下一步即可完成安装。

注意:javasdk环境是依赖于JAVA_HOME的,依次打开控制面板系统与安全系统高级系统设置环境变量系统变量新建。变量名中输入JAVA_HOME,变量值中填写刚才获取到的路径C:\tool\Java\jdk1.8.0_201(注意,此处根据自己的实际路径填写,别瞎复制)。

 

保存了JAVA_HOME环境变量,点击下方的Path环境变量,里面把java sdk安装目录下bin目录加入到环境变量中。

 

cmd终端输入java -version,出现如下内容表示安装完成。

 

安装Android SDK

[Android SDK](https://baike.baidu.com/item/Android SDK)(software development kit,译作:软件开发工具包),是用于为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件的开发工具的集合。Android SDK 指的是Android专属的软件开发工具包。

下载地址:https://www.androiddevtools.cn/#sdk-tools

 

把下载下来的sdk压缩包解压到一个没有中文路径的目录下。例如:我的是 C:/tool/

 

解压完成以后,进入sdk目录下,点击 SDK Manager.exe(sdk开发工具管理器,提供了类似pip的功能)。

按下面图中所示,勾选安卓开发最基本的7个模块到本地。

 

 

 

安装完成以后,Android SDK Tools会在安装成功以后,从上面隐藏掉,不用在意。

接下来,需要把以下三个路径加入到环境变量中,让系统能识别 android sdk(注意根据自己实际的解压路径填写,不要瞎复制)。

C:\tool\android-sdk-windows\tools
C:\tool\android-sdk-windows\platform-tools
C:\tool\android-sdk-windows\build-tools\29.0.3

 

cmd终端下输入命令adb,出现如下效果则安装正确。

 

  • adb.exe( Android Debug Bridge,安卓调试桥),调试app用的命令行工具,借助这个工具,我们可以直接在PC端就可以通过USB或者wifi就可以管理设备或模拟器的状态。保存在android-sdk-windows\platform-tools
  • aapt.exe(Android Asset Packaging Tool),安卓开发使用的一个自动资源打包工具,可以用来检测apk的包名和activity名称。保存在android-sdk-windows\build-tools\&lt;安卓sdk版本&gt;
安装模拟器

appium既支持使用真机测试,也支持模拟器测试。不过我们测试过程中实际上也并非一定要使用真机,因为我们测试的并非是移动端的操作系统而是app本身,所以很多时候测试开发过程中使用模拟器会更加方便,最关键的是模拟器可以轻松切换不同版本。这里推荐使用夜神模拟器(它不仅有windows版本,也有ios版本,而像其他的雷神模拟器,则仅支持windows版本,没有ios版本)。

下载地址:https://www.yeshen.com/

提示:如果windows下同时安装了安卓模拟器和docker-desktop的同学,如果无法顺利启动模拟器,可能需要执行以下命令,切换模拟器与docker-desktop的虚拟化服务。

# 使用模拟器
bcdedit /set hypervisorlaunchtype off
# 使用docker-desktop
bcdedit /set hypervisorlaunchtype auto

模拟器默认在安装以后会在bin目录下提供一个adb.exe安卓调试桥接工具(夜神模拟器叫nox_adb.exe),但是这个工具的版本有可能与我们安装的android sdk的abd.exe版本不一样,这样会导致无法使用appium调试模拟器中的移动端应用,所以需要把android sdk的abd.exe复制并改名替换掉模拟器bin目录下的adb.exe。真机测试则没有这个问题。

找到android sdk安装目录下platform-tools目录下的adb.exe。

 

找到夜神安装目录的bin目录下的nox_adb.exe,并备份,然后替换成上面的。

同时打开模拟器中的配置,修改为手机版面,并开启开发者模式,并勾选开启USB调试功能。

 

 

 

 

点击7下召唤神龙~。。。。说错了,重来,点击7点是打开当前设备的开发者选项。

 

返回上一步,就可以看到多了一个开发者选项了,接下来,开启USB调试选项。

 

 

安装appium

因为版本更新的原因,实际上appium是存在着2个分支版本的,分别是appium Server 与 appium Desktop。其中,appium Server的安装比较复杂需要先安装node.js,所以目前来说官方已经不再更新与维护appium Server分支了,而是推荐测试开发者安装 appium Desktop版本。所以此处,我们直接通过以下链接到github下根据自己当前使用的操作系统安装appium Desktop即可。

下载地址:https://github.com/appium/appium-desktop/releases

 

下载到本地以后双击exe文件,一路默认安装即可。

完成上面操作以后,打开终端输入adb devices ,看到如下效果,则表示安装环境全部完成。

 

> adb devices的结果是当前连接到PC端的所有的移动端设备列表。左侧参数是设备ID,右侧参数是设备的连接状态。 > > 如果使用模拟器则显示效果如下: > 127.0.0.1:5555 device # 表示雷电模拟器 > 127.0.0.1:62001 device # 表示夜神模拟器 > > 如果使用真机则显示效果如下: > UJN0221722001562 device

注意:鸿蒙手机实际上虽然不是安卓系统,但是鸿蒙手机为了兼容安卓,实际上也提供了adb调试,但是很遗憾的是,我们不能直接使用USB调试,只能改用wifi调试才可以测试鸿蒙系统下的app。

adb命令

以下是开发中比较常用的adb命令:

命令描述
adb devices 查询连接到系统的所有移动端设备状态,常见状态:<br>device:连接正常<br/>offline:已断开<br/>unauthorized:未授权(手机端弹出的调试框没有允许)
adb -s 设备ID 指定设备使用adb,设置ID通过上面adb devices可以获取
adb -s 设备ID shell [命令] 使用Android Linux内核的命令
adb -s 设备ID install -r 包名+路径 安装apk包,-r表示覆盖安装,可以使用aapt d badging apk文件路径查看app包名。
adb -s 设备ID uninstall 包名 卸载apk
adb -s 设备ID push 电脑路径 手机路径 电脑文件上传至手机
adb -s 设备ID pull 手机路径 电脑路径 手机文件下载至电脑
adb -s 设备ID shell pm list packages 列出手机中装的所有APP的包名
adb -s 设备ID shell pm clear apk包名 清除应用数据及缓存
**`adb -s 设备ID shell dumpsys window windows grep mFocusedApp`**

安装:

# 通过自动打包工具aapt,查看下载回来的apk的包名,并把源apk文件名改成包名。
aapt d badging C:\Users\Administrator\Desktop\test\jd.apk# 通过adb指定设备,进行安装
adb -s 127.0.0.1:62001 install C:\Users\Administrator\Desktop\test\com.jingdong.app.mall.apk# 卸载apk包
adb -s 127.0.0.1:62001 uninstall com.jingdong.app.mall
安装appium-inspector

Appium Inspector是appium Server UI内置的一个元素定位工具,在早期版本中是内置的,新版本已经分离了,所以可以通过以下链接进行安装。

下载地址:https://github.com/appium/appium-inspector/releases

 

安装Appium-Python-Client

Python想要操作appium,就要有专门的的连接工具模块-appium-python-client。直接安装即可。

pip install appium-python-client

OK。经过上面的步骤以后,appium的安装步骤就全部完成了。

基本使用

  1. 打开appium,点击startServer。

 

  1. 打开模拟器或真机,选择要启动的应用,通过cmd终端查找当前应用的包名(appPackage)与激活入口地址(appActivity)。

     

    例如我们在模拟器中选择并打开“设置“。

     adb devicesadb -s 127.0.0.1:62001 shell dumpsys window windows | grep mFocusedApp# adb shell dumpsys window windows | grep mFocusedApp
    

    效果:

     

  2. 通过python操作移动端打开“设置”应用。

    import time
    from appium.webdriver.webdriver import WebDriver# Appium 服务器初始化参数
    desired_capabilities = {"platformName": "Android",  # 系统类型 IOS/Android"platformVersion": "7",     # 操作系统版本"deviceName": "127.0.0.1:62001",  # 设备类型,设备ID,IOS必须填写# adb shell dumpsys window windows | grep mFocusedApp"appPackage": "com.jingdong.app.mall",  # 要打开的APP包名"appActivity": ".MainFrameActivity"             # APP激活的首屏名称
    }driver = WebDriver("http://127.0.0.1:4723/wd/hub", desired_capabilities)time.sleep(5)driver.quit()

jsonwp协议

在前面的Appium基本介绍时,我们提到过Appium Server实际上就是一个HTTP服务器,它对外暴露了一系列的restful API接口给开发者进行远程调用。

img

所以我们上面编写的python代码打开设置应用这个过程,本质上就是通过jsonwp(json wire protocol, WebDriver 开发者编写的一种通信协议)协议来实现对远程APP的操作的。

请求方法uri地址描述
POST /session 新建会话
DELETE /session/会话ID 删除会话
GET /status 获取appium服务器状态信息

更多restful API接口操作:https://w3c.github.io/webdriver/#x6-5-endpoints

postman操作

// 新建会话
// POST http://127.0.0.1:4723/wd/hub/session
{"desiredCapabilities": {"platformName": "Android","platformVersion": "7","deviceName": "127.0.0.1:62001","appPackage": "com.android.settings","appActivity": ".Settings"}
}// 删除会话【会话ID在上面的请求操作的响应字典中可以找到】
// DELETE http://127.0.0.1:4723/wd/hub/session/d9cd07ad-1170-49fd-99cc-a4fb4f4e4435

capability

初始化参数(Capability)是JSON数据类型编码的键和值,当一个新的自动化会话被请求时,Appium客户端发送此参数到服务端。此参数传递到Appium drivers用于设置各种重要事项测试工作。每种客户端语言都有特定的Appium客户端构建参数,但最终他们以JSON数据发送到Appium Server的。

初始化参数(Capability)可以编写在WebDriver测试代码中或者存放在Appium Server GUI中(Inspector会话)。

启动参数文档:https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/caps.md

中文翻译文档:https://github.com/appium/appium/blob/master/docs/cn/writing-running-appium/caps.md

通用参数
描述
automationName 自动化测试的引擎 Appium (默认)或者 Selendroid
platformName 使用的手机操作系统 iOSAndroid, 或者 FirefoxOS
platformVersion 手机操作系统的版本 例如 7.14.4
deviceName 使用的手机或模拟器设备名称 iPhone SimulatoriPad SimulatoriPhone Retina 4-inchAndroid EmulatorGalaxy S4, 等等… 在 iOS 上,使用 Instruments 的 instruments -s devices 命令可返回一个有效的设备的列表,例如:iPhone X等。在 Andorid 上虽然这个参数目前已被忽略,但仍然需要添加上该参数。
app 本地绝对路径_或_远程 http URL 所指向的一个安装包(.ipa,.apk,或 .zip 文件)。Appium 将其安装到合适的设备上。请注意,如果您指定了 appPackage 和 appActivity 参数(见下文),Android 则不需要此参数了。该参数也与 browserName 不兼容。 /abs/path/to/my.apk 或 http://myapp.com/app.ipa
browserName 做自动化时使用的浏览器名字。如果是一个应用则只需填写个空的字符串 ‘Safari’ 对应 iOS,‘Chrome’, ‘Chromium’, 或 ‘Browser’ 则对应 Android
newCommandTimeout 用于客户端在退出或者结束 session 之前,Appium 等待客户端发送一条新命令所花费的时间(秒为单位) 例如 60
language (Sim/Emu-only) 为模拟器设置语言 例如 fr
locale (Sim/Emu-only) 为模拟器设置所在区域 例如 fr_CA
udid 连接真机的唯一设备号 例如 1ae203187fc012g
orientation (Sim/Emu-only) 模拟器当前的方向 竖屏 或 横屏
autoWebview 直接转换到 Webview 上下文(context)。默认值为 false truefalse
noReset 在当前 session 下不会重置应用的状态。默认值为 false truefalse
fullReset (iOS)删除所有的模拟器文件夹。(Android) 要清除 app 里的数据,请将应用卸载才能达到重置应用的效果。在 Android, 在 session 完成之后也会将应用卸载掉。默认值为 false truefalse
Android 独有
描述
appActivity Activity 的名字是指从你的包中所要启动的 Android acticity。他通常需要再前面添加. (例如 使用 .MainActivity 代替 MainActivity MainActivity.Settings
appPackage 运行的 Android 应用的包名 com.example.android.myAppcom.android.settings
appWaitActivity 用于等待启动的 Android Activity 名称 SplashActivity
appWaitPackage 用于等待启动的 Android 应用的包 com.example.android.myAppcom.android.settings
appWaitDuration 用于等待 appWaitActivity 启动的超时时间(以毫秒为单位)(默认值为 20000) 30000
device

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/57340.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

虚拟化技术:新能源汽车空调控制系统的智能新突破

汽车生产中,空调系统已经成为标配,空调系统的性能是衡量一辆汽车是否舒适的重要指标之一。 01.汽车空调系统组成 (1) 制冷系统:制冷系统的功能是给汽车内部提供冷空气,主要由压缩机、冷凝器、膨胀阀以及蒸发器组成。首先由压缩机对空气进行压缩,使空气通过蒸发器,并由制冷…

计算机计算小数除法的陷阱

小学生都知道上面的代码中,8.1/3=2.7 但是计算机计算的结果却出人意料:2.6999999999999997 原因:计算机是用二进制格式存储小数的,这个二进制格式不能精确表示8.1,它只能表示一个非常接近8.1但又不等于8.1的一个数。

pbootcms提交留言、提交自定义表单时取消验证码

进入菜单 全局配置 -> 配置参数 -> 安全配置扫码添加技术【解决问题】专注中小企业网站建设、网站安全12年。熟悉各种CMS,精通PHP+MYSQL、HTML5、CSS3、Javascript等。承接:企业仿站、网站修改、网站改版、BUG修复、问题处理、二次开发、PSD转HTML、网站被黑、网站漏洞…

pbootcms站点信息调用

{pboot:siteindex} 站点入口地址,一般用于站内链接跳转设置地址前置,实现自适应URL模式{pboot:sitepath} 站点路径,根目录时值为空,为适应部署到二级目录时建议链接前面带上{pboot:sitelanguage} 站点语言{pboot:sitetitle} 站点标题{pboot:sitesubtitle} 站点副标题{pboot:…

house of stom

完成事项 house of stom学习 未完成事项 wmctf的blineless没打通 如何解决未完成事项 下周待做事项 house of orange house of lore 本周学习的知识分享 house of stom 条件:1.能控制unsorted的bk指针,还有largebin的fd_nextsize和bk_nextsize 码源分析 largebin attack:申…

Pbootcms留言“提交成功”的提示语修改

按照这个路径地址来修改下文件/apps/home/controller/MessageController.php 大概在103行,可以搜索提交成功快捷查询下。扫码添加技术【解决问题】专注中小企业网站建设、网站安全12年。熟悉各种CMS,精通PHP+MYSQL、HTML5、CSS3、Javascript等。承接:企业仿站、网站修改、网…

house of orange

house of orange 1.针对没有free的堆题目 orange部分 申请比topchunk的size大的chunk,会将原本的chunk放入unsortedbin中,可以借此泄露地址 FSOP io文件结构有chain连接成一个链表形式,这部分,头节点记录在_IO_list_all上,通过unsorted attack或者largebin attack劫持_io_…

docker 安装 redis 集群

集群搭建(三主三从) 集群搭建 集群中的节点都需要打开两个 TCP 连接。一个连接用于正常的给 Client 提供服务,比如 6379,还有一个额外的端口(通过在这个端口号上加10000)作为数据端口,例如:redis的端口为 6379,那么另外一个需要开通的端口是:6379 + 10000, 即需要开…