Appium客户端安装
Appium背景介绍
.1.官网:www.appium.io,由SauceLab公司开发
2.Appium是由nodejs的express框架写的Http Server,Appium使用WebDriver的json wire协议,
来驱动Apple系统的UIAutomation库、Android系统的UIAutomator框架
Appium桌面客户端安装方式
- 运行appium-desktop-Setup-1.2.7.exe,默认安装即可
- 启动客户端,按图片步骤 1 -> 2 -> 3 设置
3. 启动成功展示如下图
手机启动参数
desired_caps常用参数:
platformName 平台的名称:iOS, Android, or FirefoxOS
platformVersion 设备系统版本号
deviceName 设备号 IOS:instruments -s devices,Android: adb devices
app 安装文件路径:/abs/path/to/my.apk or http://myapp.com/app
appActivity 启动的Activity
appPackage 启动的包
unicodeKeyboard unicode设置(允许中文输入)
resetKeyboard 键盘设置(允许中文输入)
server 启动参数
desired_caps = {}
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.56.101:5555'
desired_caps['appPackage'] = 'com.android.settings'
desired_caps['appActivity'] = '.Settings'
desired_caps['unicodeKeyboard'] = True
desired_caps['resetKeyboard'] = True
启动检查器会话
设置手机启动参数
启动会话
APP元素定位操作
Appium常用元素定位方式
前置代码
from appium import webdriver
# server 启动参数
desired_caps = {}
# 设备信息
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.56.101:5555'
# app的信息
desired_caps['appPackage'] = 'com.android.settings'
desired_caps['appActivity'] = '.Settings'
# 声明我们的driver对象
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
通过id定位
方法:find_element_by_id(id_value) # id_value:为元素的id属性值
业务场景:
1.进入设置页面
2.通过ID定位方式点击搜索按钮
代码实现:
driver.find_element_by_id("com.android.settings:id/search").click()
driver.quit()
通过class定位
方法:find_element_by_class_name(class_value) # class_value:为元素的class属性值
业务场景:
1.进入设置页面
2.点击搜索按钮
3.通过class定位方式点击输入框的返回按钮
代码实现:
# id 点击搜索按钮
driver.find_element_by_id("com.android.settings:id/search").click()
# class 点击输入框返回按钮
driver.find_element_by_class_name('android.widget.ImageButton').click()
driver.quit()
通过xpath定位
方法:find_element_by_xpath(xpath_value) # xpath_value:为可以定位到元素的xpath语句
*** android端xptah常用属性定位:
1. id 😕/[contains(@resource-id,‘com.android.settings:id/search’)]
2. class 😕/[contains(@class,‘android.widget.ImageButton’)]
3. text 😕/*[contains(@text,‘WLA’)]
*** 模糊定位 contains(@key,value): value可以是部分值
业务场景:
1.进入设置页面
2.点击WLAN菜单栏
代码实现:
# xpath 点击WLAN按钮
driver.find_element_by_xpath("//*[contains(@text,'WLA')]").click()
定位一组元素,注意element -> elements
应用场景为元素值重复,无法通过元素属性直接定位到某个元素,只能通过elements方式来选择,返回一个定位对象的列表.
通过id方式定位一组元素
方法: find_elements_by_id(id_value) # id_value:为元素的id属性值
业务场景:
1.进入设置页面
2.点击WLAN菜单栏(id定位对象列表中第1个)
代码实现:
# 定位到一组元素
title = driver.find_elements_by_id("com.android.settings:id/title")
# 打印title类型,预期为list
print(type(title))
# 取title返回列表中的第一个定位对象,执行点击操作
title[0].click()
通过class方式定位一组元素
方法:find_elements_by_class_name(class_value) # class_value:为元素的class属性值
业务场景:
1.进入设置页面
2.点击WLAN菜单栏(class定位对象列表中第3个)
代码实现:
# 定位到一组元素
title = driver.find_elements_by_class_name("android.widget.TextView")
# 打印title类型,预期为list
print(type(title))
# 取title返回列表中的第一个定位对象,执行点击操作
title[3].click()
通过xpath方式定位一组元素
方法:find_elements_by_xpath(xpath_value) # xpath_value:为可以定位到元素的xpath语句
业务场景:
1.进入设置页面
2.点击WLAN菜单栏(xpath中class属性定位对象列表中第3个)
代码实现:
# 定位到一组元素
title = driver.find_elements_by_xpath("//*[contains(@class,'widget.TextView')]")
# 打印title类型,预期为list
print(type(title))
# 取title返回列表中的第一个定位对象,执行点击操作
title[3].click()
WebDriverWait 显示等待操作
在一个超时时间范围内,每隔一段时间去搜索一次元素是否存在,
如果存在返回定位对象,如果不存在直到超时时间到达,报超时异常错误。
方法:WebDriverWait(driver, timeout, poll_frequency).until(method)
参数:
1.driver:手机驱动对象
2.timeout:搜索超时时间
3.poll_frequency:每次搜索间隔时间,默认时间为0.5s
4.method:定位方法(匿名函数)
匿名函数:
lambda x: x
等价于python函数:
def test(x):
return x
使用示例:
WebDriverWait(driver, timeout, poll_frequency).until(lambda x: x.find_elements_by_id(id_value))
解释:
1.x传入值为:driver,所以才可以使用定位方法.
函数运行过程:
1.实例化WebDriverWait类,传入driver对象,之后driver对象被赋值给WebDriverWait的一个类变量:self._driver
2.until为WebDriverWait类的方法,until传入method方法(即匿名函数),之后method方法会被传入self._driver
3.搜索到元素后until返回定位对象,没有搜索到函数until返回超时异常错误.
业务场景:
1.进入设置页面
2.通过ID定位方式点击搜索按钮
代码实现:
from selenium.webdriver.support.wait import WebDriverWait # 导入WebDriverWait类
# 超时时间为30s,每隔1秒搜索一次元素是否存在,如果元素存在返回定位对象并退出
search_button = WebDriverWait(driver, 30, 1).until(lambda driver: driver.find_element_by_id("com.android.settings:id/search"))
search_button.click()
driver.quit()
点击元素
#导入appium
from appium import webdriver
caps = {}
#启动参数
caps["deviceName"] = "127.0.0.1:62001"
caps["platformName"] = "Android"
caps["appPackage"] = "com.android.settings"
caps["appActivity"] = "com.android.settings.Settings"
driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
shengyin = driver.find_element_by_xpath("//*[contains(@text,'声音')]")
shengyin.click()
发送数据到输入框
代码实现:
# 点击搜索按钮
driver.find_element_by_id("com.android.settings:id/search").click()
# 定位到输入框并输入abc
driver.find_element_by_id("android:id/search_src_text").send_keys("abc")
清空输入框内容
方法:clear()
代码实现:
# 点击搜索按钮
driver.find_element_by_id("com.android.settings:id/search").click()
# 定位到输入框并输入abc
input_text = driver.find_element_by_id("android:id/search_src_text")
# 输入abc
input_text.send_keys("abc")
time.sleep(1)
# 删除abc
input_text.clear()
获取元素的文本内容
方法:text
代码实现:
text_vlaue = driver.find_elements_by_class_name("android.widget.TextView")
for i in text_vlaue:
print(i.text)
获取元素的属性值
方法: get_attribute(value) # value:元素的属性
⚠️ value=‘name’ 返回content-desc / text属性值
⚠️ value=‘text’ 返回text的属性值
⚠️ value=‘className’ 返回 class属性值,只有 API=>18 才能支持
⚠️ value=‘resourceId’ 返回 resource-id属性值,只有 API=>18 才能支持
代码实现:
# 定位到搜索按钮
get_value = driver.find_element_by_id("com.android.settings:id/search")
print(get_value.get_attribute("content-desc"))
获取元素在屏幕上的坐标
方法:location
代码实现:
# 定位到搜索按钮
get_value = driver.find_element_by_id("com.android.settings:id/search")
# 打印搜索按钮在屏幕上的坐标
print(get_value.location)
执行结果:
{'y': 44, 'x': 408}
获取app包名和启动名
获取包名方法:current_package
获取启动名:current_activity
代码实现:
print(driver.current_package)
print(driver.current_activity)
执行结果:
com.tencent.news
.activity.SplashActivity
元素操作
前提:from appium.webdriver.common.touch_action import TouchAction
swip滑动事件
⚠️从一个坐标位置滑动到另一个坐标位置,只能是两个点之间的滑动
方法:swipe(start_x, start_y, end_x, end_y, duration=None)
参数:
1.start_x:起点X轴坐标
2.start_y:起点Y轴坐标
3.end_x: 终点X轴坐标
4.end_y,: 终点Y轴坐标
5.duration: 滑动这个操作一共持续的时间长度,单位:ms
#代码实现
driver.swipe(175,1520,175,430,duration=3000)
scroll滑动事件
⚠️ 从一个元素滑动到另一个元素,直到页面自动停止
方法:scroll(origin_el, destination_el)
参数:
1.origin_el:滑动开始的元素
2.destination_el:滑动结束的元素
3.duration: 滑动这个操作一共持续的时间长度,单位:ms
#获取元素
jianyi = driver.find_element_by_xpath("//*[contains(@text,'建议')]")
shengyin = driver.find_element_by_xpath("//*[contains(@text,'声音')]")
#执行滑动操作
driver.scroll(shengyin,jianyi,duration=3000)
drag拖拽事件
⚠️ 从一个元素滑动到另一个元素,第二个元素替代第一个元素原本屏幕上的位置
方法:drag_and_drop(origin_el, destination_el)
参数:
1.origin_el:滑动开始的元素
2.destination_el:滑动结束的元素
代码实现:
# 定位到存储菜单栏
cunchu = driver.find_element_by_xpath("//*[contains(@text,'存储')]")
# 定位到WLAN菜单栏
wlan = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]")
# 执行滑动操作
driver.drag_and_drop(cunchu,wlan)
应用置于后台事件
APP放置后台,模拟热启动
方法:background_app(seconds)
参数:
1.seconds:停留在后台的时间,单位:秒
代码实现:
driver.background_app(5)
效果:
app置于后台5s后,再次展示当前页面
手指轻敲操作
模拟手指轻敲一下屏幕操作
方法:tap(element=None, x=None, y=None)
方法:perform() # 发送命令到服务器执行操作
参数:
1.element:被定位到的元素
2.x:相对于元素左上角的坐标,通常会使用元素的X轴坐标
3.y:通常会使用元素的Y轴坐标
代码实现:
# 通过元素定位方式敲击屏幕
el = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]")
TouchAction(driver).tap(el).perform()
# 通过坐标方式敲击屏幕,WLAN坐标:x=155,y=250
# TouchAction(driver).tap(x=155,y=250).perform()
手指按操作
模拟手指按下屏幕,按就要对应着离开.
方法:press(el=None, x=None, y=None)
方法:release() # 结束动作,手指离开屏幕
参数:
1.element:被定位到的元素
2.x:通常会使用元素的X轴坐标
3.y:通常会使用元素的Y轴坐标
代码实现:
# 通过元素定位方式按下屏幕
el = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]")
TouchAction(driver).press(el).release().perform()
# 通过坐标方式按下屏幕,WLAN坐标:x=155,y=250
# TouchAction(driver).press(x=155,y=250).release().perform()
等待操作
方法:wait(ms=0)
参数:
ms:暂停的毫秒数
代码实现:
# 点击WLAN
driver.find_element_by_xpath("//*[contains(@text,'WLAN')]").click()
# 定位到WiredSSID
el =driver.find_element_by_id("android:id/title")
# 通过元素定位方式长按元素
TouchAction(driver).press(el).wait(5000).perform()
# 通过坐标方式模拟长按元素
# 添加等待(有长按)/不添加等待(无长按效果)
# TouchAction(driver).press(x=770,y=667).wait(5000).release().perform()
手指长按操作
模拟手机按下屏幕一段时间,按就要对应着离开.
方法:long_press(el=None, x=None, y=None, duration=1000)
参数:
1.element:被定位到的元素
2.x:通常会使用元素的X轴坐标
3.y:通常会使用元素的Y轴坐标
4.duration:持续时间,默认为1000ms
代码实现:
# 点击WLAN
driver.find_element_by_xpath("//*[contains(@text,'WLAN')]").click()
# 定位到WiredSSID
el =driver.find_element_by_id("android:id/title")
# 通过元素定位方式长按元素
TouchAction(driver).long_press(el,duration=5000).release().perform()
# 通过坐标方式长按元素,WiredSSID坐标:x=770,y=667
# 添加等待(有长按)/不添加等待(无长按效果)
# TouchAction(driver).long_press(x=770,y=667).perform()
手指移动操作
模拟手机的滑动操作
方法:move_to(el=None, x=None, y=None)
参数:
1.el:定位的元素
2.x:相对于前一个元素的X轴偏移量
3.y:相对于前一个元素的Y轴偏移量
代码实现:
# 定位到存储
el = driver.find_element_by_xpath("//*[contains(@text,'存储')]")
# 定位到更多
el1 = driver.find_element_by_xpath("//*[contains(@text,'更多')]")
# 元素方式滑动
TouchAction(driver).press(el).move_to(el1).release().perform()
# 坐标的方式滑动
# TouchAction(driver).press(x=240,y=600).wait(100).move_to(x=240,y=100).release().perform()
# 注意press连接一个move_to实际调用的是swip方法,可在log中查询,不要给相对坐标。
模拟图案解锁手机
from appium import webdriver
from appium.webdriver.common.touch_action import TouchAction
import time
caps = {}
caps["deviceName"] = "127.0.0.1:62001"
caps["platformName"] = "Android"
caps["appPackage"] = "com.android.settings"
caps["appActivity"] = "com.android.settings.Settings"
driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
# 隐式等待
driver.implicitly_wait(10)
# 获取元素
jianyi = driver.find_element_by_xpath("//*[contains(@text,'建议')]")
shengyin = driver.find_element_by_xpath("//*[contains(@text,'声音')]")
driver.scroll(shengyin,jianyi,duration=3000)
# 点击事件
anquan = driver.find_element_by_xpath("//*[contains(@text,'安全')]")
anquan.click()
pmsd = driver.find_element_by_xpath("//*[contains(@text,'屏幕锁定')]")
pmsd.click()
tuan = driver.find_element_by_xpath("//*[contains(@text,'图案')]")
tuan.click()
time.sleep(5)
# 绘制图案四个坐标
TouchAction(driver).press(x=182,y=774).wait(100).move_to(x=445,y=774).wait(100).move_to(x=445,y=1047).wait(100).move_to(x=182,y=1320).release().perform()
time.sleep(5)
driver.quit()