簡介
宏哥看你骨骼驚奇,印堂發亮,必是練武之奇才!?按照上一篇的節目預告,這一篇還是繼續由宏哥給小伙伴們分享元素定位,是不是按照上一篇的秘籍修煉,是不是感覺到頭頂蓋好像被掀開,內氣從頭上冒出去,頓時覺得整個身體都融化了,而且身輕如燕??!而且控制不住手,想要動手操作一番呢?那還在等什么呢,和宏哥一起練起來吧?。?!
1、 List定位
List故名思義就是一個列表,在python里面也有list這一個說法,如果你不是很理解什么是list,這里暫且理解為一個數組或者說一個集合。首先一個list是一個集合,那么他的個數也就成了不確定性,所以這里需要用復數,所以在我們定位時我們不能夠接著用find_element_by_id等等定位方式了,我們需要用他的復數形式find_elements_by_id,所有的定位方式都一樣需要采用復數加s。這里我們接著上篇的案例講,如何使用list定位想定位的元素。首先看一下圖片:
?
?
我們查看圖片可以知道我們能夠很輕松的通過id定位到整個祖父節點,我們接下來需要做的事定位這個祖父節點下所有的“android.widget.RelativeLayout”父節點,同樣的首先我們看一張圖:
?
?
這里我們需要直接使用定位復數的方法來操作,直接看代碼(祖父節點定位到父節點):
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父節點下的所有android.widget.FrameLayout子節點,但是由于這個android.widget.FrameLayout子節點下邊還有許多相同的android.widget.LinearLayout孫節點。
?
這里我們需要直接使用定位復數的方法來操作,直接看代碼(父節點定位到孫節點):
1 elements = element.find_elements_by_class_name( " android.widget.FrameLayout " ) 2 elements1 = elements[ 1 ].find_elements_by_class_name( " android.widget.LinearLayout " )
現在我們需要怎么去操作這個子節點了,這里有兩種方法:
1、前面我們講了List你可以理解為一個數組或者一個集合,這里定位的所有子節點最后就成了個list,如果我們要訪問這個list里面的某一個元素我們可以像訪問數組中的數據一樣通過下標訪問。最后的代碼就是下面這個樣子:
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()
上面的代碼最后的結果是選擇了“聚劃算”這個標簽頁面,然后點擊進入。
?
備注:如果初學者不理解是如何通過下標訪問的,這里說一下下標是從0開始,如果要訪問list i中的第一個元素結果就是i[0],這部分知識可以看一下python基礎。
2、如果你要訪問List里面的元素,那么我們是否可以通過for循環語句來依次訪問呢?這個在自動化中會經常用到。下面你可以通過這個思路自己去實戰一下,看能否達到預期效果。下面看我的代碼:
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()
看上面的代碼,我們通過循環去訪問這個list里面的每一個元素,因為每次循環得到的都是其中一個元素,那么我們只需要在這個元素上加上你想要的操作即可,所以我們這里可以直接點擊進去。
如果你動手做到這里會發現一個問題,你進入到第一個標簽后沒一會兒系統就會報錯,為什么呢?你也可以試著去解決這個問題,后面我們會講解這塊兒知識。
2、 內嵌H5定位
2.1 hybrid定位思考
在web自動化中我們會遇見frame的問題,在遇見這些內嵌的標簽后我們需要做的就是切換窗口,那么在app自動化測試也有類似的情況就是我們經??匆姷膬惹秇tml,在我們原生的app中增加一個由html做成的頁面。大家可以思考一下這種情況怎么操作。
2.2 hybrid常見定位問題分析
首先我們看一下下面一張圖片:
通過右邊的結構圖我們能夠清晰的看見整個頁面就是一個webview,無論從什么角度來定位我們都不能夠很好的進行,如果這個時候我們需要操作頁面的元素就需要通過切換contexts來完成。但是在講這個知識點之前大家先按照網上的知識來試一下處理這個頁面,看能否成功。下面先說大家會遇見的問題:
1、可能你看到有的文章顯示我們不需要通過切換contexts就能夠完成定位,這樣的情況有,但是那種情況作者只在微博登錄、qq登錄等第三方登錄時遇見過,如果不是這樣的情況而像上面的情況就沒辦法通過類似的方法進行完成,所以我希望讀者遇見這種情況時自己動手去操作,看什么方式更加適合自己的項目。
2、需要切換contexts那么就需要獲取頁面的所有contexts,此時你通過官網或者其他文章的知識通過下面的方法來獲取,可能會報錯,這種情況關系不大。
1 webview = self.driver.contexts 2 print webview
如果你通過上面的代碼來調試但是卻報錯,但是其他資料卻沒問題時你也不要著急,這里你需要確定兩件事情:(1)、app打包的時候需要開啟webview 的debug屬性setWebContentDebuggingEnabled(true),這個直接讓開發加上就好。一般情況是開啟的,畢竟他們也要調試。(2)、你用很多手機去調試,發現有一些可以有一些不可以,但是你用模擬器卻都可以,根據官方給出的答案是這個時候你需要去將手機root,然后再試。目前作者遇見了這兩種情況,第二種我也是調試了很久才找到原因。
2.3 hybrid定位講解
這兩個問題解決后那么定位webview就輕松搞定,直接看代碼:
1 webview = driver.contexts 2 driver.switch_to.context(webview[ 1 ]) 3 driver.find_element_by_link_text( ' PHP ' ).click()
對于初學者對于上面的代碼可能不是很理解,下面我們看一下日志:
大家這里不用管我執行代碼和之前的區別(多了一個self),我們看下面控制臺的輸出,輸出的是一個list,前面說過list和數組類似,在這個list里面有兩個元素“NATIVE_APP”,“WEBVIEW_cn_com_open_mooc”,第一個元素是我們原生的app的contexts,后面的則是我們的webview的context,所以我們需要獲取webview的context時只需要通過這個list的下表來進行訪問。
我們獲取到webview的context后只需要通過driver.switch_to.context()進行切換就好。當切換后我們就可以像定位web一樣進行定位。
看下面一張圖片我們通過瀏覽器將h5頁面打開:
通過上面的圖片我們就能夠很輕松的像web一樣進行定位,也就可以使用web的一些定位方式??吹竭@里是不是覺得解決了一個難題呢?動手去吧。
2.4 hybrid問題實戰
通過前面的學習我相信你已經有了一些實戰能力,這里給大家提一個問題,我們獲取到的contexts每次一定是兩個嗎?如果不是兩個那么我們上面的腳本是不是就沒辦法用了呢?可以思考一下這里怎么解決,在看我們下面的思路以及解決方案。
無論在什么頁面我們去獲取contexts時他無論有幾個但是他的類型是不是肯定都是一個list呢?既然是list那么我們是否可以取到里面的每一個值,然后把每一個值進行判斷,只要找出我們的webview就可以了呢?下面看代碼:
1 #獲取當前頁面所有的contexts 2 webview = driver.contexts 3 #在獲取到的contexts list里面去挨個循環 4 for context in webview: 5 #判斷循環中單個的context是否是webview,如果是就進行切換,并且跳出循環 6 if ' WEBVIEW ' in context: 7 driver.switch_to.context(context) 8 break 9 driver.find_element_by_link_text( ' PHP ' ).click()
通過上面的代碼我們是否完美的解決了內嵌H5的定位問題呢?動手吧
3、 滑動定位
3.1 滑動定位方式
在app自動化中我們經常會遇見一個問題,我們需要查找的元素不在當前可展示的屏幕,至于在什么地方我們不知道,如果這個時候我們一直使用在當前頁面查找,那么系統就會報錯,為了解決這個問題我們就需要使用滑動查找。
首先的思路是我們在需要查找對象的頁面查找一下該元素,判斷該元素是否在當前頁面,如果該元素不在該頁面那么我們就需要去互動屏幕,到我們的下一屏幕,然后再進行查找,依次類推到找到為止。
3.2 滑動定位思路分析
方式我們有了,那么我們就需要知道實現這個功能應該有哪些點。下面跟著我一起來分析一下:
1、需要查找的元素我們是不是需要知道是什么呢?這個需要先確定
2、我們需要找的頁面是在我們的當前頁面的上方還是下方還是左方還是右方,我們不能確定,那么我們是否需要確定我們需要滑動的方向?
3、元素和方向有了,但是你知道我們每次需要滑動屏幕的多少嗎?那么我們是否需要先去獲取屏幕的大小,然后針對不同的方向去計算一個滑動的值呢?
萬事具備只欠東風,去按照這個思路動手練習一吧。
3.3 滑動定位實戰
一、根據上面的思路我們能首先來確定我們需要查找的元素,看下面圖片:
我們要找實戰推薦后面的“換一換”按鈕,然后進行點擊。首先我們查看他的定位信息
最后我們查找元素的定位信息代碼如下:
1 self.driver.find_element_by_id( ' cn.com.open.mooc:id/tv_replace ' ).click()
?
對于有一定基礎的人可能會覺得這個很low,但是有沒有思考過一個問題,我們可以通過這個代碼去執行,在沒有這按鈕的時候卻會報錯,也就沒有辦法執行下去了,那么需要怎么處理呢?所以這個時候我們需要有一些python的容錯知識,即使我們的代碼執行出錯了,那么也要讓他按照我們的意思執行下去。try.......except.......,這個就是我們python中的容錯處理 ,下面我們看添加后的代碼:
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的意思就是告訴編譯器試著去執行他下面這一段代碼,如果報錯了,那么你就把except里面的錯誤信息打印出來。
二、有了元素現在我們需要知道的是不是就是該怎么滑動界面了呢?首先我們看一下下面這張圖片:
在我們使用app的過程中存在上面幾種滑動情況,我們把整個界面看作為一個坐標系(x,y),如果我們需要往上滑動,那么我們是不是就是x軸不動,y軸從下往上動呢?往下就是x軸不動,y軸從上往下呢?同理左右滑動是不是就是應該y軸不動x軸左右滑動呢?可以好好去體會一下,腦海中有個畫面。
在appium中滑動我們所需要使用的方法就是swipe函數,至于往哪個方向滑動就是看我們里面的x,y的值,如果我們需要下往上滑動那么我們就應該是:
1
self.driver.swipe(x1,y1,x1,y2,t)
上面的代碼x軸的值不變,y軸的值進行了變化,所以是沿著上下進行滑動的,從y2滑動到了y1點。t代表的是多少時間完成這個動作,或者說這個時間持續多久。
備注:這里需要注意的是屏幕的x,y的值是從左上角開始取的,左上角為(0,0),右下角是最大。
三、上面滑動的方法看著是好用,但是我們不可能每次都去填寫一個坐標,那樣太low,所以我們需要獲取屏幕大小,直接看代碼:
1 x = self.driver.get_window_size()[ ' width ' ] 2 y = self.driver.get_window_size()[ ' height ' ]
上面的代碼就是我們獲取到的x,y軸。通過思路我們的代碼都有了,下面我們要做的就是對原來的代碼進行修改,進行一個封裝。下面看代碼,這個暫時看不懂沒關系,到后面我們學了python'基礎就能夠看懂了。先思路,然后了解。
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
通過查看上面代碼的整個邏輯就是1、首先去查找元素,如果找到了我就直接點擊。2、如果沒有找到元素那么我就往上滑動(這里可以自己選擇),滑動后再次進行查找,如果找到就點擊,沒有找到繼續滑動。動手動手,這里知識點很重要!雖然后面會有一些替代方法,但是思路、算法很重要。
4、小結
? ?好了,元素定位,常見的大致就這些,這個目前就分享到這里吧,以后如果遇到,宏哥給小伙伴再補上?。。?
?
支持宏哥的朋友們和宏哥的宏粉記得點波推薦哦,您的肯定就是我進步的動力。宏哥先在這里給您道謝了,謝您嘞~~
個人公眾號
微信群
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
