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,然后获取当前手机的网络类型
    """飞行模式:1
    WiFi 流量:2
    数据流量:4
    数据和 WiFi 全部打开:6"""
    driver_zyb.set_network_connection(2)   # 设置手机网络为Wi-Fi
    print(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=1920
    if 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.location
    x = 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 True
        except 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 element


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)

    # 进入「我的」tab
    my_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 element


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)

    # 进入「我的」tab
    my_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 element


if __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']").text
        return toast_text
    except:
        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=1920
    if 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']").text
        return toast_text

    except:
        return None


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提示信息并打印
    # 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=1920
    if 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 element


if __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.contexts
    print(contexts)

    # 定位h5页面中的另一个元素并点击
    h5_ = By.XPATH, '(//android.widget.Image[@text="zyb_e7dd291daa70ff318315b0b5dcc59989"])[1]'
    get_element_new(driver, h5_).click()

    # 关闭驱动
    time.sleep(3)
    print("代码执行完毕")
    driver.quit()

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

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

相关文章

Java--Arrays类

1.数组的工具java.util.Arrays 2.由于数组对象本身并没有什么方法可以供我们调用&#xff0c;但API中提供了一个工具类Arrays供我们使用&#xff0c;从而可以对数据对象进行一些基本的操作。 3.查看JDK帮助文档 4.Arrays类中的方法都是static修饰静态的静态方法&…

minSdkVersion、targetSdkVersion、compileSdkVersion三者的作用解析

minSDK和targetSDK&#xff0c;这两者相当于一个区间。你能够用到targetSDK中最新的API和最酷的新功能&#xff0c;但又需要向后(向下)兼容到minSDK&#xff0c;保证这个区间内的设备都能够正常的执行你的APP。换句话说&#xff0c;想使用Android刚刚推出的新特性&#xff0c;但…

6 PXE高效批量网络装机

6.1部署PXE远程安装服务 在大规模的Liunx应用环境中&#xff0c;如web群集&#xff0c;分布式计算等&#xff0c;服务器往往并不配备光驱设备&#xff0c;在这种情况下&#xff0c;如何为数十乃至上百台服务器裸机快速安装系统呢&#xff1f;传统的USB光驱&#xff0c;移动硬盘…

零编程数据可视化展示:十个简易案例!

数据可视化是呈现数据内在价值的最终手段。数据可视化实例利用各种图表和图形设计手段&#xff0c;合乎逻辑地展示复杂而不直观的数据。为了让用户直观清楚地了解他们想要的数据及其比较关系&#xff0c;数据可视化实例的呈现至关重要。即时设计整理了10个数据可视化实例&#…

17-C语言中的变量生命周期——自动存储期、青苔存储期、自定义存储期

17-C语言中的变量生命周期——自动存储期、青苔存储期、自定义存储期 文章目录 17-C语言中的变量生命周期——自动存储期、青苔存储期、自定义存储期一、自动存储期示例 二、静态存储期2.1 示例 三、自定义存储期3.1 如何申请内存3.2 如何释放内存3.3 如何清空内存3.4 示例 概念…

【学习DayNa】信息系统开发整理

✍&#x1f3fb;记录学习过程中的输出&#xff0c;坚持每天学习一点点~ ❤️希望能给大家提供帮助~欢迎点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;指点&#x1f64f; 结构化方法 结构是指系统内各个组成要素之间的相互联系、相互作用的框架。结构化开发方法就是…

需求工程师的基本职责(合集)

需求工程师的基本职责1 职责&#xff1a; 1、负责用户需求调研、用户需求分析&#xff0c;明确用户需求分析&#xff0c;明确用户功能需求、业务需求&#xff0c;转换成软件需求说明。 2、收集、分析、整理、提炼系统需求&#xff0c;能够对业务流程提出优化建议并写成系统功能…

音视频入门基础:H.264专题(1)——H.264官方文档下载

音视频入门基础&#xff1a;H.264专题系列文章&#xff1a; 音视频入门基础&#xff1a;H.264专题&#xff08;1&#xff09;——H.264官方文档下载 音视频入门基础&#xff1a;H.264专题&#xff08;2&#xff09;——使用FFmpeg命令生成H.264裸流文件 音视频入门基础&…

SpringBoot整合Minio(支持公有及私有bucket)

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; SpringBoot整合Minio(支持公有及私有bucket) ⏱️ 创作时间&#xff1…

第6章 设备驱动程序(4)

目录 6.5 块设备操作 6.5.5 请求结构 6.5.6 BIO 6.5.7 提交请求 6.5.8 I/O调度 6.5.9 ioctl实现 本专栏文章将有70篇左右&#xff0c;欢迎关注&#xff0c;查看后续文章。 6.5 块设备操作 6.5.5 请求结构 struct request { //放在请求队列上&#xff0…

Go Gin框架

一、Gin介绍 Gin是一个用Go编写的HTTPweb框架。它是一个类似于martini但拥有更好性能的API框架, 优于httprouter&#xff0c;速度提高了近 40 倍。点击此处访问Gin官方中文文档。 二、安装 1、安装Gin go get -u github.com/gin-gonic/gin 2、代码中引入 import "githu…

【Docker】——安装镜像和创建容器,详解镜像和Dockerfile

前言 在此记录一下docker的镜像和容器的相关注意事项 前提条件&#xff1a;已安装Docker、显卡驱动等基础配置 1. 安装镜像 网上有太多的教程&#xff0c;但是都没说如何下载官方的镜像&#xff0c;在这里记录一下&#xff0c;使用docker安装官方的镜像 Docker Hub的官方链…

进阶篇05——存储过程、存储函数、触发器

存储过程 简介 基本语法 创建和调用 -- 创建名为p1的存储过程&#xff0c;小括号里可以跟参数 -- 存储过程个人觉得就是SQL里的函数 create procedure p1() begin-- begin 和 end 之间是封装的SQL语句-- 可以是一条SQL也可以是多条SQLselect * from student; end;-- 调用存储…

【FreeRTOS】估算栈的大小

参考《FreeRTOS入门与工程实践(基于DshanMCU-103).pdf》 目录 估算栈的大小回顾简介计算说明估计函数用到的栈有多大合计 估算栈的大小 回顾 上一篇文章链接&#xff1a;http://t.csdnimg.cn/Cc8b4 传送门: 上一篇文章 上一篇文章创建的三个任务 /* 创建任务&#xff1a;声 *…

vivado SITE

描述 SITE是一个设备对象&#xff0c;表示许多不同类型的逻辑资源之一 可在目标Xilinx FPGA上获得。 SITE包括SLICE/CLB&#xff0c;它们是基本逻辑元件&#xff08;BEL&#xff09;的集合&#xff0c;如 查找表&#xff08;LUT&#xff09;、触发器、多路复用器&#xff0c;携…

网页钓鱼-克隆修改--劫持口令下载后门

免责声明:本文仅做技术交流与学习... 目录 1-右键另存为 2-goblin项目(不推荐) 修改goblin.yaml文件 运行exe ​编辑 3-Setoolkit (kali自带) 网页克隆---> 1-右键另存为 --不行就再定位元素进行修改. 2-goblin项目(不推荐) GitHub - xiecat/goblin: 一款适用于红蓝…

力扣每日一题 6/19 排序+动态规划

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;IT竞赛 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 2713.矩阵中严格递增的单元格数【困难】 题目&#xff1a; 给你一个下标从…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 部门组队编程(200分) - 三语言AC题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; &#x1f…

项目3:从0开始的RPC框架(扩展版)-3

七. 负载均衡 1. 需求分析 目前我们的RPC框架仅允许消费者读取第一个服务提供者的服务节点&#xff0c;但在实际应用中&#xff0c;同一个服务会有多个服务提供者上传节点信息。如果消费者只读取第一个&#xff0c;势必会增大单个节点的压力&#xff0c;并且也浪费了其它节点…

文件扫描工具都有哪些?职场大佬都在用的文本提取工具大盘点~

回想起刚毕业初入职场那阵子&#xff0c;领导让帮忙把纸质文件扫描提取为文本时&#xff0c;还只会傻乎乎地一点点操作&#xff0c;属实是费劲得很&#xff01; 好在后面受朋友安利&#xff0c;找到了4个能够快速实现文件扫描文字提取的方法&#xff0c;这才让我的办公效率蹭蹭…