1. 元素定位
写完上一篇元素定位的博客,发现实用性基本为零。这几天真的烦死我了,一直在找资料,还去看了一遍appium官网文档。最后结合着selenium的定位方法,测试出几种可行的元素定位方法。
1.1 层级定位
什么是层级定位呢?
在很多的自动化中如果只是靠简单的定位是没有办法完成自动化的。有的元素的id、name、className都是一样的,xpath定位效率低下,并且在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
总体上就这样了,以后如果找到更好的方法,就再更新一章。