|
5 rokov pred | |
---|---|---|
.. | ||
README.md | 5 rokov pred | |
__init__.py | 5 rokov pred |
用这个插件前,要先了解一些XPath知识。 好在网上这方便的资料很多。下面列举一些
dump_hierarchy
接口,获取到当前的UI界面(一个很丰富的XML)。lxml
库解析,寻找匹配的xpath,然后使用click指令完后操作弹窗监控原理
通过hierarchy可以知道界面上的所有元素信息(包括弹窗和要点击的按钮)。
假设有 跳过
, 知道了
这两个弹窗按钮。需要点击的按钮名是 播放
跳过
, 知道了
这两个按钮,如果有就点击,然后回到第一步播放
按钮, 有就点击,结束。没有找到在回到第一步,一直执行到查找次数超标。pip install -U --pre uiautomator2
目前该插件已经内置到uiautomator2中了,所以不需要plugin注册了。
import uiautomator2 as u2
def main():
d = u2.connect()
d.app_start("com.netease.cloudmusic", stop=True)
# watchers 监控弹窗
d.xpath.when("跳过").click()
d.xpath.when("知道了").click()
# steps
d.xpath("//*[@text='私人FM']/../android.widget.ImageView").click()
d.xpath("下一首").click()
# 监控弹窗2s钟,时间可能大于2s
d.xpath.sleep_watch(2)
d.xpath("转到上一层级").click()
d.xpath("转到上一层级").click(watch=False) # click without trigger watch
d.xpath("转到上一层级").click(timeout=5.0) # wait timeout 5s
# 一直在后台监控(目前每隔4s检查一次),暂时还没提供暂停的方法
d.xpath.watch_background()
别名定义,感觉这种写法有点类似selenium中的PageObjects
下面的代码为了方便就不写
import
了
# 这里是Python3的写法,python2的string定义需要改成 u"菜单" 注意前的这个u
d.xpath.global_set("alias", {
"菜单": "@com.netease.cloudmusic:id/qh", # TODO(ssx): maybe we can support P("@com.netease.cloudmusic:id/qh", wait_timeout=2) someday
"设置": "//android.widget.TextView[@text='设置']",
})
# 这里需要 $ 开头
d.xpath("$菜单").click() # 等价于 d.xpath()
d.xpath("$设置").click()
# alias_strict 设置项
d.xpath("$返回").click() # 等价于 d.xpath("返回").click(),因为返回没有预先在alias中定义
d.xpath.global_set("alias_strict", True) # 默认 False
d.xpath("$返回").click() # 在这里会直接跑出XPathError异常
遍历操作
for el in d.xpath('//android.widget.EditText'):
print("rect:", el.rect) # output tuple: (x, y, width, height)
print("center:", el.center())
el.click() # click operation
print(el.elem) # 输出lxml解析出来的Node
为了写起脚本来更快,我们自定义了一些简化的xpath规则
规则1
//
开头代表原生xpath
规则2
@
开头代表resourceId定位
@smartisanos:id/right_container
相当于
//*[@resource-id="smartisanos:id/right_container"]
规则3
^
开头代表正则表达式
^.*道了
相当于 //*[re:match(text(), '^.*道了')]
规则4
灵感来自SQL like
知道%
匹配知道
开始的文本, 相当于 //*[starts-with(text(), '知道')]
%知道
匹配知道
结束的文本,相当于 //*[ends-with(text(), '知道')]
%知道%
匹配包含知道
的文本,相当于 //*[contains(text(), '知道')]
规则5
另外来自Selenium PageObjects
$知道
匹配 通过d.xpath.global_set("alias", dict)
dict字典中的内容, 如果不存在将使用知道
来匹配
规则 Last
会匹配text 和 description字段
如 搜索
相当于 XPath //*[@text="搜索" or @content-desc="搜索"]
$
字符,这个字符在XML中是不合法的,所以全部替换成了-
# 所有元素
//*
# resource-id包含login字符
//*[contains(@resource-id, 'login')]
# 按钮包含账号或帐号
//android.widget.Button[contains(@text, '账号') or contains(@text, '帐号')]
# 所有ImageView中的第二个
(//android.widget.ImageView)[2]
# 所有ImageView中的最后一个
(//android.widget.ImageView)[last()]
# className包含ImageView
//*[contains(name(), "ImageView")]
如有其他资料,欢迎提Issues补充