Appium(十):元素定位(加强版)

时间:2022-06-16 06:41:59

1. 元素定位

写完上一篇元素定位的博客,发现实用性基本为零。这几天真的烦死我了,一直在找资料,还去看了一遍appium官网文档。最后结合着selenium的定位方法,测试出几种可行的元素定位方法。

1.1 层级定位

什么是层级定位呢?

在很多的自动化中如果只是靠简单的定位是没有办法完成自动化的。有的元素的id、name、className都是一样的,xpath定位效率低下,并且在appium中,可以使用的属性非常少,这个时候我们就需要使用层级定位了。

Appium(十):元素定位(加强版)

 

Appium(十):元素定位(加强版)

我们可以看到,QQ天气和微视的class都是相同的, 接下来我们用代码试一试。

# coding:utf-8
from appium import webdriver
from time import sleep

# 初始化
desired_caps = {}
# 使用哪种移动平台
desired_caps[platformName] = Android
# Android版本
desired_caps[platformVersion] = 5.1.1
#使用adb devices -l 查询,当有多台设备时,需要声明
desired_caps[deviceName] = 127.0.0.1:62001
#包名
desired_caps[appPackage] = com.tencent.mobileqq
#界面名
desired_caps[appActivity] = .activity.SplashActivity
#不清除数据
desired_caps[noReset] = True
# 启动服务
driver = webdriver.Remote(http://127.0.0.1:4723/wd/hub, desired_caps)

driver.find_element_by_id(com.tencent.mobileqq:id/recent_chat_list)
driver.find_element_by_class_name(android.widget.LinearLayout).click()

#退出driver
driver.quit()

运行后,我们会发现代码执行了,也没有报错,但是也不会点击,这是为什么呢。这就牵扯到另外一个定位问题,就是下面要说的List定位。

1.2 List定位

list顾名思义就是一个列表。当我们想要获取一个元素,但是却发现符合条件的元素有很多个的时候,我们就可以选择List定位了。因为元素的个数的不确定性,所以我们的方法也需要变成复数,所以这里需要用复数,所以在我们定位时我们不能够接着用find_element_by_class_name等等定位方式了,我们需要用他的复数形式find_elements_by_class_name,所有的定位方式都一样需要采用复数加s。

driver.find_element_by_id(com.tencent.mobileqq:id/recent_chat_list)
driver.find_elements_by_class_name(android.widget.LinearLayout)

上面的代码最后选择的是com.tencent.mobileqq:id/recent_chat_list父节点下所有android.widget.LinearLayout子节点,现在我们如何去操作这些子节点呢,有两种方法:

1、List是一个集合,这里定位的所有子节点最后就成了个list,如果我们要访问这个list里面的某一个元素我们可以像访问数组中的数据一样通过下标访问。最后的代码就是下面这个样子:

driver.find_element_by_id(com.tencent.mobileqq:id/recent_chat_list)
elements = driver.find_elements_by_class_name(android.widget.LinearLayout)
elements[0].click()
#让我们更好的观看效果
sleep(5)

2、如果你要访问List里面的元素,那么我们是否可以通过for循环语句来依次访问呢?这个在自动化中会经常用到。下面你可以通过这个思路自己去实战一下,看能否达到预期效果。下面看我的代码:

for element in elements:
    sleep(2)
    element.click()

看上面的代码,我们通过循环去访问这个list里面的每一个元素,因为每次循环得到的都是其中一个元素,那么我们只需要在这个元素上加上你想要的操作即可,所以我们这里可以直接点击进去。

但是我们会发现,在进入到第一个标签后,系统就会报错,为什么呢?因为界面跳转到微视里面了,而里面没有android.widget.LinearLayout元素,所以就会因为找不到元素而报错。

所以这种方法的使用有限制,只能在那种不需要界面跳转的情况下使用。

1.3 xpath定位(补充)

xpath定位可以分为两种,绝对定位和相对定位。

但是我们会发现,绝对定位的路径非常的长,后期代码也比较麻烦,开发中几乎不可能使用。(老大看到了就叼你)

相对路径就是非常好用的一种了,不断简短,后期维护代码也方便。

以下就是相对路径的使用了:

我使用的是taptap软件来进行测试,大家可以换成其他软件。

(1) 如果当前class内存在唯一text可以定位元素,直接用当前class text,例如:

# coding:utf-8
from appium import webdriver
from time import sleep
from appium.webdriver.common.touch_action import TouchAction

# 初始化
desired_caps = {}
# 使用哪种移动平台
desired_caps[platformName] = Android
# Android版本
desired_caps[platformVersion] = 5.1.1
#使用adb devices -l 查询,当有多台设备时,需要声明
desired_caps[deviceName] = 127.0.0.1:62001
#包名
desired_caps[appPackage] = com.taptap
#界面名
desired_caps[appActivity] = com.play.taptap.ui.MainAct
#不清除数据
desired_caps[noReset] = True
#启动服务
driver = webdriver.Remote(http://127.0.0.1:4723/wd/hub, desired_caps)

element = driver.find_element_by_xpath(//android.widget.TextView[@text="排行"])
TouchAction(driver).tap(element).perform()

sleep(5)

#退出driver
driver.quit()

(2) 如果当前class内,resource-id、text两者能唯一定位元素,直接用当前class 两者并列,例如:

element1 = driver.find_element_by_xpath(//android.widget.TextView[@text="我的游戏"])
TouchAction(driver).tap(element1).perform()
sleep(2)
element2 = driver.find_element_by_xpath(//android.widget.TextView[@resource-id="com.taptap:id/app_title" and @text="第五人格T"])
TouchAction(driver).tap(element2).perform()
sleep(5)

(3) 如果当前class内,text中的文本内容不是完全符合,但能匹配部分内容,可用当前class 模糊定位contains,例如:

element = driver.find_element_by_xpath(//android.widget.TextView[contains(@text,"我的")])
TouchAction(driver).tap(element).perform()
sleep(2)

还有很多类似的定位方法,可以查看我找到的一个大佬写的博客:https://blog.csdn.net/Dome_/article/details/80638245

总体上就这样了,以后如果找到更好的方法,就再更新一章。