当前位置: 首页 > news >正文

APP自动化测试-Appium常见操作之详讲

一、基本操作

1、点击操作

示例:element.click() 针对元素进行点击操作

2、初始化:输入中文的处理

说明:如果连接的是虚拟机(真机无需加这两个参数,加上可能会影响手工输入),在初始化配置中增加两个参数:

  • "resetKeyboard": True, # 重置设备的输入键盘
  • "unicodeKeyboard": True # 采用unicode编码输入
"resetKeyboard": True,        # 重置设备的输入键盘
"unicodeKeyboard": True        # 采用unicode编码输入

3、清空和输入操作

  • element.clear()   针对元素进行清空操作
  • element.send_keys("value")    针对元素进行输入操作

输入的封装

def input_text(element, text):# 清除元素中的文本内容(为了保证代码的健壮性,在输入内容之前需要做一次清除操作。)element.clear()# 输入文本内容element.send_keys(text)

4、获取元素的信息

  • 获取元素的文本内容(获取的是元素text属性的内容)
    element.text
  • 获取元素的位置
    element.location  返回的值是一个字典,字典中包含x和y , x和y表示的是元素在手机屏幕左上角的点的坐标
  • 获取取元素的大小
    element.size     返回值是一个字典,字典中会包含 width和height, width表示的宽度,height表示的高度
  • 获取元素的属性值
    element.get_attribute("attribute")  # attribute表示的是属性名称
    获取ID值时,  attribute=  “resourceId”
    获取的是class的值 ,   attribute="className"
    如果attribute = "name"时,获取的是text或者content-desc(text优先,找不到text值,再去找content-desc的值)

代码示例:

import time
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from appium.options.android import UiAutomator2Options
from selenium.webdriver.support import expected_conditions as EC# 定义一个初始化APP的方法
def start_app(app_package, app_activity):# 定义desired_caps 字典,初始化app的配置信息desired_caps = {"platformName": "android",  # 表示的是android"platformVersion": "10",  # 表示的是设备系统的版本号"deviceName": "DWV6R19A10002101",  # 表示的是设备的ID名称"appPackage": app_package,  # 表示的是app的包名"appActivity": app_activity,  # 表示的是app的界面名"newCommandTimeout": 100000,"noReset": True,  # 用来记住app的session,如果有登陆或做过初始化的操作,为True时,后面不需要再操作"resetKeyboard": True,  # 重置设备的输入键盘"unicodeKeyboard": True  # 采用unicode编码输入}# 创建 Appium 驱动实例options = UiAutomator2Options().load_capabilities(desired_caps)driver = webdriver.Remote("http://localhost:4723/wd/hub", options=options)# 启动应用程序driver.wait_activity(desired_caps, 5)return driver# 定义一个获取元素的方法
def get_element_new(driver, element):element = WebDriverWait(driver, 10).until(EC.visibility_of_element_located(element))return element# 定义一个输入的封装方法
def input_text(element, text):# 清除元素中的文本内容(为了保证代码的健壮性,在输入内容之前需要做一次清除操作。)element.clear()# 输入文本内容element.send_keys(text)if __name__ == "__main__":# 本次启动的应用程序包名和活动名(作业帮)app_package_zyb = "com.baidu.homework"app_activity_zyb = ".activity.index.IndexActivity"# 启动应用程序driver_zyb = start_app(app_package_zyb, app_activity_zyb)# 定位到首页顶部搜索框并点击element = (By.ID, 'com.baidu.homework:id/tv_homepage_search_item')search_element = get_element_new(driver_zyb, element)search_element.click()# 定位到输入框并输入"英语学习"element = (By.ID, 'com.baidu.homework:id/index_search_et_search_text')input_element = get_element_new(driver_zyb, element)input_text(input_element, '英语学习')# 获取元素的文本内容(获取的是元素text属性的内容)print(f"输入框元素的文本信息是: {input_element.text}")# 获取元素的位置(返回的值是一个字典,字典中包含x和y , x和y表示的是元素在手机屏幕左上角的点的坐标)print(f"输入框的元素的位置坐标是: {input_element.location}")# 获取取元素的大小print(f"输入框元素的文本信息是: {input_element.size}")'''获取元素的属性值element.get_attribute("attribute")  # attribute表示的是属性名称获取ID值时,  attribute =  “resourceId”获取的是class的值, attribute = "className"如果attribute = "name"时,获取的是text或者content - desc(text优先,找不到text值,再去找content - desc的值)'''print(f"输入框元素的ID属性信息是: {input_element.get_attribute('resourceId')}")print(f"输入框元素的class属性信息是: {input_element.get_attribute('className')}")print(f"输入框元素的name属性信息是: {input_element.get_attribute('name')}")# 关闭驱动time.sleep(3)print("代码执行完毕")driver_zyb.quit()

二、获取手机操作

1、获取手机分辨率

目的:保证脚本在不同机型上都能实现滑屏的操作。

示例:driver.get_window_size()    

说明: 返回的值是字典类型, 包含 height 和 width  高度和宽度的值

2、获取手机截图

示例:driver.get_screenshot_as_file(filename)

说明:filename:1、路径必须手动创建  2、文件名称必须是以PNG结尾

3、设置/获取手机网络

目的:主要是为了实现视频类的app中,视频播放过程中网络切换时会有提示信息的操作。

示例:

  • driver.set_network_connection(connectionType)   #  connectionType   网络类型的值
  • driver.network_connection 获取手机网络

说明:在 Appium 中,网络类型通过driver.set_network_connection(connection type)方法进行设置。其中,connection type参数表示需要被设置的网络类型,常用的网络类型有以下几种:

  • 飞行模式:1
  • WiFi 流量:2
  • 数据流量:4
  • 数据和 WiFi 全部打开:6

4、模拟键盘操作

示例:driver.press_keycode(键值)

说明:常用的三个键值: 3 HOME键, 4 返回键 ,  66 回车键

5、手机通知栏操作

示例:driver.open_notifications()

import time
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from appium.options.android import UiAutomator2Options
from selenium.webdriver.support import expected_conditions as EC# 定义一个初始化APP的方法
def start_app(app_package, app_activity):# 定义desired_caps 字典,初始化app的配置信息desired_caps = {"platformName": "android",  # 表示的是android"platformVersion": "10",  # 表示的是设备系统的版本号"deviceName": "DWV6R19A10002101",  # 表示的是设备的ID名称"appPackage": app_package,  # 表示的是app的包名"appActivity": app_activity,  # 表示的是app的界面名"newCommandTimeout": 100000,"noReset": True,  # 用来记住app的session,如果有登陆或做过初始化的操作,为True时,后面不需要再操作"resetKeyboard": True,  # 重置设备的输入键盘"unicodeKeyboard": True  # 采用unicode编码输入}# 创建 Appium 驱动实例options = UiAutomator2Options().load_capabilities(desired_caps)driver = webdriver.Remote("http://localhost:4723/wd/hub", options=options)# 启动应用程序driver.wait_activity(desired_caps, 5)return driver# 定义一个获取元素的方法
def get_element_new(driver, element):element = WebDriverWait(driver, 10).until(EC.visibility_of_element_located(element))return element# 定义一个输入的封装方法
def input_text(element, text):# 清除元素中的文本内容(为了保证代码的健壮性,在输入内容之前需要做一次清除操作。)element.clear()# 输入文本内容element.send_keys(text)if __name__ == "__main__":# 本次启动的应用程序包名和活动名(作业帮)app_package_zyb = "com.baidu.homework"app_activity_zyb = ".activity.index.IndexActivity"# 启动应用程序driver_zyb = start_app(app_package_zyb, app_activity_zyb)# 获取手机分辨率print(driver_zyb.get_window_size())# 获取手机截图""" 1、路径必须手动创建2、文件名称必须是以PNG结尾"""current_time_file = "/error"+str(time.time())  # 通过文件名拼接当前时间戳的方式构造唯一文件名filename = "/Users/work_related/image" + current_time_file + ".png" # 需要设置正确的路径driver_zyb.get_screenshot_as_file(filename)# 设置手机网络为Wi-Fi,然后获取当前手机的网络类型"""飞行模式:1WiFi 流量:2数据流量:4数据和 WiFi 全部打开:6"""driver_zyb.set_network_connection(2)   # 设置手机网络为Wi-Fiprint(f"当前手机的网络类型是:{driver_zyb.network_connection}")  # 获取当前手机的网络类型# 模拟键盘操作'''常用的三个键值: 3 HOME键, 4 返回键 ,  66 回车键'''# 定位到首页顶部搜索框并点击element = (By.ID, 'com.baidu.homework:id/tv_homepage_search_item')search_element = get_element_new(driver_zyb, element)search_element.click()# 定位到输入框并输入"英语学习"element = (By.ID, 'com.baidu.homework:id/index_search_et_search_text')input_element = get_element_new(driver_zyb, element)input_text(input_element, '英语学习')# 返回到上一页driver_zyb.press_keycode(4)time.sleep(3)# home键返回driver_zyb.press_keycode(3)time.sleep(3)# 打开手机通知栏driver_zyb.open_notifications()# 关闭驱动time.sleep(3)print("代码执行完毕")driver_zyb.quit()

三、滑动和拖拽事件

1、swipe滑动事件

示例:driver.swipe(startx, starty,  endx, endy, duration=None)

说明:duration用来降低滑屏的速度及惯性, 单位是ms

2、swipe滑动事件封装

# 定义一个封装滑屏操作的方法
def slide_screen(driver, direction, count=1):w = driver.get_window_size()["width"]  # 获取手机屏幕的宽度h = driver.get_window_size()["height"] # 获取手机屏幕的高度# w=1080  h=1920if direction == "up":  # 往上滑zb = (w/2, h*0.9, w/2, h*0.1)elif direction == "down":  # 往下滑zb = (w/2, h*0.1, w/2, h*0.9)elif direction == 'left':  # 往左滑zb = (w*0.9, h/2, w*0.1, h/2)elif direction == 'right':   # 往右滑zb = (w*0.1, h/2, w*0.9, h/2)else:print("无法识别滑动方向,请重新输入!")for i in range(count):driver.swipe(*zb, duration=1200)time.sleep(1)

3、swipe边滑动边查找封装

目的:针对频道类的元素进行滑动选择对应的频道。

# 封装一个边滑动边查找的方法
def search_while_sliding(driver, element, element_info):ele_size = element.size  # 获取元素大小width = ele_size["width"]  # 获取元素的宽度height = ele_size["height"]  # 获取元素的高度# 获了element元素左上角点的坐标ele_position = element.locationx = ele_position["x"]  # 获取左上角点的x坐标值y = ele_position["y"]  # 获取左上角点的y坐标值start_x = x + width*0.9  # 获取的是起始点X的值y = y + height*0.5  # 获取的是起始及终止点的Y的值end_x = x + width*0.1   # 获取的是终止点X的值while True:page = driver.page_source  # 记录查找前的页面资源,通过对比页面资源来退出死循环try:driver.find_element(*element_info).click()  # 如果有找到对应的元素那么点击并返回return Trueexcept Exception as e:print("没有找到该元素!")driver.swipe(start_x, y, end_x, y, duration=1000)  # 没有找到元素,那么滑屏后再对比并重新查找time.sleep(1)if page == driver.page_source:print("滑屏操作完成且没有找到元素信息")return False

上述代码实现逻辑解释

  1. while True:创建一个无限循环。
  2. page = driver.page_source:记录查找前的页面资源,用于后续对比以判断是否退出循环。
  3. driver.find_element(*element_info).click():尝试查找并点击指定元素,如果找到则返回True。
  4. except Exception as e:如果没有找到元素,打印提示信息。
  5. driver.swipe(start_x, y, end_x, y, duration=1000):没有找到元素时,执行滑屏操作。
  6. time.sleep(1):等待一段时间。
  7. if page == driver.page_source:如果滑屏操作完成后页面资源没有变化,说明没有找到元素,打印相关提示并返回False。

4、scroll滑动事件

示例:driver.scroll(source_element,  target_element)

说明:scroll是通过元素来进行滑动的

  • source_element表示原元素;target_element表示目标元素,滑动原理是由原元素拖动到目标元素的位置
  • scroll无法设置滑动的持续时间,带有一定惯性。 主要用于IOS中,android高版本系统可以使用。

import time
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from appium.options.android import UiAutomator2Options
from selenium.webdriver.support import expected_conditions as EC# 定义一个初始化APP的方法
def start_app(app_package, app_activity):# 定义desired_caps 字典,初始化app的配置信息desired_caps = {"platformName": "android",  # 表示的是android"platformVersion": "10",  # 表示的是设备系统的版本号"deviceName": "DWV6R19A10002101",  # 表示的是设备的ID名称"appPackage": app_package,  # 表示的是app的包名"appActivity": app_activity,  # 表示的是app的界面名"newCommandTimeout": 100000,"noReset": True,  # 用来记住app的session,如果有登陆或做过初始化的操作,为True时,后面不需要再操作"resetKeyboard": True,  # 重置设备的输入键盘"unicodeKeyboard": True  # 采用unicode编码输入}# 创建 Appium 驱动实例options = UiAutomator2Options().load_capabilities(desired_caps)driver = webdriver.Remote("http://localhost:4723/wd/hub", options=options)# 启动应用程序driver.wait_activity(desired_caps, 5)return driver# 定义一个获取元素的方法
def get_element_new(driver, element):element = WebDriverWait(driver, 10).until(EC.visibility_of_element_located(element))return elementif __name__ == "__main__":# 本次启动的应用程序包名和活动名(作业帮)app_package_zyb = "com.baidu.homework"app_activity_zyb = ".activity.index.IndexActivity"# 启动应用程序driver_zyb = start_app(app_package_zyb, app_activity_zyb)# 进入「我的」tabmy_tab = (By.XPATH, '//android.widget.RelativeLayout[@resource-id="com.baidu.homework:id/tab_my_layout"]')get_element_new(driver_zyb, my_tab).click()# 找到「我的活动」元素My_activities = (By.XPATH, '//android.widget.TextView[@resource-id=''"com.baidu.homework:id/user_item_title" and @text="我的活动"]')my_activities = get_element_new(driver_zyb, My_activities)# 找到「我的订单」元素my_order = (By.ID, 'com.baidu.homework:id/user_item_title')my_order_element = get_element_new(driver_zyb, my_order)# 滑动driver_zyb.scroll(my_activities, my_order_element)# 关闭驱动time.sleep(3)print("代码执行完毕")driver_zyb.quit()

5、drag_and_drop拖拽事件

原理:从一个元素滑动到另外一个元素的位置, 同时也能实现将一个元素拖动另一个元素当中。

示例:driver.drag_and_drop(source_element,  target_element)

说明:

  • source_element 表示的是被拖动的元素对象
  • target_element 表示的是目标元素对象

import time
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from appium.options.android import UiAutomator2Options
from selenium.webdriver.support import expected_conditions as EC# 定义一个初始化APP的方法
def start_app(app_package, app_activity):# 定义desired_caps 字典,初始化app的配置信息desired_caps = {"platformName": "android",  # 表示的是android"platformVersion": "10",  # 表示的是设备系统的版本号"deviceName": "DWV6R19A10002101",  # 表示的是设备的ID名称"appPackage": app_package,  # 表示的是app的包名"appActivity": app_activity,  # 表示的是app的界面名"newCommandTimeout": 100000,"noReset": True,  # 用来记住app的session,如果有登陆或做过初始化的操作,为True时,后面不需要再操作# "resetKeyboard": True,  # 重置设备的输入键盘 (连接虚拟机时使用)# "unicodeKeyboard": True  # 采用unicode编码输入(连接虚拟机时使用)}# 创建 Appium 驱动实例options = UiAutomator2Options().load_capabilities(desired_caps)driver = webdriver.Remote("http://localhost:4723/wd/hub", options=options)# 启动应用程序driver.wait_activity(desired_caps, 5)return driver# 定义一个获取元素的方法
def get_element_new(driver, element):element = WebDriverWait(driver, 10).until(EC.visibility_of_element_located(element))return elementif __name__ == "__main__":# 本次启动的应用程序包名和活动名(作业帮)app_package_zyb = "com.baidu.homework"app_activity_zyb = ".activity.index.IndexActivity"# 启动应用程序driver_zyb = start_app(app_package_zyb, app_activity_zyb)# 进入「我的」tabmy_tab = (By.XPATH, '//android.widget.RelativeLayout[@resource-id="com.baidu.homework:id/tab_my_layout"]')get_element_new(driver_zyb, my_tab).click()# 找到「我的活动」元素My_activities = (By.XPATH, '//android.widget.TextView[@resource-id=''"com.baidu.homework:id/user_item_title" and @text="我的活动"]')my_activities = get_element_new(driver_zyb, My_activities)# 找到「我的订单」元素my_order = (By.ID, 'com.baidu.homework:id/user_item_title')my_order_element = get_element_new(driver_zyb, my_order)# 通过拖动来实现滑屏操作driver_zyb.drag_and_drop(my_activities,  my_order_element)# 关闭驱动time.sleep(3)print("代码执行完毕")driver_zyb.quit()

四、高级手势操作

实现步骤:

1、创建TouchAction对象

2、调用手势方法

3、调用perform() 执行操作

1、轻敲操作

示例说明:

  • action = TouchAction(driver)  #  创建建手势对象
  • action.tap(element=None, x=None, y=None, count=1)  # 调用轻敲手势方法,传入的是一个元素对象或者是一个坐标点
    count表示的是轻敲的次数, 默认值为1.
  • action.perform() # 调用perform()执行轻敲操作

2、按下和抬起操作

示例说明:

  • 按下:press(element, x, y)
  • 抬起:release()
  • TouchAction(driver).press(element=None, x=None, y=None).release().perform()

点击(原理):按下和抬起可以结合起来使用,达到点击的效果

3、等待操作

说明:模拟手指等待。 wait(ms=0)   ms表示的是毫秒数

示例:TouchAction(driver).press(element=None, x=None, y=None).wait(3000).release().perform()

长按(原理):通过等待及按下和抬起实现长按的操作

4、长按操作

示例:long_press(element, x=None, y=None,  duration=1000)

说明:

  • element表示的是元素对象
  • x, y表示的是坐标点
  • duration表示的是长按的时长,单位是毫秒

实现:

TouchAction(driver).long_press(element=None, x=None, y=None, duration=1000).perform()

5、移动操作

原理:模拟手指在手机屏幕上移动的过程,此种方式可以实现手势验证码的解锁(把所有的点都连接起来)

示例:

TouchAction(driver).press(element=None, x=None, y=None).wait(500).move_to(element=None, x=None, y=None).wait(500)
.move_to(element=None, x=None, y=None).release().perform()

说明:

  • move_to(element=None, x=None, y=None)  element表示的是元素对象, x和y表示的是坐标点。二选其一。
  • 移动的操作是需要结合press和release一起使用。

6、代码示例

import time
from appium import webdriver
from appium.webdriver.common.touch_action import TouchAction
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from appium.options.android import UiAutomator2Options
from selenium.webdriver.support import expected_conditions as EC# 定义一个初始化APP的方法
def start_app(app_package, app_activity):# 定义desired_caps 字典,初始化app的配置信息desired_caps = {"platformName": "android",  # 表示的是android"platformVersion": "10",  # 表示的是设备系统的版本号"deviceName": "DWV6R19A10002101",  # 表示的是设备的ID名称"appPackage": app_package,  # 表示的是app的包名"appActivity": app_activity,  # 表示的是app的界面名"newCommandTimeout": 100000,"noReset": True,  # 用来记住app的session,如果有登陆或做过初始化的操作,为True时,后面不需要再操作# "resetKeyboard": True,  # 重置设备的输入键盘 (连接虚拟机时使用)# "unicodeKeyboard": True  # 采用unicode编码输入(连接虚拟机时使用)}# 创建 Appium 驱动实例options = UiAutomator2Options().load_capabilities(desired_caps)driver = webdriver.Remote("http://localhost:4723/wd/hub", options=options)# 启动应用程序driver.wait_activity(desired_caps, 5)return driver# 定义一个获取元素的方法
def get_element_new(driver, element):element = WebDriverWait(driver, 10).until(EC.visibility_of_element_located(element))return elementif __name__ == "__main__":# 本次启动的应用程序包名和活动名(本机设置页面)app_package = "com.android.settings"app_activity = ".HWSettings"# 启动应用程序driver = start_app(app_package, app_activity)'''一、通过轻敲「WLAN」元素的方式进入WLAN设置页面action.tap(element=None, x=None, y=None, count=1).perform()'''wlan = (By.XPATH, '//android.widget.TextView[@resource-id="android:id/title" and @text="WLAN"]')wlan_btn = get_element_new(driver, wlan)TouchAction(driver).tap(wlan_btn).perform()'''二、通过「按下和抬起」的方式点击「更多WLAN设置」TouchAction(driver).press(element=None, x=None, y=None).release().perform()'''more_wlan = (By.XPATH, '//android.widget.TextView[@resource-id="android:id/title" and @text="更多 WLAN 设置"]')more_wlan_btn = get_element_new(driver, more_wlan)TouchAction(driver).press(more_wlan_btn).release().perform()# 返回上一页面time.sleep(1)driver.press_keycode(4)time.sleep(2)'''三、定位到Wi-Fi列表,通过「等待及按下和抬起」实现长按,展开删除网络/修改网络选项TouchAction(driver).press(element=None, x=None, y=None).wait(3000).release().perform()'''wlan_list = (By.XPATH, '//android.widget.FrameLayout[@resource-id=''"com.android.settings:id/drop_down_refresh_container"]/android.view.View')wlan_list_1 = get_element_new(driver, wlan_list)TouchAction(driver).press(wlan_list_1).wait(3000).release().perform()# 返回time.sleep(1)driver.press_keycode(4)time.sleep(3)'''四、定位到Wi-Fi列表,通过长按,展开删除网络/修改网络选项TouchAction(driver).long_press(element=None, x=None, y=None, duration=1000).perform()'''wlan_list = (By.XPATH, '//android.widget.FrameLayout[@resource-id=''"com.android.settings:id/drop_down_refresh_container"]/android.view.View')wlan_list_1 = get_element_new(driver, wlan_list)TouchAction(driver).long_press(wlan_list_1, duration=3000).perform()# 返回time.sleep(2)driver.press_keycode(4)'''五、通过move_to(element, x=x, y=y) 从一个元素移动到另一个元素此种方式可以实现手势验证码的解锁(把所有的点都连接起来)TouchAction(driver).press(element=None, x=None, y=None).wait(500).move_to(element=None, x=None, y=None).wait(500).move_to(element=None, x=None, y=None).release().perform()下图示例只为演示效果'''# 返回到设置页面time.sleep(2)driver.press_keycode(4)# 找到「更多连接」元素信息more_connections = (By.XPATH, '//android.widget.TextView[@resource-id="android:id/title" and @text="更多连接"]')more_connections_btn = get_element_new(driver, more_connections)# 由「更多连接」元素移动到「WLAN」元素位置(实际工作中,可以通过此种方式实现点到点的连接,完成手势验证码的解锁)TouchAction(driver).press(more_connections_btn).wait(500).move_to(wlan_btn).release().perform()# 关闭驱动time.sleep(3)print("代码执行完毕")driver.quit()

五、toast操作

Toast是Android中用来显示显示信息的一种机制,Toast的特点是没有焦点,而且显示的时间有限,过一定的时间就会自动消失。

定位方法:

  • 初始化配置中需要增加一个配置项:"automationName": "UiAutomator2"
  • toast 通用的class属性获取,通过xpath的方式://*[@class="android.widget.Toast"]

方法封装:

def get_toast(driver, timeout=3, poll_frequency=0.5):try:toast_loc = ("xpath", "//*[@class='android.widget.Toast']")WebDriverWait(driver, timeout, poll_frequency).until(es.presence_of_element_located(toast_loc))toast_text = driver.find_element(By.XPATH, "//*[@class='android.widget.Toast']").textreturn toast_textexcept:return None

代码示例:

import time
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from appium.options.android import UiAutomator2Options
from selenium.webdriver.support import expected_conditions as es# 定义一个初始化APP的方法
def start_app(app_package, app_activity):# 定义desired_caps 字典,初始化app的配置信息desired_caps = {"platformName": "android",  # 表示的是android"platformVersion": "10",  # 表示的是设备系统的版本号"deviceName": "DWV6R19A10002101",  # 表示的是设备的ID名称"appPackage": app_package,  # 表示的是app的包名"appActivity": app_activity,  # 表示的是app的界面名"newCommandTimeout": 100000,"noReset": True,  # 用来记住app的session,如果有登陆或做过初始化的操作,为True时,后面不需要再操作# "resetKeyboard": True,  # 重置设备的输入键盘 (连接虚拟机时使用)# "unicodeKeyboard": True  # 采用unicode编码输入(连接虚拟机时使用)"automationName": "UiAutomator2"  # 获取toast信息需要使用}# 创建 Appium 驱动实例options = UiAutomator2Options().load_capabilities(desired_caps)driver = webdriver.Remote("http://localhost:4723/wd/hub", options=options)# 启动应用程序driver.wait_activity(desired_caps, 5)return driver# 定义一个获取元素的方法
def get_element_new(driver, element):element = WebDriverWait(driver, 10).until(es.visibility_of_element_located(element))return element# 定义一个封装滑屏操作的方法
def slide_screen(driver, direction, count=1):w = driver.get_window_size()["width"]  # 获取手机屏幕的宽度h = driver.get_window_size()["height"] # 获取手机屏幕的高度# w=1080  h=1920if direction == "up":  # 往上滑zb = (w/2, h*0.9, w/2, h*0.1)elif direction == "down":  # 往下滑zb = (w/2, h*0.1, w/2, h*0.9)elif direction == 'left':  # 往左滑zb = (w*0.9, h/2, w*0.1, h/2)elif direction == 'right':   # 往右滑zb = (w*0.1, h/2, w*0.9, h/2)else:print("无法识别滑动方向,请重新输入!")for i in range(count):driver.swipe(*zb, duration=1200)time.sleep(1)# 定义一个获取toast的方法
def get_toast(driver, timeout=3, poll_frequency=0.5):try:toast_loc = ("xpath", "//*[@class='android.widget.Toast']")WebDriverWait(driver, timeout, poll_frequency).until(es.presence_of_element_located(toast_loc))toast_text = driver.find_element(By.XPATH, "//*[@class='android.widget.Toast']").textreturn toast_textexcept:return Noneif __name__ == "__main__":# 本次启动的应用程序包名和活动名(本机设置页面)app_package = "com.android.settings"app_activity = ".HWSettings"# 启动应用程序driver = start_app(app_package, app_activity)# 向上滑动页面两次到页面底部slide_screen(driver, "up", 2)time.sleep(2)# 找到「关于本机」按钮并点击about_this_machine = (By.XPATH, '//android.widget.TextView[@resource-id="android:id/title" and @text="关于手机"]')get_element_new(driver, about_this_machine).click()# 获取版本号元素信息并点击(for循环进行多次点击)version = (By.XPATH, '//android.widget.TextView[@resource-id="android:id/title" and @text="HarmonyOS 版本"]')version_btn = get_element_new(driver, version)for i in range(1, 6):if i <= 6:version_btn.click()i += 1# 获取toast提示信息并打印# toast_text = driver.find_element(By.XPATH, "//*[@class=\"android.widget.Toast\"]").text# print(f"toast提示信息是:{toast_text}")toast_text = get_toast(driver)print(toast_text)# 关闭驱动time.sleep(3)print("代码执行完毕")driver.quit()

方法二:如果上述方法无法实现获取toast信息,可以通过截图记录toast信息

代码示例如下:

import time
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from appium.options.android import UiAutomator2Options
from selenium.webdriver.support import expected_conditions as EC# 定义一个初始化APP的方法
def start_app(app_package, app_activity):# 定义desired_caps 字典,初始化app的配置信息desired_caps = {"platformName": "android",  # 表示的是android"platformVersion": "10",  # 表示的是设备系统的版本号"deviceName": "DWV6R19A10002101",  # 表示的是设备的ID名称"appPackage": app_package,  # 表示的是app的包名"appActivity": app_activity,  # 表示的是app的界面名"newCommandTimeout": 100000,"noReset": True,  # 用来记住app的session,如果有登陆或做过初始化的操作,为True时,后面不需要再操作# "resetKeyboard": True,  # 重置设备的输入键盘 (连接虚拟机时使用)# "unicodeKeyboard": True  # 采用unicode编码输入(连接虚拟机时使用)"automationName": "Uiautomator2"}# 创建 Appium 驱动实例options = UiAutomator2Options().load_capabilities(desired_caps)driver = webdriver.Remote("http://localhost:4723/wd/hub", options=options)# 启动应用程序driver.wait_activity(desired_caps, 5)return driver# 定义一个获取元素的方法
def get_element_new(driver, element):element = WebDriverWait(driver, 10).until(EC.visibility_of_element_located(element))return element# 定义一个封装滑屏操作的方法
def slide_screen(driver, direction, count=1):w = driver.get_window_size()["width"]  # 获取手机屏幕的宽度h = driver.get_window_size()["height"] # 获取手机屏幕的高度# w=1080  h=1920if direction == "up":  # 往上滑zb = (w/2, h*0.9, w/2, h*0.1)elif direction == "down":  # 往下滑zb = (w/2, h*0.1, w/2, h*0.9)elif direction == 'left':  # 往左滑zb = (w*0.9, h/2, w*0.1, h/2)elif direction == 'right':   # 往右滑zb = (w*0.1, h/2, w*0.9, h/2)else:print("无法识别滑动方向,请重新输入!")for i in range(count):driver.swipe(*zb, duration=1200)time.sleep(1)if __name__ == "__main__":# 本次启动的应用程序包名和活动名(本机设置页面)app_package = "com.android.settings"app_activity = ".HWSettings"# 启动应用程序driver = start_app(app_package, app_activity)# 向上滑动页面两次到页面底部slide_screen(driver, "up", 2)time.sleep(2)# 找到「关于本机」按钮并点击about_this_machine = (By.XPATH, '//android.widget.TextView[@resource-id="android:id/title" and @text="关于手机"]')get_element_new(driver, about_this_machine).click()# 获取版本号元素信息并点击(for循环进行多次点击)version = (By.XPATH, '//android.widget.TextView[@resource-id="android:id/title" and @text="HarmonyOS 版本"]')version_btn = get_element_new(driver, version)for i in range(1, 6):if i <= 6:version_btn.click()i += 1# 获取toast信息(截图)# 获取手机截图""" 1、路径必须手动创建2、文件名称必须是以PNG结尾"""current_time_file = "/error" + str(time.time())  # 通过文件名拼接当前时间戳的方式构造唯一文件名filename = "/替换成自己正确的路径" + current_time_file + ".png"time.sleep(0.5)driver.get_screenshot_as_file(filename) # 获取toast信息截图# 关闭驱动time.sleep(3)print("代码执行完毕")driver.quit()

六、webview操作(H5)

说明Appium Inspector 可以对 H5 页面元素直接进行操作。在操作混合 App 或 Android App 的 H5 页面时,常常需要定位 H5 页面中的元素,传统方式需要使用Chrome://inspect 来定位元素,环境准备相当繁琐,需要Android 设备安装 Google 框架以及手机版 Chrome 浏览器以及相应的 chromedriver。而使用 Appium Inspector 即可实现 H5 页面元素的定位,不需要额外安装任何软件。

示例:

如下图包含原生和H5页面(混合APP)['NATIVE_APP', 'WEBVIEW_com.huawei.browser'],可以通过Appium Inspector轻松实现定位操作:

代码示例:

import time
from appium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from appium.options.android import UiAutomator2Options
from selenium.webdriver.support import expected_conditions as EC# 定义一个初始化APP的方法
def start_app(app_package, app_activity):# 定义desired_caps 字典,初始化app的配置信息desired_caps = {"platformName": "android",  # 表示的是android"platformVersion": "10",  # 表示的是设备系统的版本号"deviceName": "DWV6R19A10002101",  # 表示的是设备的ID名称,标识测试设备"appPackage": app_package,  # 表示的是app的包名"appActivity": app_activity,  # 表示的是app的界面名"newCommandTimeout": 100000,"noReset": True,  # 用来记住app的session,如果有登陆或做过初始化的操作,为True时,后面不需要再操作# "resetKeyboard": True,  # 重置设备的输入键盘 (连接虚拟机时使用)# "unicodeKeyboard": True  # 采用unicode编码输入(连接虚拟机时使用)}# 创建 Appium 驱动实例options = UiAutomator2Options().load_capabilities(desired_caps)driver = webdriver.Remote("http://localhost:4723/wd/hub", options=options)# 启动应用程序driver.wait_activity(desired_caps, 5)return driver# 定义一个获取元素的方法
def get_element_new(driver, element):element = WebDriverWait(driver, 10).until(EC.visibility_of_element_located(element))return elementif __name__ == "__main__":# 本次启动的应用程序包名和活动名(本机设置页面)app_package = "com.baidu.homework"app_activity = ".activity.index.IndexActivity"# 启动应用程序driver = start_app(app_package, app_activity)# 定位h5页面中的一个元素并点击h5_xpath = By.XPATH, '(//android.widget.ImageView[@resource-id="com.baidu.homework:id/image"])[1]'get_element_new(driver, h5_xpath).click()# 这里可以获取下上下文,可以发现这里包含原生和H5页面(混合APP)['NATIVE_APP', 'WEBVIEW_com.huawei.browser']contexts = driver.contextsprint(contexts)# 定位h5页面中的另一个元素并点击h5_ = By.XPATH, '(//android.widget.Image[@text="zyb_e7dd291daa70ff318315b0b5dcc59989"])[1]'get_element_new(driver, h5_).click()# 关闭驱动time.sleep(3)print("代码执行完毕")driver.quit()

相关文章:

APP自动化测试-Appium常见操作之详讲

一、基本操作 1、点击操作 示例&#xff1a;element.click() 针对元素进行点击操作 2、初始化&#xff1a;输入中文的处理 说明&#xff1a;如果连接的是虚拟机&#xff08;真机无需加这两个参数&#xff0c;加上可能会影响手工输入&#xff09;&#xff0c;在初始化配置中…...

写给大数据开发:谈谈数仓建模的反三范式

在数仓建设中&#xff0c;我们经常谈论反三范式。顾名思义&#xff0c;反范式化指的是通过增加冗余或重复的数据来提高数据库的读性能。简单来说&#xff0c;就是浪费存储空间&#xff0c;节省查询时间。用行话讲&#xff0c;这就是以空间换时间。听起来像是用大炮打蚊子&#…...

Stable diffusion 3 正式开源

6月12日晚&#xff0c;著名开源大模型平台Stability AI正式开源了&#xff0c;文生图片模型Stable Diffusion 3 Medium&#xff08;以下简称“SD3-M”&#xff09;权重。 SD3-M有20亿参数&#xff0c;平均生成图片时间在2—10秒左右推理效率非常高&#xff0c;同时对硬件的需求…...

如何配置node.js环境

文章目录 step1. 下载node.js安装包step2. 创建node_global, node_cache文件夹step3.配置node环境变量step3. cmd窗口检查安装的node和npm版本号step4. 设置缓存路径\全局安装路径\下载镜像step5. 测试配置的nodejs环境 step1. 下载node.js安装包 下载地址&#xff1a;node.js…...

python tensorflow 各种神经元

感知机神经元&#xff08;Perceptron Neuron&#xff09;&#xff1a; 最基本的人工神经元模型&#xff0c;用于线性分类任务。 import numpy as npclass Perceptron:def __init__(self, input_size, learning_rate0.01, epochs1000):self.weights np.zeros(input_size 1) #…...

Gone框架介绍27 - 再讲 Goner 和 依赖注入

gone是可以高效开发Web服务的Golang依赖注入框架 github地址&#xff1a;https://github.com/gone-io/gone 文档地址&#xff1a;https://goner.fun/zh/ 文章目录 Goner 和 依赖注入Goner的定义依赖标记Goners 注册Priest函数 Goner 和 依赖注入 Gone 作为一个依赖注入框架&am…...

【Python/Pytorch 】-- 滑动窗口算法

文章目录 文章目录 00 写在前面01 基于Python版本的滑动窗口代码02 算法效果 00 写在前面 写这个算法原因是&#xff1a;训练了一个时序网络&#xff0c;该网络模型的时序维度为32&#xff0c;而测试数据的时序维度为90。因此需要采用滑动窗口的方法&#xff0c;生成一系列32…...

Clickhouse集群create drop database可删除集群数据库或只删除本地数据库

集群环境下&#xff0c;在任意一个节点创建数据库&#xff0c;如果加上了ON CLUSTER clustername&#xff0c;则在集群环境的所有节点上都创建了该数据库&#xff0c;并在集群环境的所有节点上都创建了该数据库对应的目录&#xff0c;且数据库的metadata_path对应的目录路径在所…...

【docker】adoptopenjdk/openjdk8-openj9:alpine-slim了解

adoptopenjdk/openjdk8-openj9:alpine-slim 是一个 Docker 镜像的标签&#xff0c;它指的是一个特定的软件包&#xff0c;用于在容器化环境中运行 Java 应用程序。 镜像相关的网站和资源&#xff1a; AdoptOpenJDK 官方网站 - AdoptOpenJDK 这是 AdoptOpenJDK 项目的官方网站&…...

Vscode interaction window

python 代码关联到 jupyter 模式 在代码前添加&#xff1a; # %%print("hellow wolrd!") 参考文档链接&#xff1a; https://code.visualstudio.com/docs/python/jupyter-support-py...

后端数据null前端统一显示成空

handleNullValues方法在封装请求接口返回数据时统一处理 // null 转 function handleNullValues(data) {// 使用递归处理多层嵌套的对象或数组function processItem(item) {if (Array.isArray(item)) {return item.map(processItem);} else if (typeof item object &&…...

【设计模式深度剖析】【9】【行为型】【访问者模式】| 以博物馆的导览员为例加深理解

&#x1f448;️上一篇:备忘录模式 | 下一篇:状态模式&#x1f449;️ 设计模式-专栏&#x1f448;️ 文章目录 访问者模式定义英文原话直译如何理解呢&#xff1f; 访问者模式的角色类图代码示例 访问者模式的应用优点缺点使用场景 示例解析:博物馆的导览员代码示例 访问…...

Salesforce‘s 爱因斯坦机器人助手引领工业聊天机器人时代

CRM的对话式人工智能助手&#xff0c;根据公司数据提供可靠的人工智能响应及日本工业聊天机器人现状 【前言】 爱因斯坦助手&#xff08;Einstein Copilot&#xff09;提供可靠的响应&#xff0c;因为它基于公司独特的数据和元数据&#xff0c;使其能够深入了解公司的业务和客…...

Day7—zookeeper基本操作

ZooKeeper介绍 ZooKeeper&#xff08;动物园管理员&#xff09;是一个分布式的、开源的分布式应用程序的协调服务框架&#xff0c;简称zk。ZooKeeper是Apache Hadoop 项目下的一个子项目&#xff0c;是一个树形目录服务。 ZooKeeper的主要功能 配置管理 分布式锁 集群管理…...

计算机组成原理---Cache的基本工作原理习题

对应知识点&#xff1a; Cache的基本原理 1.某存储系统中&#xff0c;主存容量是Cache容量的4096倍&#xff0c;Cache 被分为 64 个块&#xff0c;当主存地址和Cache地址采用直接映射方式时&#xff0c;地址映射表的大小应为&#xff08;&#xff09;(假设不考虑一致维护和替…...

springboot项目中切数据库(mysql-> pg)带来的适配问题:typeHandler

一、数据表中有一张表&#xff0c;名为role_permission&#xff0c;DDL如下&#xff1a; CREATE TABLE "public"."role_permission" ( "role_id" varchar(64) COLLATE "pg_catalog"."default" NOT NULL, "permiss…...

从零开始的<vue2项目脚手架>搭建:vite+vue2+eslint

前言 为了写 demo 或者研究某些问题&#xff0c;我经常需要新建空项目。每次搭建项目都要从头配置&#xff0c;很麻烦。所以我决定自己搭建一个项目初始化的脚手架&#xff08;取名为 lily-cli&#xff09;。 脚手架&#xff08;scaffolding&#xff09;&#xff1a;创建项目时…...

Hadoop升级失败,File system image contains an old layout version -64

原始版本 Hadoop 3.1.3 升级版本 Hadoop 3.3.3 报错内容如下 datasophon 部署Hadoop版本 查看Hadoop格式化版本 which hadoop-daemon.sh/bigdata/app/hadoop-3.1.3/sbin/hadoop-daemon.sh删除原来的旧版本 rm -rf /bigdata/app/hadoop-3.1.3查看环境变量 env|grep HADOOPHAD…...

[机器学习算法]决策树

1. 理解决策树的基本概念 决策树是一种监督学习算法&#xff0c;可以用于分类和回归任务。决策树通过一系列规则将数据划分为不同的类别或值。树的每个节点表示一个特征&#xff0c;节点之间的分支表示特征的可能取值&#xff0c;叶节点表示分类或回归结果。 2. 决策树的构建…...

springboot应用cpu飙升的原因排除

1、通过top或者jps命令查到是那个java进程&#xff0c; top可以看全局那个进程耗cpu&#xff0c;而jps则默认是java最耗cpu的&#xff0c;比如找到进程是196 1.1 top (推荐)或者jps命令均可 2、根据第一步获取的进程号&#xff0c;查询进程里那个线程最占用cpu&#xff0c;发…...

反激开关电源EMI电路选型及计算

EMI &#xff1a;开关电源对电网或者其他电子产品的干扰 EMI &#xff1a;传导与辐射 共模电感的滤波电路&#xff0c;La和Lb就是共模电感线圈。这两个线圈绕在同一铁芯上&#xff0c;匝数和相位都相 同(绕制反向)。 这样&#xff0c;当电路中的正常电流&#xff08;差模&…...

vue3前端对接后端的图片验证码

vue3前端对接后端的图片验证码 <template> <image :src"captchaUrl" alt"图片验证码" click"refreshCaptcha"></image> </template><script setup>import {ref} from "vue";import {useCounterStore} …...

【Unity】RPG2D龙城纷争(四)要诀、要诀数据集

更新日期&#xff1a;2024年6月20日。 项目源码&#xff1a;第五章发布&#xff08;正式开始游戏逻辑的章节&#xff09; 索引 简介要诀数据集&#xff08;AbilityDataSet&#xff09;一、定义要诀数据集类二、要诀属性1.要诀类型2.攻击距离3.基础命中、暴击率4.基础属性加成5.…...

一种基于非线性滤波过程的旋转机械故障诊断方法(MATLAB)

在众多的旋转机械故障诊断方法中&#xff0c;包络分析&#xff0c;又称为共振解调技术&#xff0c;是目前应用最为成功的方法之一。首先&#xff0c;对激励引起的共振频带进行带通滤波&#xff0c;然后对滤波信号进行包络谱分析&#xff0c;通过识别包络谱中的故障相关的特征频…...

HarmonyOS Next 系列之从手机选择图片或拍照上传功能实现(五)

系列文章目录 HarmonyOS Next 系列之省市区弹窗选择器实现&#xff08;一&#xff09; HarmonyOS Next 系列之验证码输入组件实现&#xff08;二&#xff09; HarmonyOS Next 系列之底部标签栏TabBar实现&#xff08;三&#xff09; HarmonyOS Next 系列之HTTP请求封装和Token…...

如果xml在mapper目录下,如何扫描到xml

如果xml在mapper目录下,如何扫描到xml 项目结构 src├── main│ ├── java│ │ └── com│ │ └── bg│ │ ├── Application.java│ │ ├── domain│ │ │ └── User.java│ │ …...

什么是无限铸币攻击?它是如何运作的?

一、无限铸币攻击解释 无限铸币攻击是指攻击者操纵合约代码不断铸造超出授权供应限制的新代币。 这种黑客行为在去中心化金融 (DeFi) 协议中最为常见。这种攻击通过创建无限数量的代币来损害加密货币或代币的完整性和价值。 例如&#xff0c;一名黑客利用了 Paid 网络的智能…...

【Android】怎么使APP进行开机启动

项目需求 在Android系统开启之后&#xff0c;目标app可以在系统开机之后启动。 项目实现 使用广播的方式 首先我们要创建一个广播(这里是启动了一个Service服务) public class BootReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, I…...

详细分析Element Plus的el-pagination基本知识(附Demo)

目录 前言1. 基本知识2. Demo3. 实战 前言 需求&#xff1a;从无到有做一个分页并且附带分页的导入导出增删改查等功能 前提一定是要先有分页&#xff0c;作为全栈玩家&#xff0c;先在前端部署一个分页的列表 相关后续的功能&#xff0c;是Java&#xff0c;推荐阅读&#x…...

ubuntu换镜像源方法

查看ubuntu的版本&#xff0c;不同的版本对应的不同的镜像源 cat /etc/issue Ubuntu 18.04.6 LTS \n \l 先备份一个&#xff0c;防止更改错误 cobol cp /etc/apt/sources.list /etc/apt/sources.list.backup 先进入清华源,搜索ubuntu&#xff0c;点击问号 点进来可以看到可以…...

自学网站建设最快要多久/温州seo品牌优化软件

PS&#xff1a;Nginx/LVS/HAProxy是目前使用最广泛的三种负载均衡软件&#xff0c;本人都在多个项目中实施过&#xff0c;参考了一些资料&#xff0c;结合自己的一些使用经验&#xff0c;总结一下。 一般对负载均衡的使用是随着网站规模的提升根据不同的阶段来使用不同的技术。…...

做网站流程、/广东做seo的公司

设计模式原则 1、开-闭原则&#xff08;OCP Open Close Principle&#xff09; 面向对象可利用设计(OOD)的第一块基石&#xff0c;就是“开-闭原则&#xff08;Open-Closed principle,简称OCP&#xff09;&#xff0c;它的核心含意是&#xff1a;一个好的设计应该能够容纳新的…...

江门网站建设费用/关键词优化分析工具

为了支持不同的数据源&#xff0c;数据访问层&#xff0c;就不能简单的创建不同的Command,Conection,DataAdapter对象。根据不同的数据源进行不同的t-sql语句转换&#xff0c;下面我们就来看看数据层对函数的支持。 Abs Dim o As New Common.主表_Operate Dim item As New Comm…...

营销型网站建设实战感想/店铺100个关键词

文章目录1 Redis 介绍2 Redis 安装3 benchmark性能测试4 Redis 卸载1 Redis 介绍 Redis&#xff08;Remote Dictionary Server )&#xff0c;即远程字典服务&#xff0c;是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库&#xff0c…...

360网站怎么做ppt/百度知道免费提问

描述 从镜像仓库中拉取或者更新指定镜像 语法 查看帮助 docker pull --helpdocker pull [OPTIONS] NAME[:TAG|DIGEST] Options说明 名称,简称默认描述-a&#xff0c;–all-tags拉取所有 tagged 镜像–disable-content-trusttrue忽略镜像的校验-q&#xff0c;–quiet禁止详细…...

自治区住房和城乡建设厅网站/seo优化范畴

2019独角兽企业重金招聘Python工程师标准>>> 能用代码说话的&#xff0c;觉不打字描述 public static void main(String[] args){//List<Long> to List<String>List<Long> numList1 new ArrayList<>();numList1.add(1L);numList1.add(2L)…...