appium,元素定位和元素操作,使用uiautomatorviewer
###
定位方式
定位说三种定位:id,class,xpath
###
操作说3种,点击,输入,获取元素值,
###
代码示例:
from appium import webdriver import time import unittest class Test_Demo(unittest.TestCase): def setUp(self): desired_caps={} desired_caps['platformName']='Android' desired_caps['platformVersion']='6.0' desired_caps['deviceName']='emulator-5554' desired_caps['noReset']='true' # 使用这个,就会记住上一次你的点击记录, desired_caps['appPackage']='com.tencent.news' desired_caps['appActivity']='com.tencent.news.activity.SplashActivity' desired_caps['dontStopAppOnReset']='true' self.driver=webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps) time.sleep(8) def tearDown(self): pass # driver.quit() #退出app def test_search_demo(self): self.driver.find_element_by_id("com.tencent.news:id/home_channel_search_box").click() self.driver.find_element_by_class_name("android.widget.EditText").send_keys("股票期权") self.driver.find_element_by_xpath("//*[@resource-id='com.tencent.news:id/search_history_title']").click() self.driver.implicitly_wait(5) text_ele = self.driver.find_elements_by_id("com.tencent.news:id/title_text") for item in text_ele: print(item.text) # print("text", text_ele) if __name__ == '__main__': unittest.main()
###
代码解释:
注意1,desired_caps['noReset']='true' # 使用这个,就会记住上一次你的点击记录,比如同意协议,不进行更新,这样的弹框选择
注意2,desired_caps['dontStopAppOnReset']='true',加上这个,就不用每次都重新启动app了,这样会大大的提高调试代码的效率,很重要,
注意3,self.driver.implicitly_wait(5),隐式等待,这个很重要,有很多时候你明明是定位对了,但是就是报错找不到元素,那就试试等待,一般会是这个问题,
注意4,元素的定位,定位方法有很多,到时候你再学学,
注意5,元素的操作,操作的方法有很多,到时候你再学学,
###
如何使用uiautomatorviewer进行元素定位???
准备工作
一.jdk 1.8 (请勿使用JDK 1.9 将造成兼容性错误,导致)
注意UiAutomatorViewer安装失败,要考虑是不是这个java版本的问题,我之前就遇到了java版本的问题,
二.Android-SDK 3.0.0(UiAutomatorViewer 启动依赖)
三.ADB工具(链接安卓与PC)
四.UiAutomatorViewer JAR(帮助我们获取屏幕中的控件,并使用脚本操作)
五. 打开 Android-SDK 目录下的 uiautomatorviewer.bat 进行编辑
###
我的mac的这个sdk是在我的MyProject--sdk--tools--bin--uiautomatorviewer
因为我没有设置环境变量,所以我不能直接输入这个命令就行,启动,所以要进入这个目录,然后执行这个命令,
或者是双击这个uiautomatorviewer文件,
####
uiautomatorviewer启动之后,
点击左上角的按钮,可以把手机的屏幕放到这个uiautomatorviewer来,
####
然后就可以开始进行元素的定位了,
可以通过id或者class定位
使用id或者class定位可能会有多个,可以用index选择,
如果还定位不到,就使用xpath,也可以通过xpath定位,
操作就是可以点击或者输入内容,注意下面这些元素的属性
###
AndroidElement el = driver.findElement(By.id(io.***.vodi:id/message_list_item_chat_id));
AndroidElement el2 = (AndroidElement) el.findElementByClassName("android.view.View");
el2.getText(); //result is blank
el2.getAttribute("text") //result is blank
可以通过获取text属性来获取文本
###
Appium之xpath定位元素
前面也说过appium也是以webdriver为基的,对于元素的定位也基本一致,只是增加一些更适合移动平台的独特方式,下面将着重介绍xpath方法,这应该是UI层元素定位最强大的方法啦!
以淘宝app为例,定位左上角扫一扫按钮
1.如果元素text是唯一的,可以通过text文本定位
//*[@text=’text文本属性’]
# 定位text driver.find_element_by_xpath("//*[@text='扫一扫']").click()
2.如果元素id是唯一的,也可以id属性定位
//*[@resource-id=’id属性’]
# 定位 resource-id driver.find_element_by_xpath("//*[@resource-id='com.taobao.taobao:id/tv_scan_text']").click()
同样可以联合上面两种方式定位,如下
# 也可以联合@resource-id属性和@text文本属性来下定位 driver.find_element_by_xpth("//*[@resource-id='com.taobao.taobao:id/tv_scan_text'][@text='扫一扫']").click()
3.class属性唯一的话,同样可以通过class属性定位,有两种方法
第一种: //class属性
# 定位搜索框 //class属性 driver.find_element_by_xpath("//android.widget.EditText").click()
第二种: //*[@class=’class属性’]
# 定位搜索框 //*[@class='class属性'] driver.find_element_by_xpath("//*[@class='android.widget.EditText']").click()
4.通过content-desc属性定位
//*[@content-desc=’desc的文本’]
#点登录/注册 driver.find_element_by_xpath("//*[@text='注册/登录']").click() time.sleep(3) #content-desc定位 driver.find_element_by_xpath("//*[@content-desc='帮助']").click()
contains模糊定位
1)、contains是模糊匹配的定位方法,对于一个元素的id或者text不是固定的,但有一部分是固定的,这种就可以模糊匹配。
//[contains(@content-desc, ‘帮助’)]
# contains匹配text driver.find_element_by_xpath('//*[contains(@text, "注册/登录")]').click() time.sleep(3) # contains匹配textcontent-desc driver.find_element_by_xpath("//*[contains(@content-desc, '帮助')]").click()
2)、contains也能模糊匹配id和class属性
//[contains(@resource-id, ‘id属性’)]
//[contains(@clsss, ‘class属性’)]
#定位搜索框class driver.find_element_by_xpath("//*[contains(@class, 'EditText')]").click() time.sleep(3) driver.back() #定位id driver.find_element_by_xpath("//*[contains(@resource-id, 'id/home_searchedit')]").click()
组合定位
1)、如果一个元素有2个属性,通过xpath也可以同时匹配2个属性,text, resource-id,class ,index,content-desc这些属性都能任意组合定位
# id和class属性 定位搜索框 id_class = '//android.widget.EditText[@resource-id="com.taobao.taobao:id/home_searchedit"]' driver.find_element_by_xpath(id_class).click() time.sleep(3) driver.back() # text和index属性 定位登录/注册 desc_class = '//*[@text="注册/登录" and @index="1"]' driver.find_element_by_xpath(desc_class).click() time.sleep(3) # class和text属性 定位输入手机号 class_text = '//android.widget.EditText[@text="请输入手机号码"]' driver.find_element_by_xpath(class_text).send_keys("512200893") time.sleep(3) # class和desc 定位帮助 id_desc = '//*[contains(@resource-id, "aliuser_menu_item_help") and @content-desc="帮助"]' driver.find_element_by_xpath(id_desc).click()
层级定位
1)、如果一个元素,它除了class属性(class属性肯定会有),其它属性啥都没有,这种情况用上面方法就不适用了,这个时候可以找他父元素,通过父亲定位儿子
#通过父亲定位儿子 搜索输入框 fa_sun = '//*[@resoure-id="com.taobao.taobao:id/home_searchbar"]/android.widget.EditText' t = driver.find_element_by_xpath(fa_sun).text print(t)
如果一个父元素下,有多个相同class的儿子时候,可以通过xpath的索引去取对应第几个,xpath是从1开始数的
# 父元素下第2个儿子 微淘 fu_sun2 = '//*[@resource-id="com.taobao.taobao:id/ll_navigation_tab_layout"]/android.widget.FrameLayout[2]' driver.find_element_by_xpath(fu_sun2).click()
2)、相反的,可以通过儿子定位父亲
# 通过子元素定位父元素 # 方法一: .. sun_fa1 = '//*[@resource-id="com.taobao.taobao:id/tv_scan_text"]/..' c = driver.find_element_by_xpath(sun_fa1).tag_name print(c) # 方法二 parent::* sun_fa2 = '//*[@resource-id="com.taobao.taobao:id/tv_scan_text"]/parent::*' d = driver.find_element_by_xpath(sun_fa1).tag_name print(d) # 方法三 parent::android.widget.LinearLayout sun_fa3 = '//*[@resource-id="com.taobao.taobao:id/tv_scan_text"]/parent::android.widget.LinearLayout' e = driver.find_element_by_xpath(sun_fa1).tag_name print(e)
3)、通过子元素,先找到父元素,再找父元素下的子元素,同样可以进行兄弟元素定位
# 兄弟元素 xiongdi = '//*[@resource-id="com.taobao.taobao:id/bar_search"]/../android.widget.RelativeLayout' x = driver.find_element_by_xpath(xiongdi).tag_name print(x)
4)、通过层级关系,一层一层的往下找,同样可以通过爷爷元素,定位到孙子元素
#爷爷元素FrameLayout---第一个FrameLayout儿子---孙子TextView x = '//android.widget.FrameLayout/android.widget.LinearLayout[1]/android.widget.TextView' t = driver.find_elements_by_xpath(x) print(len(t)) # 打印文本信息 print(t[0].text
* 释放 (release)
* 移动到 (moveTo)
* 点击 (tap)
* 等待 (wait)
* 长按 (longPress)
* 取消 (cancel)
def getSize(driver):
x = driver.get_window_size()['width']
y = driver.get_window_size()['height']
return (x, y)
#屏幕向上滑动
def swipeUp(driver,t=1000):
l = getSize(driver)
x1 = int(l[0] * 0.5) #x坐标
y1 = int(l[1] * 0.75) #起始y坐标
y2 = int(l[1] * 0.25) #终点y坐标
driver.swipe(x1, y1, x1, y2,t)
#屏幕向下滑动
def swipeDown(driver,t=1000):
l = getSize(driver)
x1 = int(l[0] * 0.5) #x坐标
y1 = int(l[1] * 0.25) #起始y坐标
y2 = int(l[1] * 0.75) #终点y坐标
driver.swipe(x1, y1, x1, y2,t)
#屏幕向左滑动
def swipLeft(driver,t):
l=getSize(driver)
x1=int(l[0]*0.75)
y1=int(l[1]*0.5)
x2=int(l[0]*0.05)
driver.swipe(x1,y1,x2,y1,t)
#屏幕向右滑动
def swipRight(driver,t=1000):
l=getSize(driver)
x1=int(l[0]*0.05)
y1=int(l[1]*0.5)
x2=int(l[0]*0.75)
键名 描述 键值
KEYCODE_CALL 拨号键 5
KEYCODE_ENDCALL 挂机键 6
KEYCODE_HOME 按键Home 3
KEYCODE_MENU 菜单键 82
KEYCODE_BACK 返回键 4
KEYCODE_SEARCH 搜索键 84
KEYCODE_CAMERA 拍照键 27
KEYCODE_FOCUS 拍照对焦键 80
KEYCODE_POWER 电源键 26
KEYCODE_NOTIFICATION 通知键 83
KEYCODE_MUTE 话筒静音键 91
KEYCODE_VOLUME_MUTE 扬声器静音键 164
KEYCODE_VOLUME_UP 音量增加键 24
KEYCODE_VOLUME_DOWN 音量减小键 25
######