乐于分享
好东西不私藏

App 自动化高级定位技巧(XPath + UiAutomator)(十二)

App 自动化高级定位技巧(XPath + UiAutomator)(十二)

一、XPath 定位进阶(核心:节点关系定位)

XPath 是 XML 路径语言,可通过元素的层级、属性、关系定位 App 界面元素(Android 界面本质是 XML 结构)。核心特点:路径灵活、支持层级关联、节点关系遍历

1. XPath 基础语法回顾

符号 / 语法
含义
示例
//
相对路径(从当前页面任意位置开始)
//*[@resource-id='xxx']
/
绝对子路径(直接子节点)
父节点/子节点
*
匹配任意节点(所有元素)
//*

(页面所有元素)
@
选取元素的属性
@resource-id

/@text/@class
[]
索引 / 条件筛选(索引从 1 开始!)
TextView[2]

(第 2 个 TextView)
..
定位当前节点的父节点
子节点/..

(子找父)

2. 核心层级定位场景(实战核心)

(1)父节点定位子节点(最常用)

场景:父元素属性唯一(如 resource-id),子元素无唯一属性但位置 / 类型确定。
逻辑:先定位唯一父节点 → 再通过子节点的类型 / 索引定位。
语法://父节点属性/子节点类型[索引]
实战示例:
//*[@resource-id='com.xueqiu.android:id/title_container']/android.widget.TextView[2]
解读:
① //*[@resource-id=’com.xueqiu.android:id/title_container’]:找到页面上 resource-id 为title_container的所有元素(父节点);
② /android.widget.TextView[2]:在该父节点的直接子节点中,选取第 2 个 class 为android.widget.TextView的元素

(2)子节点定位父节点

场景:子元素易定位(如 text 唯一),但父元素无唯一属性,需通过子找父。
语法:子节点/..(..表示当前节点的父节点)
实战示例:
//*[@resource-id='com.xueqiu.android:id/title_container']/android.widget.TextView[2]/..
解读:先找到上述子节点 → 通过/..定位到该子节点的直接父节点(即title_container)。
扩展:如需找爷爷节点,可叠加/.. → 子节点/../../..(3 个/..表示向上找 3 级父节点)。

(3)子节点定位兄弟节点

场景:两个元素为同一父节点下的兄弟,其中一个易定位,需找另一个。
逻辑:子节点→父节点→目标兄弟节点
语法:子节点/../兄弟节点类型[索引]
示例:找到 “09988” 的兄弟节点 “涨跌幅”
//*[@text='09988']/../android.widget.TextView[3]

(4)跨级定位(爷爷→孙子 / 任意后代)

场景:目标元素与祖先元素有明确层级,但非直接父子。
核心:通过/逐级向下,或//跳过中间层级(匹配任意后代)。
实战案例:验证 “09988” 和 “73.25” 的关联性(是否属于同一父容器)
//*[@text='09988']/../../..//*[@resource-id='com.xueqiu.android:id/current_price']
解读:
① //*[@text=’09988′]:定位文本为 “09988” 的元素(孙子节点);
② /../../..:向上找 3 级父节点(找到两者的共同祖先);
③ //*[@resource-id=’current_price’]:在共同祖先的所有后代中,找到价格元素(73.25);
④ 作用:验证两个元素是否属于同一模块(若能定位到,说明关联性成立)。

3. XPath 定位注意事项

索引从1开始(区别于编程的 0 索引);
优先用resource-id/text等稳定属性,避免仅用 class + 索引(易因界面变化失效);
层级不宜过长(如/../../../../),否则易因界面结构变动导致定位失败。

二、UiAutomator 定位(Android 专属,效率更高)

UiAutomator 是 Android 官方提供的 UI 自动化测试框架,Appium 封装了该接口,定位效率高于 XPath(直接调用 Android 底层 API),支持更灵活的组合定位。

1. 基础用法

Appium 中调用语法(Python 示例):
from appium.webdriver.common.appiumby import AppiumBy# 核心格式:通过By.ANDROID_UIAUTOMATOR传入UiAutomator表达式driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'UiAutomator表达式').click()

2. 单独定位(单一属性匹配)

适用于元素有唯一属性的场景,语法简洁,优先级:resourceId > text > className > description。
定位方式
语法
实战示例
通过 resource-id
new UiSelector().resourceId("完整id") new UiSelector().resourceId("com.xueqiu.android:id/login_account")
通过 className
new UiSelector().className("类名") new UiSelector().className("android.widget.TextView")
通过 content-desc
new UiSelector().description("desc文本") new UiSelector().description("返回")
精准文本
new UiSelector().text("完整文本") new UiSelector().text("我的")
模糊文本(包含)
new UiSelector().textContains("文本片段") new UiSelector().textContains("帐号密码")
文本开头
new UiSelector().textStartsWith("开头文本") new UiSelector().textStartsWith("登录")
正则匹配文本
new UiSelector().textMatches("正则表达式") new UiSelector().textMatches("^[0-9]{5}$")

(匹配 5 位数字)
实战代码示例:
# 1. 点击“我的”(精准文本)driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().text("我的")').click()# 2. 输入账号(通过resource-id)driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,                    'new UiSelector().resourceId("com.xueqiu.android:id/login_account")').send_keys("long")# 3. 模糊匹配“帐号密码”driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,                    'new UiSelector().textContains("帐号密码")').click()

3. 组合定位(多属性 / 层级关联,解决元素重复问题)

适用于单一属性无法定位(如多个 “我的” 按钮),需通过多属性 / 层级缩小范围。

(1)多属性组合(id+text / 类名 + text)

场景:页面有多个相同 text 的元素,需结合 resource-id 区分。
语法:resourceId(“id”).text(“文本”)(多个属性直接拼接)
实战示例:定位雪球 App 的 “我的” 标签(避免其他 “我的” 干扰)
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,                    'new UiSelector().resourceId("com.xueqiu.android:id/tab_name").text("我的")').click()

(2)父子关系定位(childSelector)

场景:子元素无唯一属性,但父元素易定位(如父节点有唯一 resource-id)。
语法:父元素定位.childSelector(子元素定位)
实战示例:通过父容器title_container找 “股票” 文本子元素
# 注意:原示例中test('股票')是笔误,应为text('股票')driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,                    'new UiSelector().resourceId("com.xueqiu.android:id/title_container").childSelector(text("股票"))').click()

(3)兄弟关系定位(fromParent)

场景:目标元素难定位,但同属一个父节点的兄弟元素易定位。
逻辑:先定位兄弟元素 → 通过fromParent找到同一父节点下的目标元素。
语法:兄弟元素定位.fromParent(目标元素定位)
实战示例:通过title_container兄弟元素找 “用户” 文本元素
# 注意:原示例中test('用户')是笔误,应为text('用户')driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,                    'new UiSelector().resourceId("com.xueqiu.android:id/title_container").fromParent(text("用户"))').click()

(4)滚动查找元素(UiScrollable)

场景:目标元素在屏幕外,需滚动页面才能显示(如列表、长页面)。
核心:UiScrollable(滚动容器) + scrollIntoView(滚动到目标元素可见)
语法:
new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("查找的文本").instance(0))
实战示例:滚动查找 “设置” 选项
# Python代码示例scroll_expression = '''new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("设置").instance(0))'''driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, scroll_expression).click()
关键参数解读:
scrollable(true):筛选可滚动的容器;
instance(0):选取第 1 个可滚动容器(页面通常只有 1 个主滚动容器);
scrollIntoView:滚动直到目标元素可见。

三、XPath vs UiAutomator 对比与选型建议

维度
XPath
UiAutomator
效率
较低(解析 XML 遍历)
较高(Android 底层 API)
灵活性
高(支持任意层级 / 跨级)
高(组合定位更丰富)
学习成本
低(路径语法简单)
中(需熟悉 UiSelector 语法)
稳定性
中(易受层级变动影响)
高(属性组合更稳定)
适用场景
快速定位、简单层级关联
复杂场景(滚动、兄弟 / 父子定位、重复元素)
选型原则:
简单场景(单一属性 / 父找子):优先 XPath(语法简洁);
复杂场景(滚动、重复元素、兄弟定位):优先 UiAutomator(效率 + 稳定性更高);
跨平台(Android+iOS):优先 XPath(UiAutomator 仅支持 Android)。

总结

XPath 核心:通过/////..实现层级遍历,利用@属性+[索引]定位,核心解决 “节点上下层级关联” 问题(如子找父、跨级找后代);
UiAutomator 核心:支持单一属性、多属性组合、父子 / 兄弟关联、滚动查找,是 Android 端更高效的定位方式;
实战关键:优先用稳定属性(resource-id > text > class),减少层级依赖,避免因界面改版导致定位失效。
本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » App 自动化高级定位技巧(XPath + UiAutomator)(十二)

猜你喜欢

  • 暂无文章