通过python调用adb命令实现用元素名称、id、class定位元素

来源:互联网 发布:淘宝签到领金币 编辑:程序博客网 时间:2024/06/06 02:17

在Android自动化测试过程中,使用monkeyrunner可以通过坐标点击某个元素,但缺点是受屏幕分辨率影响,需要随时更改坐标位置。最近有使用了下Appium这个工具,优点是可以通过元素名称、id、class等属性定位,但是需要搭建稍微有点复杂的环境,然后我就想能不能不依赖任何环境,使用纯Python实现通过这几个属性定位,只需要直接执行python脚本就ok?接下来开始着手实现

首先需要Android版本高于4.0,使用这个命令“adb shell uiautomator dump”命令,执行“adb shell uiautomator dump /data/local/tmp/uidump.xml”,然后将该xml文件pull到本地,从里面可以看到手机上当前页面的布局,在note节点下可以找到这些属性:text,resource-id,class,bounds,知道这些内容后就可以使用python对该xml文件解析获取到对应的属性,取出bounds的值,计算出对应元素区域的中心坐标,接着使用adb shell input tap 命令就可以点击该坐标,如果有相同的属性值,那就需要得到一个坐标点的列表,以应用“1号店“为例,在桌面上通过应用名称“1号店”,点击进入应用,然后点击“手机充值”,截图如下:






用python简单实现:

[python] view plain copy
  1. #coding=utf-8  
  2.   
  3. import tempfile  
  4. import os  
  5. import re  
  6. import time  
  7. import xml.etree.cElementTree as ET  
  8.   
  9. class Element(object):  
  10.     """ 
  11.     通过元素定位,需要Android 4.0以上 
  12.     """  
  13.     def __init__(self):  
  14.         """ 
  15.         初始化,获取系统临时文件存储目录,定义匹配数字模式 
  16.         """  
  17.         self.tempFile = tempfile.gettempdir()  
  18.         self.pattern = re.compile(r"\d+")  
  19.   
  20.     def __uidump(self):  
  21.         """ 
  22.         获取当前Activity控件树 
  23.         """  
  24.         os.popen("adb shell uiautomator dump /data/local/tmp/uidump.xml")  
  25.         os.popen("adb pull /data/local/tmp/uidump.xml " + self.tempFile)  
  26.   
  27.     def __element(self, attrib, name):  
  28.         """ 
  29.         同属性单个元素,返回单个坐标元组 
  30.         """  
  31.         self.__uidump()  
  32.         tree = ET.ElementTree(file=self.tempFile + "\\uidump.xml")  
  33.         treeIter = tree.iter(tag="node")  
  34.         for elem in treeIter:  
  35.             if elem.attrib[attrib] == name:  
  36.                 bounds = elem.attrib["bounds"]  
  37.                 coord = self.pattern.findall(bounds)  
  38.                 Xpoint = (int(coord[2]) - int(coord[0])) / 2.0 + int(coord[0])  
  39.                 Ypoint = (int(coord[3]) - int(coord[1])) / 2.0 + int(coord[1])  
  40.   
  41.                 return Xpoint, Ypoint  
  42.   
  43.   
  44.     def __elements(self, attrib, name):  
  45.         """ 
  46.         同属性多个元素,返回坐标元组列表 
  47.         """  
  48.         list = []  
  49.         self.__uidump()  
  50.         tree = ET.ElementTree(file=self.tempFile + "\\uidump.xml")  
  51.         treeIter = tree.iter(tag="node")  
  52.         for elem in treeIter:  
  53.             if elem.attrib[attrib] == name:  
  54.                 bounds = elem.attrib["bounds"]  
  55.                 coord = self.pattern.findall(bounds)  
  56.                 Xpoint = (int(coord[2]) - int(coord[0])) / 2.0 + int(coord[0])  
  57.                 Ypoint = (int(coord[3]) - int(coord[1])) / 2.0 + int(coord[1])  
  58.                 list.append((Xpoint, Ypoint))  
  59.         return list  
  60.   
  61.     def findElementByName(self, name):  
  62.         """ 
  63.         通过元素名称定位 
  64.         usage: findElementByName(u"设置") 
  65.         """  
  66.         return self.__element("text", name)  
  67.   
  68.     def findElementsByName(self, name):  
  69.         return self.__elements("text", name)  
  70.   
  71.     def findElementByClass(self, className):  
  72.         """ 
  73.         通过元素类名定位 
  74.         usage: findElementByClass("android.widget.TextView") 
  75.         """  
  76.         return self.__element("class", className)  
  77.   
  78.     def findElementsByClass(self, className):  
  79.         return self.__elements("class", className)  
  80.   
  81.     def findElementById(self, id):  
  82.         """ 
  83.         通过元素的resource-id定位 
  84.         usage: findElementsById("com.android.deskclock:id/imageview") 
  85.         """  
  86.         return self.__element("resource-id",id)  
  87.   
  88.     def findElementsById(self, id):  
  89.         return self.__elements("resource-id",id)  
  90.   
  91. class Event(object):  
  92.     def __init__(self):  
  93.         os.popen("adb wait-for-device ")  
  94.   
  95.     def touch(self, dx, dy):  
  96.         """ 
  97.         触摸事件 
  98.         usage: touch(500, 500) 
  99.         """  
  100.         os.popen("adb shell input tap " + str(dx) + " " + str(dy))  
  101.         time.sleep(0.5)  
  102.   
  103. def test():  
  104.     element = Element()  
  105.     evevt = Event()  
  106.   
  107.     e1 = element.findElementByName(u"1号店")  
  108.     evevt.touch(e1[0], e1[1])  
  109.     time.sleep(1)  
  110.   
  111.     e2 = element.findElementByName(u"手机充值")  
  112.     evevt.touch(e2[0], e2[1])  

这是一个简单的思路,使用的前提是需要开启view server,否则无法获取到uidump.xml这个文件。另外程序运行的会有点慢,可以有优化的方法。

另外如果属性值相同,使用elements,返回的是含坐标元组的列表,如何使用,这里就不讲了。


该文转自:http://blog.csdn.net/gb112211/article/details/33730221

原创粉丝点击