uiautomator的xpath选择器

官方的uiautomator是没有xpath选择器的,这里介绍一种利用xpath查找控件的方法。

首要的问题是,如何获取界面元素根节点。

先来看UiDevice的这段代码:

public void dumpWindowHierarchy(String fileName) {
        AccessibilityNodeInfo root =
                getAutomatorBridge().getQueryController().getAccessibilityRootNode();
        if(root != null) {
            AccessibilityNodeInfoDumper.dumpWindowToFile(
                    root, new File(new File(Environment.getDataDirectory(),
                            "local/tmp"), fileName));
        }
    }

root即是所要获取的根节点。

接下来看getAutomatorBridge()干了什么:

    UiAutomatorBridge getAutomatorBridge() {
        return mUiAutomationBridge;
    }

很简单,直接返回了一个成员变量。我们看看这个变量是啥:

    // provides access the {@link QueryController} and {@link InteractionController}
    private final UiAutomatorBridge mUiAutomationBridge;

getAutomatorBridge()方法是包内可见的,也就是说在代码中不能直接调用。就算定义了一个com.android.uiautomator.core包内的类,也没法调用,因为android.jar并没有对外暴露这个API.

不过可以通过反射的方式,获取UiDevice实例对象的getAutomatorBridge方法,再行调用就可以了。

另外,这个方法返回的是UiAutomatorBridge类型,这个类型也是包内可见,没问题,再用反射就是。

就这样一层一层剥,终于获取到AccessibilityNodeInfo类型的根节点,代码如下:

        UiDevice dev = UiDevice.getInstance();
        Method getAutomatorBridge = UiDevice.class.getDeclaredMethod("getAutomatorBridge");
        Object bridge = getAutomatorBridge.invoke(dev);

        Class<?> UiAutomatorBridge_class = dev.getClass().getClassLoader().loadClass("com.android.uiautomator.core.UiAutomatorBridge");
        Method getQueryController = UiAutomatorBridge_class.getDeclaredMethod("getQueryController");
        Object qc = getQueryController.invoke(bridge);

        Class<?> QueryController_class = dev.getClass().getClassLoader().loadClass("com.android.uiautomator.core.QueryController");
        Method getAccessibilityRootNode = QueryController_class.getDeclaredMethod("getAccessibilityRootNode");
        AccessibilityNodeInfo root = (AccessibilityNodeInfo) getAccessibilityRootNode.invoke(qc);

获取界面根节点后,事情就好办了。参见这个类:com.android.uiautomator.core.AccessibilityNodeInfoDumper,它从根节点出发遍历控件树,读取控件属性,并生成对应的XML节点,过程很简单,不贴代码了。

需要注意的是,生成的XML除了根节点,每个节点名称都是node,控件类型则放在class属性中。可以重写这个过程,把class作为XML节点名称,这样就可以利用xpath进行定位了。

XML示例片断如下:

<hierarchy>  <android.widget.FrameLayout instance="0" index="0" text="" resource-id="" package="com.android.settings" content-desc=""     checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false"     long-clickable="false" password="false" selected="false" bounds="[0,0][1080,1920]">  <android.widget.FrameLayout instance="1" index="0" text="" resource-id="miui:id/action_bar_overlay_layout" package="com.android.settings" content-desc=""       checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][1080,1920]">    <android.widget.FrameLayout instance="2" index="0" text="" resource-id="android:id/content" package="com.android.settings" content-desc="" checkable="false" checked="false" clickable="false"       enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][1080,1920]"><!-- 省略 --></hierarchy>

注意这里增加了一个很重要的属性instance,它对应于UiSelector.instance(int),表示同类型节点的深度优先次序编号。

在生成XML遍历控件树时,是以深度优先次序进行的,只要记住遍历过节点每种类型的个数,就能很方便地得到instance属性。

后面就简单了,用xpath定位节点,获取节点的名称和instance属性,就可以利用UiSelector.className(...).instance(...)进行控件定位。

还有一种笨方法,在xpath定位到节点后,一路沿parent向上,直到根节点,并把路径记下来。再从根节点出发,沿路径返回,利用子节点的index属性,通过UiObject.getChild(...)来依次获取子节点,就这样一路向下,直到目标节点。这个方法比较笨,个人觉得它只适合于前一种方法找不到的情况下的一种补充手段。

时间: 2024-10-10 13:46:40

uiautomator的xpath选择器的相关文章

在Scrapy中如何利用Xpath选择器从HTML中提取目标信息(两种方式)

前一阵子我们介绍了如何启动Scrapy项目以及关于Scrapy爬虫的一些小技巧介绍,没来得及上车的小伙伴可以戳这些文章: 手把手教你如何新建scrapy爬虫框架的第一个项目(上) 手把手教你如何新建scrapy爬虫框架的第一个项目(下) 关于Scrapy爬虫项目运行和调试的小技巧(上篇) 关于Scrapy爬虫项目运行和调试的小技巧(下篇) 今天我们将介绍在Scrapy中如何利用Xpath选择器从HTML中提取目标信息.在Scrapy中,其提供了两种数据提取的方式,一种是Xpath选择器,一种是C

xpath选择器使用

简单说,xpath就是选择XML文件中节点的方法. 所谓节点(node),就是XML文件的最小构成单位,一共分成7种. - element(元素节点)- attribute(属性节点)- text (文本节点)- namespace (名称空间节点)- processing-instruction (处理命令节点)- comment (注释节点)- root (根节点) xpath可以用来选择这7种节点.不过,下面的笔记只涉及最常用的第一种element(元素节点),因此可以将下文中的节点和元素

安卓自动化测试,贺晓聪之uiautomator设备和选择器~Python详解

1.设备对象 引入uiautomator,获取设备对象<所谓设备对象可理解为:Android模拟器或者真机> 语法:from uiautomator import device as d d 即为设备对象 1.1.获取设备信息 语法:d.info 返回值: { u'displayRotation': 0, u'displaySizeDpY': 640, u'displaySizeDpX': 360, u'currentPackageName': u'com.android.launcher',

初始scrapy,简单项目创建和CSS选择器,xpath选择器(1)

一 安装 #Linux: pip3 install scrapy #Windows: a. pip3 install wheel b. 下载twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted c. 进入下载目录,执行 pip3 install Twisted?17.1.0?cp35?cp35m?win_amd64.whl d. pip3 install pywin32 e. pip3 install scrapy 二 实验要求 目

CSS/Xpath 选择器 第几个子节点/父节点/兄弟节点

0.参考 1.初始化 In [325]: from scrapy import Selector In [326]: text=""" ...: <div> ...: <a>1a</a> ...: <p>2p</p> ...: <p>3p</p> ...: </div>""" In [327]: sel=Selector(text=text) In [

scrapy xpath选择器多级选择错误

在学习scrapy中用xpath提取网页内容时,有时要先提取出一整个行标签内容,再从行标签里寻找目标内容.出现一个错误. 错误代码: def parse(self, response): sel = scrapy.Selector(response) sel_li = sel.xpath('/html/body/div[2]/div[5]/div[1]/ul/li') for i in sel_li: print(i.xpath('//h5/a/text()').extract()[0]) 结果

XPath和CSS选择器

[译]XPath和CSS选择器 原文:http://ejohn.org/blog/xpath-css-selectors 最近,我做了很多工作来实现一个同时支持XPath和CSS 3的解析器,令我惊讶的是:它们俩在某些方面上非常相似,而在另一些方面上又完全不同.不同的地方有,CSS是用来配合HTML工作的,可以使用#id来根据ID获取元素,以及使用.class来根据class获取元素.这些用XPath实现的话都不会那么简洁,反过来呢,XPath可以使用..来返回到DOM树的上层节点中,还可以使用

jquery 选择器(name,属性,元素)大全

jQuery 选择器大体上可分为:基本选择器.层次选择器.过滤选择器.表单选择器. 其中过滤选择器可以分为:简单过滤选择器.内容过滤选择器.可见性过滤选择器.属性过滤选择器.子元素过滤选择器.表单对象属性过滤选择器.选择器是jQuery最基础的东西,下面向大家介绍jquery+%D1%A1%D4%F1%C6%F7/" target="_blank">jquery 选择器的用法 选择器是jQuery的核心组成部分,因为使用jQuery操作DOM时所做的每件事都和选择器密切

python xpath

提取Item 选择器介绍 我们有很多方法从网站中提取数据.Scrapy 使用一种叫做 XPath selectors的机制,它基于 XPath表达式.如果你想了解更多selectors和其他机制你可以查阅资料http://doc.scrapy.org/topics /selectors.html#topics-selectors  这是一些XPath表达式的例子和他们的含义 /html/head/title: 选择HTML文档<head>元素下面的<title> 标签. /html