基本元素操作
click(self):
点击元素
# 点击元素
driver.find_element('xpath','//*[@text='我的柠檬']').click()
send_keys(self,*value):
在元素中输入文本内容
# 在元素中输入文本信息
element = driver.find_element('id','com.lemon.lemonban:id/et_mobile')
element.send_keys('18843387465')
clear(self):
在元素中清除文本内容
# 在元素中清除文本内容
element = driver.find_element('id','com.lemon.lemonban:id/et_mobile')
element.send_keys('18843387465')
element.clear()
submit(self):
提交表单操作,在H5和webview中可使用
获取元素属性操作
- text:获取元素属性中的text值
- tag_name:获取元素的标签名(原生应用无标签名,所以为None)
- get_attribute(self,*name):根据属性名获取元素属性,属性名填写错误会报错
- size:获取元素的宽和高,返回字典
- location:获取元素左上角的坐标,返回字典
- rect:元素的大小和位置组合字典,返回字典
- context:返回当前会话的当前上下文,使用后可以识别H5页面的控件
- contexts:返回当前会话的上下文
备注:还有部分方法如screenshot(self,*filename)等用在H5和webview端,由于appium中api没有区分原生和H5,所以当在代码中报错Methodhasnotyetbeenimplemented时,可以确认该方法在另外一端使用
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/8/14 16:54
# @Author : shisuiyi
# @File : app_kaoyan.py
# @Software: win10 Tensorflow1.13.1 python3.7
from appium import webdriver
import time
# 1.设置终端参数
desired_caps = {
"platformName": "Android",
"platformVersion": "7.1.2",
"deviceName": "模拟器",
"appPackage": "com.lemon.lemonban",
"appActivity": "com.lemon.lemonban.activity.MainActivity",
"noReset": "True",
'skipServerInstallation': "True",
'automationName': 'UiAutomator2'
}
# 2.appium server 进行启动
# 3. 发送指令到appium server
driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)
time.sleep(3)
element = driver.find_element('xpath', "//*[@text='我的柠檬']")
# 获取元素属性中的text值
print(element.text)
# 获取元素的标签名
print(element.tag_name)
# 根据属性名获取元素属性
print(element.get_attribute('checkable'))
# 获取元素的宽和高,返回字典
print(element.size)
# 获取元素左上角的坐标,返回字典
print(element.location)
# 元素的大小和位置组合字典,返回字典
print(element.rect)
# H5 环境
# 返回当前会话的当前上下文,使用后可以识别H5页面的控件
# print(driver.context)
# 返回当前会话中的上下文,使用后可以识别H5页面的控件
# print(driver.contexts)
输出:
我的柠檬
None
false
{'height': 30, 'width': 88}
{'x': 832, 'y': 1887}
{'x': 832, 'y': 1887, 'width': 88, 'height': 30}
Process finished with exit code 0
元素判断的操作
- is_displayed(self):此元素是否可见。隐藏元素和被控件挡住无法操作的元素(仅限H5和webview支持)返回布尔值;
# 该元素是否可见
is_d = driver.find_element('xpath', "//*[@text='我的柠檬']").is_displayed()
print(is_d)
- is_enabled(self):此元素是否可用。元素灰色和无法操作的元素(仅限H5和webview支持)返回布尔值;
# 该元素是否可用
is_e = driver.find_element('xpath','xxxx').is_enabled()
print(is_e)
- is_selected(self):此元素是否被选中。适用于单选框、复选框等类型的元素(仅限H5和webview支持)返回布尔值;
# 此元素是否被选中
is_s = driver.find_element('xpath','xxxx"]').is_selected()
print(is_s)
- 对于原生应用来讲,元素断言可以通过获取displayed、enabled、selected属性值,然后通过条件语句if来进行判断;
TouchAction 类型的操作
按压控件press()
开始按压一个元素或坐标点(x,y)。通过手指按压手机屏幕的某个位置。
from appium.webdriver.common.touch_action import TouchAction # 需要导入 TouchAction
'''
release():结束的行动取消屏幕上的指针。
Perform():执行的操作发送到服务器的命令操作。
'''
TouchAction(driver).press(x=0,y=308).release().perform() # press 也可以接收屏幕的坐标(x,y)
长按控件· long_press()
开始按压一个元素或坐标点(x,y)。 相比press()方法,long_press()多了一个入参,既然长按,得有按的时间吧。duration 以毫秒为单位。1000 表示按一秒钟。其用法与 press() 方法相同。
from appium.webdriver.common.touch_action import TouchAction # 需要导入 TouchAction
TouchAction(driver).long_press(x=100, y=200, duration=3000).perform() #duration单位是ms
点击控件· tap()
对一个元素或控件执行点击操作。用法参考 press()。
from appium.webdriver.common.touch_action import TouchAction # 需要导入 TouchAction
TouchAction(driver).tap(1 ,302).perform();
移动· move_to()
move_to(el=None, x=None, y=None)这里的x,y为前一个坐标的偏移量
参数:
- el:定位的元素
- x:相对于前一个元素的x轴偏移量
- 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=1000).move_to(x=0,y=-400).release().perform()
# press().move_to() 实际使用的是TouchAction方法,需要给相对坐标.
绘制图案四个坐标
# 绘制图案四个坐标 1:(244,967) 2:(723,967) 3:(723,1442) 4:(244,1916)
TouchAction(driver).press(x=244,y=967).wait(100).move_to(x=479,y=0).wait(100)\
.move_to(x=0,y=475).wait(100).move_to(x=-479,y=474).release().perform()
暂停· wait()
暂停脚本的执行,单位为毫秒。
from appium.webdriver.common.touch_action import TouchAction # 需要导入 TouchAction
TouchAction(driver).wait(1000)
松开· release()
松开press
执行 · perform
每个动作需要这个函数才能执行
滑屏操作 swipe
从一个点滑到另外一个点,那么每个点都有 x 值和 y 值。swipe
有 4 个参数。所以起始 x,起始 y,结束 x,结束 y。
def swipe(self: T, start_x: int, start_y: int, end_x: int, end_y: int, duration: int = 0) -> T:
- 先获取设备的屏幕的大小get_window_size()这个函数的返回值
- 再设置滑动的距离和屏幕大小的百分比
- 调动滑动接口来执行滑动操作
window_size = driver.get_window_size()
print("手机屏幕的尺寸:", window_size)
x = window_size["width"]
y = window_size["height"]
driver.swipe(x*0.9, y*0.5, x*0.1, y*0.5, 2000)
滑动的封装
class BasePage:
def __init__(self, driver):
self.driver = driver
def width(self):
"""获取当前屏幕的宽度"""
size = self.driver.get_window_size()
return size['width']
def height(self):
"""获取当前屏幕的高"""
size = self.driver.get_window_size()
return size['height']
def swipe_left(self):
"""从右到左滑动"""
# 算出手机的分辨率, 控制滑动的比例是根据手机的分辨率
width = self.width()
height = self.height()
self.driver.swipe(width * 0.95, height * 0.5, end_x=width * 0.05, end_y=height * 0.5)
def swipe_right(self):
"""从左到右滑动"""
# 算出手机的分辨率, 控制滑动的比例是根据手机的分辨率
width = self.width()
height = self.height()
self.driver.swipe(width * 0.05, height * 0.5, end_x=width * 0.95, end_y=height * 0.5)
def swipe_down(self):
"""从上到下"""
# 算出手机的分辨率, 控制滑动的比例是根据手机的分辨率
width = self.width()
height = self.height()
self.driver.swipe(width * 0.5, height * 0.05, end_x=width * 0.5, end_y=height * 0.95)
def swipe_up(self):
"""从下到上"""
# 算出手机的分辨率, 控制滑动的比例是根据手机的分辨率
width = self.width()
height = self.height()
self.driver.swipe(width * 0.5, height * 0.95, end_x=width * 0.5, end_y=height * 0.05)
# 表示告诉appium 服务连接哪个手机, 手机系统信息, 你要测哪个 app
caps = {
"platformName": "Android",
"udid": "emulator-5554",
"app": file,
# "appPackage": "com.lemon.lemonban", # 包名, 每个app在手机上面的标志。 id
# "appActivity": ".activity.WelcomeActivity",
# "platformVersion": '4',
# "noRest": True, # 不重启app的状态
}
driver = Remote(desired_capabilities=caps,
command_executor = 'http://127.0.0.1:4723/wd/hub')
time.sleep(10)
# 滑动
# swipe_left(driver)
page = BasePage(driver)
page.swipe_left()
page.swipe_left()
page.swipe_left()
time.sleep(3)
# # 点击操作,点击,
driver.quit()
放大缩小操作
在 appium2.0 之前,在移动端设备上的触屏操作,单手指触屏和多手指触屏分别是由 TouchAction 类,Multiaction 类实现的。
在 appium2.0 之后,这 2 个方法将会被舍弃。
在 w3c 的 actions 当中,将输入源分为了三类:
- 键盘类 - Key
- 指针类 - Pointer
- None
from selenium.webdriver import ActionChains
from selenium.webdriver.common.actions.mouse_button import MouseButton
def zoom(driver: Remote):
actions = ActionChains(driver)
actions.w3c_actions.devices = [] # 输入源设备列表为空
finger1 = actions.w3c_actions.add_pointer_input('touch', 'finger1') # 添加一个新的指针输入源
finger2 = actions.w3c_actions.add_pointer_input('touch', 'finger2')
width = driver.get_window_size()['width']
height = driver.get_window_size()['height']
# 两个手指移动到屏幕正中间
# PointerMove:移动到屏幕某个点
finger1.create_pointer_move(x=width*0.5, y=height*0.5)
finger2.create_pointer_move(x=width * 0.5, y=height * 0.5)
# 两个手指按下去
# PointerDown:按下鼠标键,或者触屏或者触屏笔触屏
finger1.create_pointer_down(MouseButton.LEFT)
finger2.create_pointer_down(MouseButton.LEFT)
# 两个手指移动
finger1.create_pointer_move(x=width*0.5, y=height * 0.9)
finger2.create_pointer_move(x=width * 0.5, y=height *0.1)
# 两个手指松开
# PointerUp:松开鼠标键,或者手离开屏幕,或者触屏笔离开屏幕
finger1.create_pointer_up(MouseButton.LEFT)
finger2.create_pointer_up(MouseButton.LEFT)
actions.perform()
def suoxiao(driver: Remote):
"""缩小"""
actions = ActionChains(driver)
actions.w3c_actions.devices = []
finger1 = actions.w3c_actions.add_pointer_input('touch', 'finger1')
finger2 = actions.w3c_actions.add_pointer_input('touch', 'finger2')
width = driver.get_window_size()['width']
height = driver.get_window_size()['height']
# 两个手指移动到屏幕正中间
finger1.create_pointer_move(x=width*0.5, y=height*0.9)
finger2.create_pointer_move(x=width * 0.5, y=height * 0.1)
# 两个手指按下去
finger1.create_pointer_down(MouseButton.LEFT)
finger2.create_pointer_down(MouseButton.LEFT)
# 两个手指移动
finger1.create_pointer_move(x=width*0.5, y=height * 0.5)
finger2.create_pointer_move(x=width * 0.5, y=height *0.5)
# 两个手指松开
finger1.create_pointer_up(MouseButton.LEFT)
finger2.create_pointer_up(MouseButton.LEFT)
actions.perform()
Keyboard 相关
Keyboard 类在 appium\webdriver\extensions 下的 keyboard.py 模块中, 属于键盘操作类
driver.press_keycode()
driver.long_press_keycode()
driver.hide_keyboard()
driver.keyevent()
driver.is_keyboard_shown()
driver.press_keycode()
源码:
def press_keycode(self: T, keycode: int, metastate: Optional[int] = None, flags: Optional[int] = None) -> T:
"""Sends a keycode to the device.
Android only. Possible keycodes can be found
in http://developer.android.com/reference/android/view/KeyEvent.html.
Args:
keycode: the keycode to be sent to the device
metastate: meta information about the keycode being sent
flags: the set of key event flags
Returns:
Union['WebDriver', 'Keyboard']: Self instance
"""
data = {
'keycode': keycode,
}
if metastate is not None:
data['metastate'] = metastate
if flags is not None:
data['flags'] = flags
self.execute(Command.PRESS_KEYCODE, data)
return self
作用
发送按键code,模拟手机按键【Android专属】
参数讲解
- keycode:按键代码
- metastate:键码的元信息
- flags:按键事件的合集
用法
如输入大写字母A:按下caps_lock大小写锁定键输入字符 press_keycode(29,115) 输入大写A
driver.press_keycode(29,115)
按下返回键:
driver.press_keycode(4)
driver.long_press_keycode()
源码:
def long_press_keycode(self: T, keycode: int, metastate: Optional[int] = None, flags: Optional[int] = None) -> T:
"""Sends a long press of keycode to the device.
Android only. Possible keycodes can be found in
http://developer.android.com/reference/android/view/KeyEvent.html.
Args:
keycode: the keycode to be sent to the device
metastate: meta information about the keycode being sent
flags: the set of key event flags
Returns:
Union['WebDriver', 'Keyboard']: Self instance
"""
data = {'keycode': keycode}
if metastate is not None:
data['metastate'] = metastate
if flags is not None:
data['flags'] = flags
self.execute(Command.LONG_PRESS_KEYCODE, data)
return self
作用
按键code长按发送给设备,模拟手机按键【Android专属】
参数讲解
- keycode:按键代码
- metastate:键码的元信息
- flags:目标按键事件
用法
driver.long_press_keycode(4)
driver.hide_keyboard()
源码:
def hide_keyboard(
self: T, key_name: Optional[str] = None, key: Optional[str] = None, strategy: Optional[str] = None
) -> T:
"""Hides the software keyboard on the device.
In iOS, use `key_name` to press
a particular key, or `strategy`. In Android, no parameters are used.
Args:
key_name: key to press
key:
strategy: strategy for closing the keyboard (e.g., `tapOutside`)
Returns:
Union['WebDriver', 'Keyboard']: Self instance
"""
data: Dict[str, Optional[str]] = {}
if key_name is not None:
data['keyName'] = key_name
elif key is not None:
data['key'] = key
elif strategy is None:
strategy = 'tapOutside'
data['strategy'] = strategy
self.execute(Command.HIDE_KEYBOARD, data)
return self
作用
隐藏设备上的键盘
参数讲解(参数仅适用iOS)
- key_name:iOS 才需要此参数
- key:未知
- strategy:隐藏键盘的模式
用法
driver.hide_keyboard()
driver.keyevent()
源码:
def keyevent(self: T, keycode: int, metastate: Optional[int] = None) -> T:
"""Sends a keycode to the device.
Android only.
Possible keycodes can be found in http://developer.android.com/reference/android/view/KeyEvent.html.
Args:
keycode: the keycode to be sent to the device
metastate: meta information about the keycode being sent
Returns:
Union['WebDriver', 'Keyboard']: Self instance
"""
data = {
'keycode': keycode,
}
if metastate is not None:
data['metastate'] = metastate
self.execute(Command.KEY_EVENT, data)
return self
作用
发送按键code,模拟手机按键【Android专属】
参数讲解
- keycode:按键代码
- metastate:键码的元信息
注意
现在这方法其实已经过时了,使用press_keycode取代它,否则可能会错误
用法
driver.keyevent(4)
driver.is_keyboard_shown()
源码:
def is_keyboard_shown(self: T) -> bool:
"""Attempts to detect whether a software keyboard is present
Returns:
`True` if keyboard is shown
"""
return self.execute(Command.IS_KEYBOARD_SHOWN)['value']
作用
检查当前键盘是否已出现
返回
如果键盘已出现,则返回True
用法
print(driver.is_keyboard_shown())
EventCode | KeyEvent | EventName |
---|---|---|
0 | KEYCODE_UNKNOWN | 未知键 |
1 | KEYCODE_SOFT_LEFT | 左键 |
2 | KEYCODE_SOFT_RIGHT | 右键 |
3 | KEYCODE_HOME | Home键 |
4 | KEYCODE_BACK | 返回键 |
5 | KEYCODE_CALL | 拨号键 |
6 | KEYCODE_ENDCALL | 挂机键 |
7 | KEYCODE_0 | 按键“0” |
8 | KEYCODE_1 | 按键“1” |
9 | KEYCODE_2 | 按键“2” |
10 | KEYCODE_3 | 按键“3” |
11 | KEYCODE_4 | 按键“4” |
12 | KEYCODE_5 | 按键“5” |
13 | KEYCODE_6 | 按键“6” |
14 | KEYCODE_7 | 按键“7” |
15 | KEYCODE_8 | 按键“8” |
16 | KEYCODE_9 | 按键“9” |
17 | KEYCODE_STAR | 按键“*” |
18 | KEYCODE_POUND | 按键“#” |
19 | KEYCODE_DPAD_UP | 导航键 向上 |
20 | KEYCODE_DPAD_DOWN | 导航键 向下 |
21 | KEYCODE_DPAD_LEFT | 导航键 向左 |
22 | KEYCODE_DPAD_RIGHT | 导航键 向右 |
23 | KEYCODE_DPAD_CENTER | 导航键 确定 |
24 | KEYCODE_VOLUME_UP | 音量键加 |
25 | KEYCODE_VOLUME_DOWN | 音量键减 |
26 | KEYCODE_POWER | 电源键 |
27 | KEYCODE_CAMERA | 相机键 |
28 | KEYCODE_CLEAR | 清除键 |
29 | KEYCODE_A | 按键“A” |
30 | KEYCODE_B | 按键“B” |
31 | KEYCODE_C | 按键“C” |
32 | KEYCODE_D | 按键“D” |
33 | KEYCODE_E | 按键“E” |
34 | KEYCODE_F | 按键“F” |
35 | KEYCODE_G | 按键“G” |
36 | KEYCODE_H | 按键“H” |
37 | KEYCODE_I | 按键“I” |
38 | KEYCODE_J | 按键“J” |
39 | KEYCODE_K | 按键“K” |
40 | KEYCODE_L | 按键“L” |
41 | KEYCODE_M | 按键“M” |
42 | KEYCODE_N | 按键“N” |
43 | KEYCODE_O | 按键“O” |
44 | KEYCODE_P | 按键“P” |
45 | KEYCODE_Q | 按键“Q” |
46 | KEYCODE_R | 按键“R” |
47 | KEYCODE_S | 按键“S” |
48 | KEYCODE_T | 按键“T” |
49 | KEYCODE_U | 按键“U” |
50 | KEYCODE_V | 按键“V” |
51 | KEYCODE_W | 按键“W” |
52 | KEYCODE_X | 按键“X” |
53 | KEYCODE_Y | 按键“Y” |
54 | KEYCODE_Z | 按键“Z” |
55 | KEYCODE_COMMA | 按键“,” |
56 | KEYCODE_PERIOD | 按键‘.’ |
57 | KEYCODE_ALT_LEFT | 组合键 Alt+Left |
58 | KEYCODE_ALT_RIGHT | 组合键 Alt+Right |
59 | KEYCODE_SHIFT_LEFT | 组合键 Shift+Left |
60 | KEYCODE_SHIFT_RIGHT | 组合键 Shift+Left |
61 | KEYCODE_TAB | Tab键 |
62 | KEYCODE_SPACE | 空格键 |
63 | KEYCODE_SYM | 选择输入法 |
64 | KEYCODE_EXPLORER | 浏览器 |
65 | KEYCODE_ENVELOPE | 邮件 |
66 | KEYCODE_ENTER | 回车键 |
67 | KEYCODE_DEL | 退格键 |
68 | KEYCODE_GRAVE | 按键‘`’ |
69 | KEYCODE_MINUS | 按键‘-’ |
70 | KEYCODE_EQUALS | 按键‘=’ |
71 | KEYCODE_LEFT_BRACKET | 按键‘[’ |
72 | KEYCODE_RIGHT_BRACKET | 按键‘]’ |
73 | KEYCODE_BACKSLASH | 按键‘\’ |
74 | KEYCODE_SEMICOLON | 按键‘,’ |
75 | KEYCODE_APOSTROPHE | 按键‘'’(单引号) |
76 | KEYCODE_SLASH | 按键‘/’ |
77 | KEYCODE_AT | 按键‘@’ |
78 | KEYCODE_NUM | |
79 | KEYCODE_HEADSETHOOK | |
80 | KEYCODE_FOCUS | |
81 | KEYCODE_PLUS | 按键‘+’ |
82 | KEYCODE_MENU | 菜单键 |
83 | KEYCODE_NOTIFICATION | |
84 | KEYCODE_SEARCH | |
85 | TAG_LAST_KEYCODE |
toast处理
- appium server 1.6.3 以上
- 代码中必须制定 automationName为:UiAutomator2, 1.14之后的 appium 可以不加
- UIAutomator2只支持安卓版本 5.0+
- jdk1.8 64位以上。配置 JAVA_HOME 环境变量;
- toast只有文本,只支持xpath定位, //*[contains(@text,“错误的账号信息”) 不能够用等待元素可见,只能用元素存在否则会报错
# Toast 弹框
# 方法一:直接通过文本属性定位
# driver.find_element('xpath', "//*[@text='错误的账号信息')]")
toast = driver.find_element('xpath', "//*[contains(@text,'错误的账号信息')]")
# 方法二://android.widget.Toast
# toast = driver.find_element('xpath', "//android.widget.Toast")
print(toast.text)
应用切换 driver.start_activity(包名,应用名)
# 传包名和应用名
driver.start_activity('com.tal.kaoyan', '.ui.activity.SplashActivity')
评论