簡介
宏哥看你骨骼驚奇,印堂發(fā)亮,必是練武之奇才!?按照上一篇的節(jié)目預(yù)告,這一篇還是繼續(xù)由宏哥給小伙伴們分享元素定位,是不是按照上一篇的秘籍修煉,是不是感覺到頭頂蓋好像被掀開,內(nèi)氣從頭上冒出去,頓時(shí)覺得整個(gè)身體都融化了,而且身輕如燕啊!而且控制不住手,想要?jiǎng)邮植僮饕环兀磕沁€在等什么呢,和宏哥一起練起來吧!!!
1、 List定位
List故名思義就是一個(gè)列表,在python里面也有l(wèi)ist這一個(gè)說法,如果你不是很理解什么是list,這里暫且理解為一個(gè)數(shù)組或者說一個(gè)集合。首先一個(gè)list是一個(gè)集合,那么他的個(gè)數(shù)也就成了不確定性,所以這里需要用復(fù)數(shù),所以在我們定位時(shí)我們不能夠接著用find_element_by_id等等定位方式了,我們需要用他的復(fù)數(shù)形式find_elements_by_id,所有的定位方式都一樣需要采用復(fù)數(shù)加s。這里我們接著上篇的案例講,如何使用list定位想定位的元素。首先看一下圖片:
?
?
我們查看圖片可以知道我們能夠很輕松的通過id定位到整個(gè)祖父節(jié)點(diǎn),我們接下來需要做的事定位這個(gè)祖父節(jié)點(diǎn)下所有的“android.widget.RelativeLayout”父節(jié)點(diǎn),同樣的首先我們看一張圖:
?
?
這里我們需要直接使用定位復(fù)數(shù)的方法來操作,直接看代碼(祖父節(jié)點(diǎn)定位到父節(jié)點(diǎn)):
element= driver.find_element_by_id(
"
com.taobao.taobao:id/rv_main_container
"
)
elements
= element.find_elements_by_class_name(
"
android.widget.FrameLayout
"
)
通過上面的代碼我們直接定位了com.taobao.taobao:id/rv_main_container父節(jié)點(diǎn)下的所有android.widget.FrameLayout子節(jié)點(diǎn),但是由于這個(gè)android.widget.FrameLayout子節(jié)點(diǎn)下邊還有許多相同的android.widget.LinearLayout孫節(jié)點(diǎn)。
?
這里我們需要直接使用定位復(fù)數(shù)的方法來操作,直接看代碼(父節(jié)點(diǎn)定位到孫節(jié)點(diǎn)):
1
elements = element.find_elements_by_class_name(
"
android.widget.FrameLayout
"
)
2
elements1 = elements[
1
].find_elements_by_class_name(
"
android.widget.LinearLayout
"
)
現(xiàn)在我們需要怎么去操作這個(gè)子節(jié)點(diǎn)了,這里有兩種方法:
1、前面我們講了List你可以理解為一個(gè)數(shù)組或者一個(gè)集合,這里定位的所有子節(jié)點(diǎn)最后就成了個(gè)list,如果我們要訪問這個(gè)list里面的某一個(gè)元素我們可以像訪問數(shù)組中的數(shù)據(jù)一樣通過下標(biāo)訪問。最后的代碼就是下面這個(gè)樣子:
1
element= driver.find_element_by_id(
"
com.taobao.taobao:id/rv_main_container
"
)
2
elements = element.find_elements_by_class_name(
"
android.widget.FrameLayout
"
)
3
elements1 = elements[
1
].find_elements_by_class_name(
"
android.widget.LinearLayout
"
)
4
elements1[
1
].click()
上面的代碼最后的結(jié)果是選擇了“聚劃算”這個(gè)標(biāo)簽頁面,然后點(diǎn)擊進(jìn)入。
?
備注:如果初學(xué)者不理解是如何通過下標(biāo)訪問的,這里說一下下標(biāo)是從0開始,如果要訪問list i中的第一個(gè)元素結(jié)果就是i[0],這部分知識可以看一下python基礎(chǔ)。
2、如果你要訪問List里面的元素,那么我們是否可以通過for循環(huán)語句來依次訪問呢?這個(gè)在自動化中會經(jīng)常用到。下面你可以通過這個(gè)思路自己去實(shí)戰(zhàn)一下,看能否達(dá)到預(yù)期效果。下面看我的代碼:
1
element= driver.find_element_by_id(
"
com.taobao.taobao:id/rv_main_container
"
)
2
elements = element.find_elements_by_class_name(
"
android.widget.FrameLayout
"
)
3
elements1 = elements[
1
].find_elements_by_class_name(
"
android.widget.LinearLayout
"
)
4
for
ele
in
elements1:
5
ele.click()
看上面的代碼,我們通過循環(huán)去訪問這個(gè)list里面的每一個(gè)元素,因?yàn)槊看窝h(huán)得到的都是其中一個(gè)元素,那么我們只需要在這個(gè)元素上加上你想要的操作即可,所以我們這里可以直接點(diǎn)擊進(jìn)去。
如果你動手做到這里會發(fā)現(xiàn)一個(gè)問題,你進(jìn)入到第一個(gè)標(biāo)簽后沒一會兒系統(tǒng)就會報(bào)錯(cuò),為什么呢?你也可以試著去解決這個(gè)問題,后面我們會講解這塊兒知識。
2、 內(nèi)嵌H5定位
2.1 hybrid定位思考
在web自動化中我們會遇見frame的問題,在遇見這些內(nèi)嵌的標(biāo)簽后我們需要做的就是切換窗口,那么在app自動化測試也有類似的情況就是我們經(jīng)常看見的內(nèi)嵌html,在我們原生的app中增加一個(gè)由html做成的頁面。大家可以思考一下這種情況怎么操作。
2.2 hybrid常見定位問題分析
首先我們看一下下面一張圖片:
通過右邊的結(jié)構(gòu)圖我們能夠清晰的看見整個(gè)頁面就是一個(gè)webview,無論從什么角度來定位我們都不能夠很好的進(jìn)行,如果這個(gè)時(shí)候我們需要操作頁面的元素就需要通過切換contexts來完成。但是在講這個(gè)知識點(diǎn)之前大家先按照網(wǎng)上的知識來試一下處理這個(gè)頁面,看能否成功。下面先說大家會遇見的問題:
1、可能你看到有的文章顯示我們不需要通過切換contexts就能夠完成定位,這樣的情況有,但是那種情況作者只在微博登錄、qq登錄等第三方登錄時(shí)遇見過,如果不是這樣的情況而像上面的情況就沒辦法通過類似的方法進(jìn)行完成,所以我希望讀者遇見這種情況時(shí)自己動手去操作,看什么方式更加適合自己的項(xiàng)目。
2、需要切換contexts那么就需要獲取頁面的所有contexts,此時(shí)你通過官網(wǎng)或者其他文章的知識通過下面的方法來獲取,可能會報(bào)錯(cuò),這種情況關(guān)系不大。
1
webview =
self.driver.contexts
2
print webview
如果你通過上面的代碼來調(diào)試但是卻報(bào)錯(cuò),但是其他資料卻沒問題時(shí)你也不要著急,這里你需要確定兩件事情:(1)、app打包的時(shí)候需要開啟webview 的debug屬性setWebContentDebuggingEnabled(true),這個(gè)直接讓開發(fā)加上就好。一般情況是開啟的,畢竟他們也要調(diào)試。(2)、你用很多手機(jī)去調(diào)試,發(fā)現(xiàn)有一些可以有一些不可以,但是你用模擬器卻都可以,根據(jù)官方給出的答案是這個(gè)時(shí)候你需要去將手機(jī)root,然后再試。目前作者遇見了這兩種情況,第二種我也是調(diào)試了很久才找到原因。
2.3 hybrid定位講解
這兩個(gè)問題解決后那么定位webview就輕松搞定,直接看代碼:
1
webview =
driver.contexts
2
driver.switch_to.context(webview[
1
])
3
driver.find_element_by_link_text(
'
PHP
'
).click()
對于初學(xué)者對于上面的代碼可能不是很理解,下面我們看一下日志:
大家這里不用管我執(zhí)行代碼和之前的區(qū)別(多了一個(gè)self),我們看下面控制臺的輸出,輸出的是一個(gè)list,前面說過list和數(shù)組類似,在這個(gè)list里面有兩個(gè)元素“NATIVE_APP”,“WEBVIEW_cn_com_open_mooc”,第一個(gè)元素是我們原生的app的contexts,后面的則是我們的webview的context,所以我們需要獲取webview的context時(shí)只需要通過這個(gè)list的下表來進(jìn)行訪問。
我們獲取到webview的context后只需要通過driver.switch_to.context()進(jìn)行切換就好。當(dāng)切換后我們就可以像定位web一樣進(jìn)行定位。
看下面一張圖片我們通過瀏覽器將h5頁面打開:
通過上面的圖片我們就能夠很輕松的像web一樣進(jìn)行定位,也就可以使用web的一些定位方式。看到這里是不是覺得解決了一個(gè)難題呢?動手去吧。
2.4 hybrid問題實(shí)戰(zhàn)
通過前面的學(xué)習(xí)我相信你已經(jīng)有了一些實(shí)戰(zhàn)能力,這里給大家提一個(gè)問題,我們獲取到的contexts每次一定是兩個(gè)嗎?如果不是兩個(gè)那么我們上面的腳本是不是就沒辦法用了呢?可以思考一下這里怎么解決,在看我們下面的思路以及解決方案。
無論在什么頁面我們?nèi)カ@取contexts時(shí)他無論有幾個(gè)但是他的類型是不是肯定都是一個(gè)list呢?既然是list那么我們是否可以取到里面的每一個(gè)值,然后把每一個(gè)值進(jìn)行判斷,只要找出我們的webview就可以了呢?下面看代碼:
1
#獲取當(dāng)前頁面所有的contexts
2
webview =
driver.contexts
3
#在獲取到的contexts list里面去挨個(gè)循環(huán)
4
for
context
in
webview:
5
#判斷循環(huán)中單個(gè)的context是否是webview,如果是就進(jìn)行切換,并且跳出循環(huán)
6
if
'
WEBVIEW
'
in
context:
7
driver.switch_to.context(context)
8
break
9
driver.find_element_by_link_text(
'
PHP
'
).click()
通過上面的代碼我們是否完美的解決了內(nèi)嵌H5的定位問題呢?動手吧
3、 滑動定位
3.1 滑動定位方式
在app自動化中我們經(jīng)常會遇見一個(gè)問題,我們需要查找的元素不在當(dāng)前可展示的屏幕,至于在什么地方我們不知道,如果這個(gè)時(shí)候我們一直使用在當(dāng)前頁面查找,那么系統(tǒng)就會報(bào)錯(cuò),為了解決這個(gè)問題我們就需要使用滑動查找。
首先的思路是我們在需要查找對象的頁面查找一下該元素,判斷該元素是否在當(dāng)前頁面,如果該元素不在該頁面那么我們就需要去互動屏幕,到我們的下一屏幕,然后再進(jìn)行查找,依次類推到找到為止。
3.2 滑動定位思路分析
方式我們有了,那么我們就需要知道實(shí)現(xiàn)這個(gè)功能應(yīng)該有哪些點(diǎn)。下面跟著我一起來分析一下:
1、需要查找的元素我們是不是需要知道是什么呢?這個(gè)需要先確定
2、我們需要找的頁面是在我們的當(dāng)前頁面的上方還是下方還是左方還是右方,我們不能確定,那么我們是否需要確定我們需要滑動的方向?
3、元素和方向有了,但是你知道我們每次需要滑動屏幕的多少嗎?那么我們是否需要先去獲取屏幕的大小,然后針對不同的方向去計(jì)算一個(gè)滑動的值呢?
萬事具備只欠東風(fēng),去按照這個(gè)思路動手練習(xí)一吧。
3.3 滑動定位實(shí)戰(zhàn)
一、根據(jù)上面的思路我們能首先來確定我們需要查找的元素,看下面圖片:
我們要找實(shí)戰(zhàn)推薦后面的“換一換”按鈕,然后進(jìn)行點(diǎn)擊。首先我們查看他的定位信息
最后我們查找元素的定位信息代碼如下:
1
self.driver.find_element_by_id(
'
cn.com.open.mooc:id/tv_replace
'
).click()
?
對于有一定基礎(chǔ)的人可能會覺得這個(gè)很low,但是有沒有思考過一個(gè)問題,我們可以通過這個(gè)代碼去執(zhí)行,在沒有這按鈕的時(shí)候卻會報(bào)錯(cuò),也就沒有辦法執(zhí)行下去了,那么需要怎么處理呢?所以這個(gè)時(shí)候我們需要有一些python的容錯(cuò)知識,即使我們的代碼執(zhí)行出錯(cuò)了,那么也要讓他按照我們的意思執(zhí)行下去。try.......except.......,這個(gè)就是我們python中的容錯(cuò)處理 ,下面我們看添加后的代碼:
1
try
:
2
self.driver.find_element_by_id(
'
cn.com.open.mooc:id/tv_replace
'
).click()
3
except Exception,e:
4
print e
try的意思就是告訴編譯器試著去執(zhí)行他下面這一段代碼,如果報(bào)錯(cuò)了,那么你就把except里面的錯(cuò)誤信息打印出來。
二、有了元素現(xiàn)在我們需要知道的是不是就是該怎么滑動界面了呢?首先我們看一下下面這張圖片:
在我們使用app的過程中存在上面幾種滑動情況,我們把整個(gè)界面看作為一個(gè)坐標(biāo)系(x,y),如果我們需要往上滑動,那么我們是不是就是x軸不動,y軸從下往上動呢?往下就是x軸不動,y軸從上往下呢?同理左右滑動是不是就是應(yīng)該y軸不動x軸左右滑動呢?可以好好去體會一下,腦海中有個(gè)畫面。
在appium中滑動我們所需要使用的方法就是swipe函數(shù),至于往哪個(gè)方向滑動就是看我們里面的x,y的值,如果我們需要下往上滑動那么我們就應(yīng)該是:
1
self.driver.swipe(x1,y1,x1,y2,t)
上面的代碼x軸的值不變,y軸的值進(jìn)行了變化,所以是沿著上下進(jìn)行滑動的,從y2滑動到了y1點(diǎn)。t代表的是多少時(shí)間完成這個(gè)動作,或者說這個(gè)時(shí)間持續(xù)多久。
備注:這里需要注意的是屏幕的x,y的值是從左上角開始取的,左上角為(0,0),右下角是最大。
三、上面滑動的方法看著是好用,但是我們不可能每次都去填寫一個(gè)坐標(biāo),那樣太low,所以我們需要獲取屏幕大小,直接看代碼:
1
x = self.driver.get_window_size()[
'
width
'
]
2
y = self.driver.get_window_size()[
'
height
'
]
上面的代碼就是我們獲取到的x,y軸。通過思路我們的代碼都有了,下面我們要做的就是對原來的代碼進(jìn)行修改,進(jìn)行一個(gè)封裝。下面看代碼,這個(gè)暫時(shí)看不懂沒關(guān)系,到后面我們學(xué)了python'基礎(chǔ)就能夠看懂了。先思路,然后了解。
1
#獲取屏幕大小
2
3
def getSize(self):
4
x = self.driver.get_window_size()[
'
width
'
]
5
y = self.driver.get_window_size()[
'
height
'
]
6
return
(x,y)
7
8
9
#向左滑動
10
def swipeLeft(self,t):
11
l=
self.getSize()
12
x1=
int
(l[
0
]*
0.9
)
13
y1=
int
(l[
1
]*
0.5
)
14
x2=
int
(l[
0
]*
0.1
)
15
self.driver.swipe(x1,y1,x2,y1,t)
16
17
#向右滑動
18
def swipeRight(self,t):
19
l=
self.getSize()
20
x1=
int
(l[
0
]*
0.25
)
21
y1=
int
(l[
1
]*
0.5
)
22
x2=
int
(l[
0
]*
0.75
)
23
self.driver.swipe(x1,y1,x2,y1,t)
24
25
#向上滑動
26
def swipeUp(self,t):
27
l=
self.getSize()
28
x1=
int
(l[
0
]*
0.5
)
29
y1=
int
(l[
1
]*
0.8
)
30
y2=
int
(l[
1
]*
0.4
)
31
self.driver.swipe(x1,y1,x1,y2,t)
32
time.sleep(
5
)
33
34
#向下滑動
35
def swipeDown(self,t):
36
l=
self.getSize()
37
x1=
int
(l[
0
]*
0.5
)
38
y1=
int
(l[
1
]*
0.25
)
39
y2=
int
(l[
1
]*
0.75
)
40
self.driver.swipe(x1,y1,x1,y2,t)
41
42
#查找元素,沒找到滑動
43
def findLocal(self):
44
x =
1
45
while
x==
1
:
46
if
self.fact() ==
1
:
47
self.swipeUp(
2000
)
48
time.sleep(
3
)
49
self.fact()
50
else
:
51
print
"
找到了
"
52
x=
2
53
54
55
56
#遞歸
57
def fact(self):
58
n =
1
59
try
:
60
self.driver.find_element_by_id(
'
cn.com.open.mooc:id/tv_replace
'
).click()
61
except Exception,e:
62
return
n
通過查看上面代碼的整個(gè)邏輯就是1、首先去查找元素,如果找到了我就直接點(diǎn)擊。2、如果沒有找到元素那么我就往上滑動(這里可以自己選擇),滑動后再次進(jìn)行查找,如果找到就點(diǎn)擊,沒有找到繼續(xù)滑動。動手動手,這里知識點(diǎn)很重要!雖然后面會有一些替代方法,但是思路、算法很重要。
4、小結(jié)
? ?好了,元素定位,常見的大致就這些,這個(gè)目前就分享到這里吧,以后如果遇到,宏哥給小伙伴再補(bǔ)上!!!
?
支持宏哥的朋友們和宏哥的宏粉記得點(diǎn)波推薦哦,您的肯定就是我進(jìn)步的動力。宏哥先在這里給您道謝了,謝您嘞~~
個(gè)人公眾號
微信群
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

