啓動過程
appium的啓動實際上是在本機使用了4723端口開啓了一個服務
1. 我們寫的 python 代碼會訪問本機的 appium 服務器,並獲取 driver 對象
2. appium 會將我們的 driver 對象調用的方法轉化成 post 請求,提交給appium服務器
3. appium 通過接收到的 post 請求發送給手機,再由手機進行執行
# 導模塊
from appium import webdriver
# 創建一個字典,包裝相應的啓動參數
desired_caps = dict()
# 需要連接的手機的平臺(不限制大小寫)
desired_caps['platformName'] = 'Android'
# 需要連接的手機的版本號(比如 5.2.1 的版本可以填寫 5.2.1 或 5.2 或 5 ,以此類推) desired_caps['platformVersion'] = '5.1'
# 需要連接的手機的設備號(andoird平臺下,可以隨便寫,但是不能不寫)
desired_caps['deviceName'] = '192.168.56.101:5555'
# 需要啓動的程序的包名
desired_caps['appPackage'] = 'com.android.settings'
# 需要啓動的程序的界面名
desired_caps['appActivity'] = '.Settings'
# 連接appium服務器
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
# 退出
driver.quit()
App基礎操作API
import os
from app.util import encode_data, decode_data, get_driver
driver = get_driver()
"3、app是否已安裝"
is_installed = driver.is_app_installed('com.example.corel.calc')
# eg:沒安裝安裝,安裝了就卸載
if is_installed:
"2、卸載手機自己安裝的app,不能卸載系統的app"
driver.remove_app('com.example.corel.calc')
else:
"1、安裝apk到手機,支持重複安裝進行覆蓋,絕對路徑"
driver.install_app(os.getcwd() + os.sep + 'apk' + os.sep + 'com.example.corel.calc_2.1.1023_11.apk')
"""4、發送⽂件到⼿機,eg:將hello寫入到手機
driver.push_file(path, data)
參數:
path:⼿機設備上的路徑(例如:/sdcard/a.txt)
data:⽂件內數據,要求base64編碼
Python3.x中字符都爲unicode編碼,⽽b64encode函數的參數爲byte類型,需要先轉碼;⽣成的數據爲byte類型,需要將byte轉換回去。"""
data = encode_data('hello')
driver.push_file('/sdcard/abc.txt', data) # 不指定abc.txt,會生成一個.tmp結尾的臨時文件,不便於後續的維護
"5、從手機拉取文件,返回的是base64編碼數據"
data = driver.pull_file('/sdcard/abc.txt') # 返回數據爲base64編碼
re_data = decode_data(data)
print(re_data)
"6、獲取 當前屏幕 元素結構,返回xml字符串,只是當前屏幕(activity頁面內容是xml承載的)"
with open('./result/page.xml', 'w') as f:
f.write(driver.page_source)
driver.quit()
import base64
from appium import webdriver
# 輸⼊⽂本內容到⼿機,中文輸入支持:
# 1 使用Unicode鍵盤:'unicodeKeyboard': True
# 2 重置鍵盤:'resetKeyboard': True
def get_driver():
desired_caps = {'platformName': 'android',
'platformVersionName': '5.1',
'deviceName': '192.168.192.101:5555',
'appPackage': 'com.android.settings',
'appActivity': '.Settings',
'unicodeKeyboard': True}
return webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
# base64編碼
def encode_data(value_arg):
return str(base64.b64encode(value_arg.encode('utf-8')), 'utf-8')
# base64解碼
def decode_data(data):
return str(base64.b64decode(data), 'utf-8')
APP元素定位操作
name |
value |
id |
resource-id屬性值 |
class |
class屬性值 |
xpath |
xpath表達式 |
from time import sleep
from selenium.webdriver.support.wait import WebDriverWait
# ❀ 藉助sdk家⽬錄下的tools⽬錄中的uiautomatorviewer.bat進行定位,而該shell腳本和appium共用同一個adb,
# 如果自動化腳本中因異常沒有關閉adb服務,那此時進行快照截圖的話是會報錯的,解決辦法:adb kill-server
# 三種定位使用優先級:
# 優先使用:id class
# 其次使用:xpath,需藉助text、class、resource-id纔可完成
# xpath語句:
# 1."//*[contains(@text,'text屬性值')]"
# 2."//*[contains(@class,'class屬性值')]"
# 3."//*[contains(@resource-id,'resource-id屬性值')]"
from app.util import get_driver
driver = get_driver()
# 1、id獲取搜索按鈕並點擊
driver.find_element_by_id('com.android.settings:id/search').click()
# 3.1 xpath + id組合 獲取搜索按鈕並點擊
search_btn = '//*[contains(@resource-id, "com.android.settings:id/search")]'
driver.find_element_by_xpath(search_btn).click()
sleep(2)
# 2、class獲取返回按鈕並點擊
driver.find_element_by_class_name('android.widget.ImageButton').click()
# 3.2 xpath + class組合 獲取返回按鈕並點擊
search_return_btn = '//*[contains(@class, "android.widget.ImageButton")]'
driver.find_element_by_xpath(search_return_btn).click()
sleep(2)
# 3.3 xpath + text 獲取返回按鈕並點擊
more_btn = '//*[contains(@text, "更")]'
driver.find_element_by_xpath(more_btn).click()
sleep(2)
# 定位一組元素id,class,xpath
ids_value = driver.find_elements_by_id('com.android.settings:id/title')
for i in ids_value:
print(i.text)
print('❀______')
classes_value = driver.find_elements_by_class_name('android.widget.TextView')
for i in classes_value:
print(i.text)
print('❀______')
xpath_value = '//*[contains(@text, "示")]'
xpaths_value = driver.find_elements_by_xpath(xpath_value)
for i in xpaths_value:
print(i.text)
# 隱式等待:是等到整個頁面加載結束才進行後續操作
# 顯示等待:是等待某一個具體的元素成功獲取
driver.find_element_by_xpath('//*[contains(@text, "更多")]').click()
WebDriverWait(driver, 10).until(lambda x: x.find_element_by_xpath('//*[contains(@text, "飛行模式")]')).click()
driver.quit()
APP元素信息操作API
from app.util import get_driver
driver = get_driver()
search = driver.find_element_by_id('com.android.settings:id/search')
search.click()
search_input = driver.find_element_by_id('android:id/search_src_text')
search_input.send_keys('文')
search_input.clear()
search_input.send_keys('星魂')
# 獲取元素id class text content-desc的屬性值:
# get_attribute(value):
# value = name -> 返回content-desc或text
# value = text -> 返回text
# value = className -> 返回class,只有API>=18(Android4.3)才能支持
# value = resourceId -> 返回resource_id,只有API>=18才能支持
print('resource_id:', search.get_attribute('resourceId'))
print('class:', search.get_attribute('className'))
print('content_desc:', search.get_attribute('name'))
# 應用場景:只是想滑動輪播圖,並不想整個頁面滑動
more_btn = '//*[contains(@text, "更")]'
more = driver.find_element_by_xpath(more_btn)
# 1 獲取元素屏幕座標
print('座標:' + more.location)
# 2 獲取元素大小
print('寬和高:' + more.size)
# 獲取包命和啓動名
print('包命:', driver.current_package)
print('啓動名:', driver.current_activity)
driver.quit()
APP元素事件操作API
swipe滑動事件
import time from util import get_driver # swipe(start_x, start_y, end_x, end_y, duration=None),duration單位ms # 作用: # 1 滑動沒有持續時間,滑動相對隨機,隨機距離不遠 # 2 滑動持續在2s左右時,滑動相對準確 --最常用 # 3 滑動持續爲幾十毫秒時,會產生點擊起點位置操作 driver = get_driver() save = driver.find_element_by_xpath("//*[contains(@text,'存儲')]").location wlan = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]").location # driver.swipe(save.get("x"), save.get("y"), wlan.get("x"), wlan.get("y")) # 滑動,有滑動時間,滑動相對準確 最少2s driver.swipe(save.get("x"), save.get("y"), wlan.get("x"), wlan.get("y"), 2000) # 滑動,有滑動時間,滑動相對較長 最少200ms 但如果時幾十毫秒,會產生點擊起點位置操作 driver.swipe(save.get("x"), save.get("y"), wlan.get("x"), wlan.get("y"), 200) # 關閉 time.sleep(2) driver.quit()
scroll滑動事件
import time from util import get_driver # scroll(origin_el, destination_el, duration=None) # 滑動相對隨機,不用 driver = get_driver() save = driver.find_element_by_xpath("//*[contains(@text,'存儲')]").location wlan = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]").location # 無滑動時間 driver.scroll(save, wlan) # 有滑動時間2s driver.scroll(save, wlan, 2000) # 關閉 time.sleep(2) driver.quit()
drag拖拽事件
import time from util import get_driver # drag_and_drop(origin_el, destination_el):從⼀個元素滑動到另⼀個元素,起點元素最終會替代終點元素原本屏幕上的位置 driver = get_driver() save = driver.find_element_by_xpath("//*[contains(@text,'存儲')]").location wlan = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]").location driver.drag_and_drop(save, wlan) # 關閉 time.sleep(2) driver.quit()
from time import sleep from appium.webdriver.common.touch_action import TouchAction from util import get_driver driver = get_driver() save = driver.find_element_by_xpath("//*[contains(@text,'存儲')]") more = driver.find_element_by_xpath("//*[contains(@text,'更多')]") touch_action = TouchAction(driver) # 滑動方式一:press(元素).move_to(元素) 滑動不精準,scroll底層實現方式 touch_action.press(save).move_to(more).release().perform() # 滑動方式二:press(座標).move_to(座標) 滑動不精準,swipe底層實現方式 touch_action.press(x=save.location.get('x'), y=save.location.get('y')).move_to(x=more.location.get('x'), y=more.location.get( 'y')).release().perform() # 滑動方式三:long_press(元素).move_to(座標) 精準滑動,drag_and_drop底層實現方式 touch_action.long_press(save).move_to(more).release().perform() sleep(2) driver.quit()
應⽤置於後臺事件
from time import sleep
from util import get_driver
driver = get_driver()
sleep(1)
# 將設置app放置後臺5s,在此期間,點擊桌面應用無效,因爲它並沒有運行結束,而是在後臺運行
driver.background_app(5)
driver.quit()
APP模擬⼿勢⾼級操作
TouchAction是AppiumDriver的輔助類,主要針對⼿勢操作,⽐如滑動、⻓按、拖動等, 原理是將⼀系列的動作放在⼀個鏈條中 發送 到服務器,服務器接受到該鏈條後,解析各個動作,逐個執⾏
from time import sleep
from appium.webdriver.common.touch_action import TouchAction
from util import get_driver
driver = get_driver()
wlan = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]")
touch_action = TouchAction(driver)
"""1 手指輕敲操作:模擬⼿指輕敲⼀下屏幕操作"""
# TouchAction(driver).tap(wlan).perform() # 元素方式
touch_action.tap(x=wlan.location.get('x'), y=wlan.location.get('y')).perform() # 座標方式
"""2 ⼿指按操作:: 模擬⼿指按下屏幕,然後鬆開"""
touch_action.press(wlan).release().perform() # 元素方式
touch_action.press(x=wlan.location.get('x'), y=wlan.location.get('y')).perform() # 座標方式
"""3 等待操作:wait(ms=0)"""
# 方式一:press + wait
wlan.click()
ssid = driver.find_element_by_xpath("//*[contains(@text,'SSID')]")
# 添加等待(有⻓按)/不添加等待(⽆⻓按效果)
touch_action.press(ssid).wait(2000).release().perform()
# 方式二:long_press
touch_action.long_press(ssid).release().perform() # 元素方式
touch_action.long_press(x=ssid.location.get('x'), y=wlan.location.get('y')).release().perform() # 座標方式
sleep(2)
driver.quit()
from time import sleep
from appium.webdriver.common.touch_action import TouchAction
from util import get_driver
# appium版本 1.12
# move_to:絕對座標
# appium版本 1.7之前
# move_to:相對座標
driver = get_driver()
bat = driver.find_element_by_xpath("//*[contains(@text,'電池')]")
wlan = driver.find_element_by_xpath("//*[contains(@text,'WLAN')]")
driver.drag_and_drop(bat, wlan)
driver.find_element_by_xpath("//*[contains(@text,'安全')]").click()
sleep(2)
driver.find_element_by_xpath("//*[contains(@text,'屏幕鎖定')]").click()
sleep(2)
driver.find_element_by_xpath("//*[contains(@text,'圖案')]").click()
sleep(2)
TouchAction(driver).press(x=234, y=850).wait(100).move_to(x=723, y=850).wait(100) \
.move_to(x=723, y=1326).wait(100).move_to(x=234, y=1808).release().perform()
sleep(2)
driver.quit()
⼿機操作API
from time import sleep
from util import get_driver
driver = get_driver()
# 1 獲取手機分辨率,通常用於swipe方法完成滑動操作
size = driver.get_window_size()
print('分辨率:', size)
width = size.get('width')
height = size.get('height')
driver.swipe(width * 0.5, height * 0.8, width * 0.5, height * 0.2, 2000)
sleep(3)
driver.close_app()
driver.swipe(width * 0.8, height * 0.5, width * 0.2, height * 0.5, 2000)
sleep(3)
driver.quit()
發送鍵到設備
from time import sleep
from util import get_driver
driver = get_driver()
# 模擬音量鍵 +
for i in range(3):
driver.keyevent(24)
# 模擬音量鍵 -
for i in range(3):
driver.keyevent(25)
sleep(3)
driver.quit()
操作⼿機通知欄
from appium import webdriver
import time
# server 啓動參數
from appium.webdriver.common.touch_action import TouchAction
desired_caps = {}
# 設備信息
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.56.101:5555'
# app的信息
desired_caps['appPackage'] = 'io.manong.developerdaily'
desired_caps['appActivity'] = 'io.toutiao.android.ui.activity.MainActivity'
# 聲明我們的driver對象
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
# 打開通知欄
driver.open_notifications()
# 獲取時間 id
value = driver.find_element_by_id("com.android.systemui:id/date_expanded").text
print("時間爲:", value)
time.sleep(2)
driver.quit()
獲取⼿機當前⽹絡
from appium import webdriver
import time
# server 啓動參數
from appium.webdriver.common.touch_action import TouchAction
desired_caps = {}
# 設備信息
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.56.101:5555'
# app的信息
desired_caps['appPackage'] = 'com.android.settings'
desired_caps['appActivity'] = '.Settings'
# 聲明我們的driver對象
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
# 打印手機網絡狀態
print("當前網絡爲:", driver.network_connection)
# 修改手機網絡 data
driver.set_network_connection(4)
# 打印手機網絡狀態
print("當前網絡爲:", driver.network_connection)
# 修改手機網絡
driver.set_network_connection(2)
# 打印手機網絡狀態
print("當前網絡爲:", driver.network_connection)
# 修改手機網絡
driver.set_network_connection(1)
# 打印手機網絡狀態
print("當前網絡爲:", driver.network_connection)
time.sleep(2)
driver.quit()
⼿機截圖
from appium import webdriver
import time
# server 啓動參數
from appium.webdriver.common.touch_action import TouchAction
desired_caps = {}
# 設備信息
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '5.1'
desired_caps['deviceName'] = '192.168.56.101:5555'
# app的信息
desired_caps['appPackage'] = 'com.android.settings'
desired_caps['appActivity'] = '.Settings'
# 聲明我們的driver對象
driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
# 截圖
driver.get_screenshot_as_file("{}.png".format(int(time.time()))) # 1583378495 不加int:1583378546.1369514
time.sleep(2)
driver.quit()