【Appium学习总结3】----Appium常用代码

前置代码

```python

from appium import webdriver

import time

desired_caps = dict()

# 平台名,大小写不敏感

desired_caps['platformName'] = 'Android'

# android系统版本

desired_caps['platformVersion'] = '5.1'

# 设备名,可通过adb devices命令获取

desired_caps['deviceName'] = '192.168.x.x'

# 要打开的app包名

# 可通过adb shell dumpsys window windows | findstr mFocusedApp获取

desired_caps['appPackage'] = 'com.android.settings'

# 要打开的界面名

# 可通过adb shell dumpsys window windows | findstr mFocusedApp获取

desired_caps['appActivity'] = '.Settings'

driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)

time.sleep(5)

driver.quit()

```

1、元素定位

元素定位:

​ step1、打开uiautomatorviewer工具

​ step2、打开真机或模拟器

​ step3、通过uiautomatorviewer工具获取想要选择的元素的Node Detail信息

​ step4、通过元素定位API进行定位

​ step5、对元素进行相关操作

1.1、定位一个元素

```python

# 通过id定位一个元素

# 参数:id_value-->元素的resource_id属性值

# 返回值:定位到的单个元素

driver.find_element_by_id(id_value)

```

```python

# 通过class_name定位一个元素

# 参数:class_value-->元素的class属性值

# 返回值:定位到的单个元素

driver.find_element_by_class_name(class_value)

```

```python

# 通过xpath定位一个元素

# 参数:xpath_value-->元素的xpath属性值

# 返回值:定位到的单个元素

driver.find_element_by_xpath(xpath_value)

```

注:如果很多元素的”特征“相同,使用find_element_by_xxx的方法会找到第一个,所以,尽量去找元素特征有唯一性的”特征“来定位

1.2、定位一组元素

```python

# 通过id定位一组元素

# 参数:id_value-->元素的resource_id属性值

# 返回值:定位到的一组元素

driver.find_elements_by_id(id_value)

```

```python

# 通过class_name定位一组元素

# 参数:class_value-->元素的class属性值

# 返回值:定位到的一组元素

driver.find_elements_by_class_name(class_value)

```

```python

# 通过xpath定位一组元素

# 参数:xpath_value-->元素的xpath属性值

# 返回值:定位到的一组元素

driver.find_elements_by_xpath(xpath_value)

```

注:如果通过一组的方式进行定位,获取的返回值不再是一个元素,而是一个列表,列表中装着所有符合这个特征的元素

1.3、定位元素注意点

如果find_element_by_xxx方法,传入了一个没有的条件,会报错,NoSuchElementException

如果find_elements_by_xxx方法,传入了一个没有的条件,不会报错,返回一个空列表

2、元素等待

2.1、隐式等待:

关键方法:

- 通过driver对象调用implicitly_wait方法

- 设置超时时间

作用:

- 在设置了超时时间之后,后续所有的定位元素的方法都会在这个时间内等待元素出现

- 如果出现了,直接进行后续操作(等待跳出)

- 如果没有出现,报错NoSuchElementException

```python

# time为等待时间,单位为秒

driver.implicitly_wait(time)

```

 2.2、显式等待:

关键方法:

- 关键类:WebDriverWait

- 关键方法:WebDriverWait对象中的until的方法

作用:

- 在设置了显式等待之后,可以等待一个超时时间,在这个超时时间之内进行查找,默认每0.5秒查找元素一次(查找频率可配置)

- 如果找到元素,直接进行后续操作

- 如果没有找到元素,报错TimeOutException

```python

# 使用显示等待,在30秒时间内,每3秒查询一次,id为xxx的元素

WebDriverWait(driver, 30, 3).until(lambda x: x.find_element_by_id("xxx"))

```

2.3、显式等待和隐式等待的区别

作用域:

- 隐式等待对全局有效,显式等待只对单个元素有效

方法:

- 隐式等待直接通过driver实例化对象调用,显式等待方法封装在WebDriverWait类中

3、元素操作方法

3.1、点击元素

```python

#对element按钮进行点击操作

driver.find_element_by_id("xxx").click()

```

3.2、输入和清空内容

```python

# 在输入框中输入hello

driver.find_element_by_id("xxx").send_keys("hello")

# 清空输入框

driver.find_element_by_id("xxx").clear()

```

注意点:输入框输入中文无效,但不会报错,需要在“前置代码中”增加两个参数

```python

desired_caps['unicodeKeyboard'] = True

desired_caps['resetKeyboard'] = True

```

3.3、获取文本内容

```python

driver.find_element_by_id("xxx").text

```

3.4、获取元素位置和大小

```python

# 获取元素的位置,返回值是字典,{'x': 111, 'y': 222},x和y分别为距离屏幕左上角的距离

driver.find_element_by_id("xxx").location

```

```python

# 获取元素大小,返回值是字典,{'width': 111, 'heigth': 222},width是元素宽度,heigth是元素高度

driver.find_element_by_di('xxx').size

```

3.5、获取元素的属性值

```python

# 获取元素enable的属性值

driver.find_element_by_id("xxx").get_attribute("enable")

# 获取元素text属性值,等价于 driver.find_element_by_id("xxx").text

driver.find_element_by_id("xxx").get_attribute("text")

# 获取元素content_desc/text属性值,如果content_desc属性值不为空,则输出content_desc属性值,为空,则输出text属性值

driver.find_element_by_id("xxx").get_attribute("name")

# 获取元素resource-id属性值

driver.find_element_by_id("xxx").get_attribute("resourceId")

# 获取元素class属性值

driver.find_element_by_id("xxx").get_attribute("className")

```

4、滑动和拖拽事件

4.1、swipe滑动事件

```python

# 从一个位置滑动到另一个坐标位置,两点之间的滑动

# duration:滑动操作的持续时间,单位为毫秒

driver.swipe(start_x, start_y, end_x, end_y, duration=None)

```

小结:距离相同,持续时间越长,惯性越小

4.2、scroll滑动事件

```python

# 从一个元素滑动到另外一个元素,直到页面自动停止(有惯性)

# 从'存储'滑动到'更多'

button1 = driver.find_element_by_xpath("//*[@text='存储']")

button2 = driver.find_element_by_xpath("//*[@text='更多']")

driver.scroll(button1, button2)

```

4.3、drag_and_drop拖拽事件

```python

# 从一个元素滑动到另外一个元素,第二个元素替代第一个元素原本屏幕上的位置(没有惯性)

# 从'存储'拖拽到'更多'

button1 = driver.find_element_by_xpath("//*[@text='存储']")

button2 = driver.find_element_by_xpath("//*[@text='更多']")

driver.drag_and_drop(button1, button2)

```

4.4、滑动和拖拽事件如何选择

滑动和拖拽无非就是考虑是否有“惯性”,以及传递的参数是“元素”还是“坐标”

可以分为一下四种情况:

4.4.1. 有惯性,传入元素

选择 scroll

4.4.2. 无惯性,传入元素

选择 drag_and_drop

4.4.3. 有惯性,传入坐标

选择swipe,设置较短的duration时间

4.4.4. 无惯性,传入坐标

选择swipe,设置较长的duration时间

5、高级手势TouchAction

应用场景:

TouchAction可以实现一些针对手势的操作,比如滑动、长按、拖动等。我们可以将这些基本手势组合成一个相对复杂的手势。比如,手机的手势解锁。

使用步骤:

- 创建TouchAction对象

- 通过对象调用想执行的手势

- 通过perform()执行动作

5.1、轻敲操作--tap

关键方法:tap

参数:

- 元素

- 坐标

- 轻敲次数

```python

# 确定要轻敲的元素

button = driver.find_element_by_xpath("//*[@text='xxx']")

# 1、创建TouchAction对象

touch_action = TouchAction(driver)

# 2、调用想要执行的动作

touch_action = touch_action.tap(button)

# 3、使用perform()执行动作

touch_action.perform()

# 代码简写

button = driver.find_element_by_xpath("//*[@text='xxx']")

TouchAction(driver).tap(button).perform()

```

5.2、按下和抬起操作--press\release

5.2.1、按下--press

```python

# 模拟手指对元素或坐标的按下操作

# 参数:

# el:元素

# x:x坐标

# y:y坐标

TouchAction(driver).press(el=None, x=None, y=None).perform()

```

5.2.2、抬起--release

```python

# 模拟手指对元素或坐标的抬起操作

TouchAction(driver).release().perform()

```

```python

# 在(111,222)坐标处先按下,再抬起操作

TouchAction(driver).press(x=111, y=222).release().perform()

```

5.3、等待操作--wait

```python

# 模拟手指暂停操作

# 参数:ms->暂停的毫秒数

TouchAction(driver).wait(ms=1000).perform()

```

```python

# 点击坐标(100, 200),2秒后,按下(300,400)位置,暂停2s后抬起

TouchAction(driver).tap(x=100, y=200).perform()

time.sleep(2)

TouchAction(driver).press(x=300, y=400).wait(ms=2000).release().perform()

```

5.4、长按操作--long_press

```python

# 模拟手指对元素或坐标的长按操作

# 参数:

# el:元素

# x:x坐标

# y:y坐标

# duration:长按时间,单位毫秒

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

```

```python

# 点击坐标(100, 200),2秒后,按下(300,400)位置,暂停2s后抬起

TouchAction(driver).tap(x=100, y=200).perform()

time.sleep(2)

TouchAction(driver).long_press(x=300, y=400, duration=2000).perform()

```

5.5、移动操作--move_to

```python

# 模拟手指对元素或坐标的移动操作

# 参数:

# el:元素

# x:x坐标

# y:y坐标

TouchAction(driver).move_to(el=None, x=None, y=None).perform()

```

6、手机操作API

6.1、获取手机屏幕分辨率

```python

# 获取手机分辨率

# 返回值为字典,{'heigth': 100, 'width': 200}

driver.get_window_size()

```

6.2、手机截图

```python

# 可以在指定位置保存屏幕截图

# 参数:文件的路径

# 如果直接写文件名,则会在默认保存在当前路径下

get_screenshot_as_file(filename)

```

6.3、获取当前网络

```python

# 获取手机网络

print(driver.network_connection)

```

```python

# 设置手机网络

# 参数:connectionType 网络类型

# 0 --> None

# 1 --> Airplane Mode

# 0 --> Wifi only

# 0 --> Data only

# 0 --> All network on

driver.set_network_connection(connectionType)

```

6.4、发送键到设备

```python

# 发送键到设备

# 参数:

# keycode:发送给设备的关键代码,可百度搜索“Android keycode”

# metastate:关于被发送的关键代码的元信息,一般为默认值

driver.press_keycode(keycode, metastate=None)

```

6.5、操作手机通知栏

```python

# 打开手机通知栏

# appium未提供关闭通知栏的api,需要模拟用户实际操作关闭通知栏,如:手指往上滑、点击返回键

driver.open_notifications()

```

```python

# 打开通知栏,两秒后关闭通知栏

driver.open_notifications()

time.sleep(2)

driver.press_keycode(4)

常用函数

1.获取设备包名、活动名、设备名函数

def get_appPackage(apk):

    """

   :param apk:apk的存放路径,例如:D:/apk/1434839438204272641-**Shop-v1.0.0.960-testus-debug-autel.apk

    注意:如果apk名称中是带有空格的,直接复制apk名称会无法找到对应的文件,因此需要检查名称并根据需要修改apk命名

    实际返回的包名是代码中定义的,与apk叫什么名字无关

    :return: 返回appPackage

    """

    appPackage_order = "aapt dump badging " + apk

    LOG.info("获取appPackage的执行命令为:{}".format(appPackage_order))

re_text= subprocess.Popen(appPackage_order,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE).stdout.read()

    #LOG.info("获取到的设备包名及活动名为:{}".format(re_text))

    appPackage_pattern = re.compile(r"package: name='(.*?)'")

    appPackage = appPackage_pattern.findall(re_text.decode('utf-8'))[0]

    LOG.info("获取到的包名为:{}".format(appPackage))

    return appPackage

2.获取appActivity的函数

def get_appActivity(apk):

    """

    :param apk: apk名称,同上述appPackage中所述

    :return: 返回appActivity

    """

    appActivity_order = "aapt dump badging " + apk

    LOG.info("获取appActivity_order的执行命令为:{}".format(appActivity_order))

    re_text = subprocess.Popen(appActivity_order, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.read()

    #LOG.info("获取到的设备包名及活动名为:{}".format(re_text))

    appActivity_pattern = re.compile(r"launchable-activity: name='(.*?)'")

    appActivity = appActivity_pattern.findall(re_text.decode('utf-8'))[0]

    LOG.info("获取到的活动名为:{}".format(appActivity))

    return appActivity

3.获取deviceName函数

def get_deviceName():

    deviceName_order = "adb devices -l"

    re_text = subprocess.Popen(deviceName_order, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.read()

    deviceName_pattern = re.compile(r"model:(.*?) ")

    deviceName = deviceName_pattern.findall(re_text.decode('utf-8'))[0]

    LOG.info("获取到的设备名称为:{}".format(deviceName))

    return deviceName

4.获取安卓设备系统版本号函数

def get_android_version():

    version_order = "adb shell getprop ro.build.version.release"

    """这种方式获取到的内容都是字节类型,因此需要通过decode方法解码为字符串

    """

    re_text = subprocess.Popen(version_order, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.read()

    version = re_text.decode('utf-8').split('\r')[0]

    LOG.info("安卓设备的版本号为:{}".format(version))

    return version

5.处理授权弹框函数

def deal_login_permission(driver,number):

    """

    :param driver:  webdriver

    :param number: 根据第一次安装应用时弹出的确认授权框的数量传值

    :return:

    """

    for i in range(number):

        auth = ("xpath", "//*[@text='允许']")

        try:

            WebDriverWait(driver, 3, 0.5).until(EC.presence_of_element_located(auth)).click()

        except:

            LOG.info("登录时未弹出确认授权信息")

6.获取弹框中的文本

def toast_exist(driver, toastmessage):

    loc = '//*[contains(@text,"{}")]'.format(toastmessage)

    # 等待的时候,要用元素存在的条件。不能用元素可见的条件。visibility_of_element_located对toast的处理并不支持,会直接报错

    try:

        WebDriverWait(driver, 10, 0.01).until(EC.presence_of_element_located((MobileBy.XPATH, loc)))

        # 上限10秒就够了,确认toast在页面上存在的时候大概是多久,一般这种提示消息时间很短,如果都没有0.5秒,你去间隔0.5,可能消失了,你还只留在这。

        toast_text = driver.find_element_by_xpath(loc).text

        LOG.info("toast提示消息为:{}".format(toast_text))

        return toast_text

    except:

        LOG.info("没有找到匹配的toast!!!!")

7.处理页面滑动

def get_size(self):

    """获取屏幕分辨率."""

    rect = self.driver.get_window_size()

    return rect['width'], rect['height']

def swipe_by_ratio(self, start_x, start_y, direction, ratio, duration=None):

        """

        按照屏幕比例的滑动.

        :param start_x: 起始横坐标

        :param start_y: 起始纵坐标

        :param direction: 滑动方向,只支持'up'、'down'、'left'、'right'四种方向参数

        :param ratio: 滑动距离与屏幕的比例,范围0到1

        :param duration: 滑动时间,单位ms

        :return:

        """

        direction_list = ['up', 'down', 'left', 'right']

        if direction not in direction_list:

            LOG.info('滑动方向%s不支持', direction)

        width, height = self.get_size()

        def swipe_up():

            """上滑."""

            end_y = start_y - ratio * height

            if end_y < 0:

                LOG.info('上滑距离过大')

                return False

            else:

                self.driver.swipe(start_x, start_y, start_x, end_y, duration)

            return True

        def swipe_down():

            """下滑."""

            end_y = start_y + ratio * height

            if end_y > height:

                LOG.info('下滑距离过大')

                return False

            else:

                self.driver.swipe(start_x, start_y, start_x, end_y, duration)

            return True

        def swipe_left():

            """左滑."""

            end_x = start_x - ratio * width

            if end_x < 0:

                LOG.info('左滑距离过大')

                return False

            else:

                self.driver.swipe(start_x, start_y, end_x, start_y, duration)

            return True

        def swipe_right():

            """右滑."""

            end_x = start_x + ratio * width

            if end_x > width:

                LOG.info('右滑距离过大')

                return False

            else:

                self.driver.swipe(start_x, start_y, end_x, start_y, duration)

            return True

        swipe_dict = {'up': swipe_up, 'down': swipe_down, 'left': swipe_left,

                      'right': swipe_right}

        return swipe_dict[direction]()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值