安卓手机 Python 自动化( uiautomation、uiautomation2、weditor )
其他自動(dòng)化工具或者框架:
- Airtest:https://airtest.readthedocs.io/zh_CN/latest/
- autojs:Auto.js快速入門實(shí)戰(zhàn)教程:https://zhuanlan.zhihu.com/p/90065914
- appium:https://blog.csdn.net/freeking101/article/details/107881979
AutomateIt、Automate、按鍵精靈、AutoJS 等 Android 自動(dòng)化工具有什么特點(diǎn)?:https://www.zhihu.com/question/59503646
1、uiautomation
From:https://blog.csdn.net/ma524654165/article/details/77686526
? ? ? ? 主要用到一個(gè) uiautomation 的開源框架,是一個(gè)國(guó)人用 Python 封裝 Windows GUI (UI Automation) 而成的自動(dòng)化工具;
開源作者原文:http://www.cnblogs.com/Yinkaisheng/p/3444132.html
Github 地址:https://github.com/yinkaisheng/Python-UIAutomation-for-Windows
此自動(dòng)化的主要思想:利用此框架抓取到程序的各種句柄,然后對(duì)句柄執(zhí)行各種操作。
一、uiautomation 方法
- 1、WindowContrl(searchDepth,ClassName,SubName)
? ? ? ? 查找窗口中的程序,如果有中文則需用Unicode;可用window.Exists(maxSearchSeconds)來(lái)判斷此窗口是否存在; - 2、EditControl(searchFromControl)
? ? ? ? 查找編輯位置,找到后可用DoubleClick()來(lái)改變電腦的focus;edit.SetValue("string")輸入值; - 3、Win32API.SendKeys("string")?
? ? ? ? 如果已在編輯位置,則可用此方法來(lái)輸入值,{Ctrl}為ctrl鍵,其他類似;{@??8}格式可輸入8個(gè)@,
? ? ? ? 對(duì)于數(shù)字也可實(shí)現(xiàn)此功能,但對(duì)于字母不能...; - 4、MenuItemControl(searchFromControl,Name)???? ?????? ?????? 查找菜單按鈕;
- 5、ComboBoxControl(searchFromControl,AutomationI) ?????
? ? ? ? 查找下拉框,然后在此基礎(chǔ)上用Select("name")方法來(lái)選擇需要的選項(xiàng); - 6、BottonControl(searchFromControl,Name,SubName) ?????? 查找按鈕;
- 7、automation.FindControl(firefoxWindow,lambda c:(isinstance(c, automation.EditControl) or isinstance(c, automation.ComboBoxControl)) and c.Name == 'Enter your search term')? ?按條件搜索handle
二、對(duì)找到句柄常用操作
- Click()??????????? 點(diǎn)擊;
- RighClik()?????? 右鍵點(diǎn)擊;
- SendKeys()???? 發(fā)送字符;
- SetValue()????? 傳值,一般對(duì)EditControl用;
三、對(duì) windows 程序常用操作
- subprocess.Popen('Name')? 用進(jìn)程打開程序;
- window.Close()???? 關(guān)閉窗口;
- window.SetActive()?????? 使用;
- window.SetTopMost()?? 設(shè)置為頂層
- window.ShowWindow(uiautomation.ShowWindow.Maximize)? 窗口最大化
- window.CaptureToImage('Notepad.png')? 截圖;
- uiautomation.Win32API.PressKey(uiautomation.Keys.VK_CONTROL)??? 按住Ctrl鍵
- uiautomation.Win32API.ReleaseKey(uiautomation.Keys.VK_CONTROL) 釋放Ctrl鍵
- automation.GetConsoleWindow()????? #return console window that runs python,打開控制臺(tái)
- automation.Logger.ColorfulWriteLine('\nI will open <Color=Green>Notepad</Color> and <Color=Yellow>automate</Color> it. Please wait for a while.')? 控制臺(tái)傳值(彩色字體),普通傳值用WriteLine;
- automation.ShowDesktop() 顯示桌面;
四、句柄的抓取
直接運(yùn)行 automation 模塊枚舉窗口時(shí),支持下列參數(shù)(從 doc 窗口運(yùn)行 automation.py 程序 ):
-t intValue???? 延遲枚舉時(shí)間,單位秒 -r??????????????從樹的根部枚舉,如果不指定,從當(dāng)前窗口枚舉 -d intValue??? 枚舉控件樹的的深度,如果不指定,枚舉整個(gè)樹 -f??????????????從焦點(diǎn)控件枚舉,如果不指定,從當(dāng)前窗口枚舉 -c??????????????從光標(biāo)下的控件枚舉,如果不指定,從當(dāng)前窗口枚舉 -a??????????????獲取光標(biāo)下控件及其所有父控件 -n??????????????顯示控件的完整Name, 如果不指定,只顯示前30個(gè)字符 -m??????????????顯示控件更多屬性,默認(rèn)只顯示控件的四個(gè)屬性示例:
automation.pyc –t3, 3秒后枚舉當(dāng)前窗口所有控件 automation.pyc –d2 –t3, 3秒后枚舉當(dāng)前窗口前三層控件 automation.pyc –r –d1 –t0 -n, 0秒后從根部枚舉前兩層控件,并顯示控件完整名稱 automation.pyc –c –t3, 3秒后顯示鼠標(biāo)光標(biāo)下面的控件信息2、UIAutomator2
參考
- :https://vic.kim/2019/05/20/UIAutomator2的使用/
- :https://blog.csdn.net/d1240673769/article/details/113809889
uiautomator2 是一個(gè)可以使用 Python 對(duì) Android 設(shè)備進(jìn)行UI自動(dòng)化的庫(kù)。其底層基于 Google uiautomator,Google 提供的 uiautomator 庫(kù)可以獲取屏幕上任意一個(gè) APP 的任意一個(gè)控件屬性,并對(duì)其進(jìn)行任意操作。
uiautomator2 不是 android SDK 下的 uiautomator,而是一個(gè) python 庫(kù),用于 Android 的 ui 自動(dòng)化測(cè)試。使用 uiautomator2 只能用于?android 端測(cè)試,不像 appium 可以跨平臺(tái)可用于 ios 端。使用 uiautomator2 可以使用 wifi 或數(shù)據(jù)線和手機(jī)相連。
GitHub地址:https://github.com/openatx/uiautomator2
? ? ? ? ? ? https://github.com/openatx/uiautomator2/blob/master/README.md
工作原理:
如圖所示,python-uiautomator2 主要分為兩個(gè)部分,python 客戶端,移動(dòng)設(shè)備
- Python端:運(yùn)行腳本,并向移動(dòng)設(shè)備發(fā)送 HTTP 請(qǐng)求
- 移動(dòng)設(shè)備:移動(dòng)設(shè)備上運(yùn)行了封裝了 uiautomator2 的 HTTP 服務(wù),解析收到的請(qǐng)求,并轉(zhuǎn)化成 uiautomator2 的代碼。
整個(gè)過程
安裝 uiautomator2
pip install --pre uiautomator2?
pip install pillow (如果需要截圖,可安裝這個(gè)庫(kù))
設(shè)備安裝 atx-agent
首先設(shè)備連接到 PC,并能夠 adb devices 發(fā)現(xiàn)該設(shè)備。
執(zhí)行下面的命令
然后就會(huì)自動(dòng)安裝庫(kù)所需要的設(shè)備端程序:uiautomator-server,atx-agent,openstf / minicap,openstf / minitouch。 最后提示 success,代表 atx-agent 初始化成功。
安裝 weditor
有了這個(gè),方便我們快速的識(shí)別手機(jī)上的元素,方便寫代碼
pip install -U weditor安裝好之后,就可以在命令行運(yùn)行?weditor --help?確認(rèn)是否安裝成功了。Windows 系統(tǒng)可以使用命令在桌面創(chuàng)建一個(gè)快捷方式:weditor --shortcut??,在 windows cmd 中執(zhí)行上述命令后,會(huì)在桌面上創(chuàng)建一個(gè)快捷方式,如下圖:
安裝 weditor 報(bào)錯(cuò) UnicodeDecodeError 時(shí),可以安裝老版本:pip install weditor==0.6.3
啟動(dòng)方法
- 方法 1:命令行執(zhí)行?weditor?會(huì)自動(dòng)打開瀏覽器,輸入 設(shè)備的IP?或者 序列號(hào)( 序列號(hào)可以通過 adb devices 命令查看得到?),然后點(diǎn)擊 Connect
- 方法 2:桌面上雙擊 WEditor 快捷方式即可。
- 方法 3:命令行中執(zhí)行?python -m weditor
啟動(dòng)后如下圖:
應(yīng)用以及操作
調(diào)用 uiautomator2 的過程
配置手機(jī)設(shè)備參數(shù),設(shè)置具體操作的是哪一臺(tái)手機(jī)
抓取手機(jī)上應(yīng)用的控件,制定對(duì)應(yīng)的控件來(lái)進(jìn)行操作
對(duì)抓取到的控件進(jìn)行操作,比如點(diǎn)擊、填寫參數(shù)等。
設(shè)備連接方法,有兩種:
python-uiautomator2 連接手機(jī)的方式有兩種,
- 一種是通過WIFI。WIFI 最便利的地方是可以不用連接數(shù)據(jù)線
- 一種是通過USB。USB則可以用在PC和手機(jī)網(wǎng)絡(luò)不在一個(gè)網(wǎng)段用不了的情況。
(1)通過WiFi,假設(shè)設(shè)備IP 192.168.0.107和您的PC在同一網(wǎng)絡(luò)中
import uiautomator2 as u2 d = u2.connect('192.168.0.107')(2)通過USB, 假設(shè)設(shè)備序列是123456789F
import uiautomator2 as u2 d = u2.connect('123456789F') # USB鏈接設(shè)備。或者u2.connect_usb('123456f') #d = u2.connect_usb() 或者 d = u2.connect() ,當(dāng)前只有一個(gè)設(shè)備時(shí)可以用這個(gè)在沒有參數(shù)的情況下調(diào)用 u2.connect(), uiautomator2 將從環(huán)境變量 ANDROID_DEVICE_IP 獲取設(shè)備 IP。如果這個(gè)環(huán)境變量是空的,uiautomator 將返回 connect_usb,您需要確保只有一個(gè)設(shè)備連接到計(jì)算機(jī)。
檢查并維持設(shè)備端守護(hù)進(jìn)程處于運(yùn)行狀態(tài):
d.healthcheck()打開調(diào)試開關(guān):
d.debug = True d.info安裝應(yīng)用,只能從URL安裝:
d.app_install('http://some-domain.com/some.apk') #引號(hào)內(nèi)為下載apk地址啟動(dòng)應(yīng)用:
d.app_start('com.eg.android.AlipayGphone') #引號(hào)內(nèi)為包名稱,這里為支付寶停止應(yīng)用:
#相當(dāng)于'am force-stop'強(qiáng)制停止應(yīng)用 d.app_stop('com.eg.android.AlipayGphone') #相當(dāng)于'pm clear' 清空App數(shù)據(jù) d.app_clear('com.eg.android.AlipayGphone')停止所有正在運(yùn)行的應(yīng)用程序:
# 停止所有 d.app_stop_all()# 停止所有應(yīng)用程序,除了com.examples.demo d.app_stop_all(excludes=['com.examples.demo'])跳過彈窗,禁止彈窗:
d.disable_popups() # 自動(dòng)跳過彈出窗口 d.disable_popups(False) # 禁用自動(dòng)跳過彈出窗獲取設(shè)備信息:
# 獲取基本信息 d.info# 獲取窗口大小 print(d.window_size()) # 設(shè)備垂直輸出示例: (1080, 1920) # 設(shè)備水平輸出示例: (1920, 1080)# 獲取當(dāng)前應(yīng)用程序信息。對(duì)于某些android設(shè)備,輸出可以為空 print(d.current_app())#獲取設(shè)備序列號(hào) print(d.serial)#獲取WIFI IP print(d.wlan_ip)#獲取詳細(xì)的設(shè)備信息 print(d.device_info)獲取應(yīng)用信息:
d.app_info("com.eg.android.AlipayGphone") # 會(huì)輸出 ''' {"packageName": "com.eg.android.AlipayGphone", "mainActivity": "com.eg.android.AlipayGphone.AlipayLogin", "label": "支付寶", "versionName": "10.2.13.9020", "versionCode": 360, "size": 108306104 } ''' # 保存應(yīng)用程序圖標(biāo) img = d.app_icon("com.eg.android.AlipayGphone") img.save("icon.png")推拉文件:
(1)將文件推送到設(shè)備
# push文件夾 d.push("foo.txt", "/sdcard/") # push和重命名 d.push("foo.txt", "/sdcard/bar.txt") # push fileobj with open("foo.txt", 'rb') as f:d.push(f, "/sdcard/") # 推動(dòng)和更改文件訪問模式 d.push("foo.sh", "/data/local/tmp/", mode=0o755)(2)從設(shè)備中拉出一個(gè)文件
d.pull("/sdcard/tmp.txt", "tmp.txt")# 如果在設(shè)備上找不到文件,FileNotFoundError將引發(fā) d.pull("/sdcard/some-file-not-exists.txt", "tmp.txt")關(guān)鍵事件 ( 屏幕、鍵盤?操作?):
(1)打開/關(guān)閉屏幕
d.screen_on()#打開屏幕 d.screen_off() #關(guān)閉屏幕(2)獲取當(dāng)前屏幕狀態(tài)
d.info.get('screenOn') # 需要 Android> = 4.4(3)硬鍵盤和軟鍵盤操作
d.press("home") # 點(diǎn)擊home鍵 d.press("back") # 點(diǎn)擊back鍵 d.press("left") # 點(diǎn)擊左鍵 d.press("right") # 點(diǎn)擊右鍵 d.press("up") # 點(diǎn)擊上鍵 d.press("down") # 點(diǎn)擊下鍵 d.press("center") # 點(diǎn)擊選中 d.press("menu") # 點(diǎn)擊menu按鍵 d.press("search") # 點(diǎn)擊搜索按鍵 d.press("enter") # 點(diǎn)擊enter鍵 d.press("delete") # 點(diǎn)擊刪除按鍵 d.press("recent") # 點(diǎn)擊近期活動(dòng)按鍵 d.press("volume_up") # 音量+ d.press("volume_down") # 音量- d.press("volume_mute") # 靜音 d.press("camera") # 相機(jī) d.press("power") #電源鍵(4)解鎖屏幕
d.unlock() # 相當(dāng)于 # 1. 發(fā)射活動(dòng):com.github.uiautomator.ACTION_IDENTIFY # 2. 按home鍵手勢(shì)與設(shè)備的交互:
# 單擊屏幕 d.click(x,y) # x,y為點(diǎn)擊坐標(biāo)# 雙擊屏幕 d.double_click(x,y) d.double_click(x,y,0.1) # 默認(rèn)兩個(gè)單擊之間間隔時(shí)間為0.1秒# 長(zhǎng)按 d.long_click(x,y) d.long_click(x,y,0.5) # 長(zhǎng)按0.5秒(默認(rèn))# 滑動(dòng) d.swipe(sx, sy, ex, ey) d.swipe(sx, sy, ex, ey, 0.5) #滑動(dòng)0.5s(default)#拖動(dòng) d.drag(sx, sy, ex, ey) d.drag(sx, sy, ex, ey, 0.5)#拖動(dòng)0.5s(default) # 滑動(dòng)點(diǎn) 多用于九宮格解鎖,提前獲取到每個(gè)點(diǎn)的相對(duì)坐標(biāo)(這里支持百分比)# 從點(diǎn)(x0, y0)滑到點(diǎn)(x1, y1)再滑到點(diǎn)(x2, y2) # 兩點(diǎn)之間的滑動(dòng)速度是0.2秒 d.swipe((x0, y0), (x1, y1), (x2, y2), 0.2) # 注意:單擊,滑動(dòng),拖動(dòng)操作支持百分比位置值。例: d.long_click(0.5, 0.5) 表示長(zhǎng)按屏幕中心XPath:
# 檢索方向 d.orientation # 檢索方向。輸出可以是 "natural" or "left" or "right" or "upsidedown"# 設(shè)置方向 d.set_orientation("l") # or "left" d.set_orientation("r") # or "right" d.set_orientation("n") # or "natural"#凍結(jié)/ 開啟旋轉(zhuǎn) d.freeze_rotation() # 凍結(jié)旋轉(zhuǎn) d.freeze_rotation(False) # 開啟旋轉(zhuǎn)########## 截圖 ############ # 截圖并保存到電腦上的一個(gè)文件中,需要Android>=4.2。 d.screenshot("home.jpg")# 得到PIL.Image格式的圖像. 但你必須先安裝pillow image = d.screenshot() # default format="pillow" image.save("home.jpg") # 或'home.png',目前只支持png 和 jpg格式的圖像# 得到OpenCV的格式圖像。當(dāng)然,你需要numpy和cv2安裝第一個(gè) import cv2 image = d.screenshot(format='opencv') cv2.imwrite('home.jpg', image)# 獲取原始JPEG數(shù)據(jù) imagebin = d.screenshot(format='raw') open("some.jpg", "wb").write(imagebin)############################## 轉(zhuǎn)儲(chǔ)UI層次結(jié)構(gòu) # get the UI hierarchy dump content (unicoded).(獲取UI層次結(jié)構(gòu)轉(zhuǎn)儲(chǔ)內(nèi)容) d.dump_hierarchy()# 打開通知或快速設(shè)置 d.open_notification() #下拉打開通知欄 d.open_quick_settings() #下拉打開快速設(shè)置欄# 檢查特定的UI對(duì)象是否存在 d(text="Settings").exists # 返回布爾值,如果存在則為True,否則為False d.exists(text="Settings") # 另一種寫法 # 高級(jí)用法 d(text="Settings").exists(timeout=3) # 等待'Settings'在3秒鐘出現(xiàn)# 獲取特定UI對(duì)象的信息 d(text="Settings").info# 獲取/設(shè)置/清除可編輯字段的文本(例如EditText小部件) d(text="Settings").get_text() #得到文本小部件 d(text="Settings").set_text("My text...") #設(shè)置文本 d(text="Settings").clear_text() #清除文本# 獲取Widget中心點(diǎn) d(text="Settings").center() #d(text="Settings").center(offset=(0, 0)) # 基準(zhǔn)位置左前UI 對(duì)象 的 五種 定位方式:
# text、resourceId、description、className、xpath、坐標(biāo)# 執(zhí)行單擊UI對(duì)象 #text定位單擊 d(text="Settings").click() d(text="Settings", className="android.widget.TextView").click()#resourceId定位單擊 d(resourceId="com.ruguoapp.jike:id/tv_title", className="android.widget.TextView").click() #description定位單擊 d(description="設(shè)置").click() d(description="設(shè)置", className="android.widget.TextView").click()#className定位單擊 d(className="android.widget.TextView").click()#xpath定位單擊 d.xpath("//android.widget.FrameLayout[@index='0']/android.widget.LinearLayout[@index='0']").click()#坐標(biāo)單擊 d.click(182, 1264)# 等待元素出現(xiàn)(最多10秒),出現(xiàn)后單擊 d(text="Settings").click(timeout=10) # 在10秒時(shí)點(diǎn)擊,默認(rèn)的超時(shí)0 d(text='Skip').click_exists(timeout=10.0) # 單擊直到元素消失,返回布爾 d(text="Skip").click_gone(maxretry=10, interval=1.0) # maxretry默認(rèn)值10,interval默認(rèn)值1.0 # 點(diǎn)擊基準(zhǔn)位置偏移 d(text="Settings").click(offset=(0.5, 0.5)) # 點(diǎn)擊中心位置,同d(text="Settings").click() d(text="Settings").click(offset=(0, 0)) # 點(diǎn)擊左前位置 d(text="Settings").click(offset=(1, 1)) # 點(diǎn)擊右下# 執(zhí)行雙擊UI對(duì)象 d(text="設(shè)置").double_click() # 雙擊特定ui對(duì)象的中心 d.double_click(x, y, 0.1) # 兩次單擊之間的默認(rèn)持續(xù)時(shí)間為0.1秒#執(zhí)行長(zhǎng)按UI對(duì)象 # 長(zhǎng)按特定UI對(duì)象的中心 d(text="Settings").long_click() d.long_click(x, y, 0.5) # 長(zhǎng)按坐標(biāo)位置0.5s默認(rèn)# 將UI對(duì)象拖向另一個(gè)點(diǎn)或另一個(gè)UI對(duì)象 # Android<4.3不能使用drag. # 在0.5秒內(nèi)將UI對(duì)象拖到屏幕點(diǎn)(x, y) d(text="Settings").drag_to(x, y, duration=0.5)# 將UI對(duì)象拖到另一個(gè)UI對(duì)象的中心位置,時(shí)間為0.25秒 d(text="Settings").drag_to(text="Clock", duration=0.25)常見用法:
# 等待10s d.xpath("//android.widget.TextView").wait(10.0)# 找到并單擊 d.xpath("//*[@content-desc='分享']").click()# 檢查是否存在 if d.xpath("//android.widget.TextView[contains(@text, 'Se')]").exists:print("exists")# 獲取所有文本視圖文本、屬性和中心點(diǎn) for elem in d.xpath("//android.widget.TextView").all():print("Text:", elem.text)#獲取視圖文本 for elem in d.xpath("//android.widget.TextView").all():print("Attrib:", elem.attrib)#獲取屬性和中心點(diǎn) #返回: (100, 200) for elem in d.xpath("//android.widget.TextView").all():print("Position:", elem.center())# xpath常見用法: # 所有元素 //*# resource-id包含login字符 //*[contains(@resource-id, 'login')]# 按鈕包含賬號(hào)或帳號(hào) //android.widget.Button[contains(@text, '賬號(hào)') or contains(@text, '帳號(hào)')]# 所有ImageView中的第二個(gè) (//android.widget.ImageView)[2]# 所有ImageView中的最后一個(gè) (//android.widget.ImageView)[last()]# className包含ImageView //*[contains(name(), "ImageView")]會(huì)在瀏覽器中打開網(wǎng)頁(yè),輸入設(shè)備 devices 信息 可以 通過 adb devices 來(lái)進(jìn)行查詢?cè)O(shè)備 信息。出現(xiàn)樹的模樣,代表鏈接上手機(jī),然后點(diǎn)擊右上角的 Reload 實(shí)時(shí)顯示手機(jī)頁(yè)面。 這樣就可以開始你的元素定位了。
通用的元素定位方式。
- (1) 根據(jù)文本進(jìn)行定位:d(text=顯示的文本).click()
- (2) 通過 resourceId 進(jìn)行定位:d(resourceId="com.tcl.tclplus:id/cart_layout").click()
- (3) 滑動(dòng) 上 或者 下 。手指向上,就是頁(yè)面往下拉,分兩種情況 拉到底 或者 只拉一部分。
- 拉到底:d(scrollable=True).scroll.toEnd()
- 拉一部分:d.swipe(0.806, 0.801,0.818, 0.487) # 向上滑動(dòng) ?橫坐標(biāo)可以不變,縱坐標(biāo)是變化的,是變小的趨勢(shì) ?這是手指向上
- 拉倒頁(yè)面首頁(yè) 開頭部分:d(scrollable=True).scroll.toBeginning(steps=50)
- (4) 滑動(dòng) 左右?
????????d(scrollable=True).scroll.horiz.toEnd() #橫向滾動(dòng)到最右側(cè)
????????d(scrollable=True).scroll.horiz.toBeginning() #橫向滾動(dòng)到最左側(cè)
????或者
????????c.水平向右滾動(dòng):d(scrollable=True).scroll.horiz.forward(steps=50)
????????d.水平向左滾動(dòng):d(scrollable=True).scroll.horiz.backward(steps=50) - (5) 滑動(dòng)到指定位置:滑動(dòng)到文本為測(cè)試的位置:d(scrollable=True).scroll.to(text ='測(cè)試')
- (6) 元素判斷 ?可以這樣寫,通過判斷元素的存在性來(lái)執(zhí)行不同的操作 s = self.d(resourceId="com.tcl.tclplus:id/iot_txt_home_name", text=u"立即登錄", className="android.widget.TextView" ) if len(s) == 0:print('元素未找到,執(zhí)行退出操作')
- (7) 隨機(jī)字符串或者隨機(jī)字母 輸入 a = random.sample(string.ascii_letters, 4) data = ''.join([str(x) for x in a]) # 隨機(jī)從大小寫字母中取四位,然后寫入到輸入框中。 d(resourceId="com.tcl.tclplus:id/et_invoice_header").set_text(data)
- (8) 截圖 filepaths 就是截圖所存的路徑,可以自己填寫。filepaths = os.path.normpath(os.path.join(os.path.join(os.path.dirname(os.path.dirname(__file__)), "Automation/Tcase"))) def get_png(self, filename, filepath='/Member'):"""截圖操作,默認(rèn)截圖的存儲(chǔ)路徑為Member"""imgName = filename + datetime.datetime.now().strftime('%Y%m%d%H%M%S') + '.png' # 截圖可以單獨(dú)保存為別的名字的文件stringPath = filepaths + '/image' + filepath + '\\' + imgNameprint stringPath# img.save('filename.png')#圖片保存在當(dāng)前項(xiàng)目的文件夾下邊self.d.screenshot().save(stringPath) # 保存文件到指定的文件夾下邊self.get_png(filename='訂單-取消購(gòu)買'.decode('utf-8'), filepath='/Market/訂單') 實(shí)際調(diào)用的時(shí)候 需要進(jìn)行decode
- (9) apk 自動(dòng)安裝 def install_app(path):app_Path = lambda x: os.path.join(file_path, "app", x)apk = app_Path(path + ".apk")os.system('adb install -r -d ' + apk)time.sleep(5)
- (10) 報(bào)告生成 # 用例文件很多 采用 關(guān)鍵字匹配的方式進(jìn)行。def UI_Report(testcase, ReportPath):"""根據(jù)傳入的testcase 來(lái)判斷執(zhí)行哪種報(bào)告生成方式。"""def Report(s):@wraps(s)def creat_report():AA = hasattr(testcase,'__call__')# AA = isfunction(testcase)if AA:print '這個(gè)是函數(shù)'suite = unittest.makeSuite(testcase)fp = file(ReportPath, 'wb')runner = HTMLTestRunner(stream=fp, title=r'UI自動(dòng)化', description=r'接口自動(dòng)化測(cè)試報(bào)告')runner.run(suite) #區(qū)別fp.close()else:print '不是函數(shù),是執(zhí)行run_main方法'fp = file(ReportPath, 'wb')runner = HTMLTestRunner(stream=fp, title=r'UI自動(dòng)化測(cè)試報(bào)告', description=r'商城')runner.run(testcase)fp.close()return creat_reportreturn Reportdef all_case():testcase = unittest.TestSuite() # 加載測(cè)試套件# 用例的目錄,關(guān)鍵字進(jìn)行匹配discover = unittest.defaultTestLoader.discover(filepath, pattern='Market*.py', top_level_dir=None)testcase.addTest(discover)return testcase@UI_Report(testcase=all_case(),ReportPath=filepath+'/report/result.html')
def run():print '生成測(cè)試報(bào)告'if __name__ == '__main__':run()
因?yàn)?run_main 執(zhí)行的時(shí)候,是打印所有用例文件+名稱,而通過測(cè)試套件 添加 類名稱時(shí),執(zhí)行方式不一樣。至于公共函數(shù),比如啟動(dòng) app、一些共有的操作,可以寫到 公共函數(shù)中
?在unitest中 增加setupclass 函數(shù) 是只 啟動(dòng)一次app,跟setup 區(qū)別一下,下面增加你的公共函數(shù)。然后用例文件中 直接通過繼承的方式來(lái)進(jìn)行。
例如:class test(commons):
def del_file(filepath):listdir = os.listdir(filepath) # 獲取文件和子文件夾for rename in listdir:rename = filepath + "//" + renameif os.path.isfile(rename): # 是文件os.remove(rename) # 刪除文件elif os.path.isdir(rename): # 是子文件duellist = os.listdir(rename)for f in duellist: # 遍歷該子文件夾file_path = os.path.join(rename, f)if os.path.isfile(file_path): # 刪除子文件夾下文件os.remove(file_path)elif os.path.isdir(file_path): # 強(qiáng)制刪除子文件夾下的子文件夾shutil.rmtree(file_path)可以在用例文件執(zhí)行開頭增加一些 調(diào)用方法
如刪除截圖 和初始化 app環(huán)境 都是可以的??
3、pyautogui?
From:https://www.jb51.net/article/183926.htm
在使用 Python 做 安卓自動(dòng)化腳本 時(shí),兩個(gè)庫(kù)可以使用,一個(gè)為 PyUserInput 庫(kù),另一個(gè)為pyautogui 庫(kù)。就本人而言,我更喜歡使用pyautogui庫(kù),該庫(kù)功能多,使用便利。下面給大家介紹一下pyautogui庫(kù)的使用方法。在cmd命令框中輸入pip3 install pyautogui即可安裝該庫(kù)!
常用操作
我們?cè)?pyautogui 庫(kù)中常常使用的方法,如下:
import pyautogui# 調(diào)用在執(zhí)行動(dòng)作后暫停的秒數(shù),只能在執(zhí)行一些pyautogui動(dòng)作后才能使用,建議用time.sleep pyautogui.PAUSE = 1# 啟用自動(dòng)防故障功能,左上角的坐標(biāo)為(0,0),將鼠標(biāo)移到屏幕的左上角,來(lái)拋出failSafeException異常 pyautogui.FAILSAFE = True# 判斷(x,y)是否在屏幕上 x, y = 122, 244 pyautogui.onScreen(x, y) # 結(jié)果為truewidth, height = pyautogui.size() # 屏幕的寬度和高度 print(width, height)鼠標(biāo)操作
我們?cè)?pyautogui 庫(kù)對(duì)于鼠標(biāo)的使用方法大體如下:
import pyautoguicurrentMouseX, currentMouseY = pyautogui.position() # 鼠標(biāo)當(dāng)前位置 print(currentMouseX, currentMouseY)# 控制鼠標(biāo)移動(dòng),duration為持續(xù)時(shí)間 for i in range(2):pyautogui.moveTo(100, 100, duration=0.25) # 移動(dòng)到 (100,100)pyautogui.moveTo(200, 100, duration=0.25)pyautogui.moveTo(200, 200, duration=0.25)pyautogui.moveTo(100, 200, duration=0.25)for i in range(2):pyautogui.moveRel(50, 0, duration=0.25) # 從當(dāng)前位置右移100像素pyautogui.moveRel(0, 50, duration=0.25) # 向下pyautogui.moveRel(-50, 0, duration=0.25) # 向左pyautogui.moveRel(0, -50, duration=0.25) # 向上# 按住鼠標(biāo)左鍵,把鼠標(biāo)拖拽到(100, 200)位置 pyautogui.dragTo(100, 200, button='left') # 按住鼠標(biāo)左鍵,用2秒鐘把鼠標(biāo)拖拽到(300, 400)位置 pyautogui.dragTo(300, 400, 2, button='left') # 按住鼠標(biāo)左鍵,用0.2秒鐘把鼠標(biāo)向上拖拽 pyautogui.dragRel(0, -60, duration=0.2)# pyautogui.click( # x=moveToX, y=moveToY, clicks=num_of_clicks, # interval=secs_between_clicks, button='left' # ) # 其中,button屬性可以設(shè)置成left,middle和right。 pyautogui.click(10, 20, 2, 0.25, button='left') pyautogui.click(x=100, y=200, duration=2) # 先移動(dòng)到(100, 200)再單擊 pyautogui.click() # 鼠標(biāo)當(dāng)前位置點(diǎn)擊一下 pyautogui.doubleClick() # 鼠標(biāo)當(dāng)前位置左擊兩下 pyautogui.doubleClick(x=100, y=150, button="left") # 鼠標(biāo)在(100,150)位置左擊兩下 pyautogui.tripleClick() # 鼠標(biāo)當(dāng)前位置左擊三下pyautogui.mouseDown() # 鼠標(biāo)左鍵按下再松開 pyautogui.mouseUp() pyautogui.mouseDown(button='right') # 按下鼠標(biāo)右鍵 pyautogui.mouseUp(button='right', x=100, y=200) # 移動(dòng)到(100, 200)位置,然后松開鼠標(biāo)右鍵# scroll函數(shù)控制鼠標(biāo)滾輪的滾動(dòng),amount_to_scroll參數(shù)表示滾動(dòng)的格數(shù)。正數(shù)則頁(yè)面向上滾動(dòng),負(fù)數(shù)則向下滾動(dòng) # pyautogui.scroll(clicks=amount_to_scroll, x=moveToX, y=moveToY) pyautogui.scroll(5, 20, 2) pyautogui.scroll(10) # 向上滾動(dòng)10格 pyautogui.scroll(-10) # 向下滾動(dòng)10格 pyautogui.scroll(10, x=100, y=100) # 移動(dòng)到(100, 100)位置再向上滾動(dòng)10格# 緩動(dòng)/漸變函數(shù)可以改變光標(biāo)移動(dòng)過程的速度和方向。通常鼠標(biāo)是勻速直線運(yùn)動(dòng),這就是線性緩動(dòng)/漸變函數(shù)。 # PyAutoGUI有30種緩動(dòng)/漸變函數(shù),可以通過pyautogui.ease*?查看。 # 開始很慢,不斷加速 pyautogui.moveTo(100, 100, 2, pyautogui.easeInQuad) # 開始很快,不斷減速 pyautogui.moveTo(100, 100, 2, pyautogui.easeOutQuad) # 開始和結(jié)束都快,中間比較慢 pyautogui.moveTo(100, 100, 2, pyautogui.easeInOutQuad) # 一步一徘徊前進(jìn) pyautogui.moveTo(100, 100, 2, pyautogui.easeInBounce) # 徘徊幅度更大,甚至超過起點(diǎn)和終點(diǎn) pyautogui.moveTo(100, 100, 2, pyautogui.easeInElastic)對(duì)于我們要獲取鼠標(biāo)在屏幕中的位置,我們可以采用如下代碼:
# 案例獲取鼠標(biāo)的位置,方便復(fù)制我們定位的鼠標(biāo)坐標(biāo)點(diǎn)到代碼中 import pyautogui import time# 獲取鼠標(biāo)位置 def get_mouse_position():time.sleep(5) # 準(zhǔn)備時(shí)間print('開始獲取鼠標(biāo)位置')try:for i in range(10):# Get and print the mouse coordinates.x, y = pyautogui.position()positionStr = '鼠標(biāo)坐標(biāo)點(diǎn)(X,Y)為:{},{}'.format(str(x).rjust(4), str(y).rjust(4))pix = pyautogui.screenshot().getpixel((x, y)) # 獲取鼠標(biāo)所在屏幕點(diǎn)的RGB顏色positionStr += ' RGB:(' + str(pix[0]).rjust(3) + ',' + str(pix[1]).rjust(3) + ',' + str(pix[2]).rjust(3) + ')'print(positionStr)time.sleep(0.5) # 停頓時(shí)間except:print('獲取鼠標(biāo)位置失敗')if __name__ == "__main__":get_mouse_position()也可以使用pyautogui庫(kù)幫助文檔的方法,不過本人認(rèn)為使用上面的方法,更加便利。pyautogui庫(kù)幫助文檔的獲取鼠標(biāo)位置的方法如下:
import pyautoguiprint('Press Ctrl-C to quit.') try:while True:# Get and print the mouse coordinates.x, y = pyautogui.position()positionStr = 'X:' + str(x).rjust(4) + ' Y:' + str(y).rjust(4)pix = pyautogui.screenshot().getpixel((x, y)) # 獲取鼠標(biāo)所在屏幕點(diǎn)的RGB顏色positionStr += ' RGB:(' + str(pix[0]).rjust(3) + ',' + \str(pix[1]).rjust(3) + ',' + str(pix[2]).rjust(3) + ')'print(positionStr, end='') # end='' 替換了默認(rèn)的換行# 連續(xù)退格鍵并刷新,刪除之前打印的坐標(biāo),就像直接更新坐標(biāo)效果print('\b' * len(positionStr), end='', flush=True) except KeyboardInterrupt: # 處理 Ctrl-C 按鍵print('\nDone.')鍵盤操作
我們?cè)趐yautogui庫(kù)對(duì)于鍵盤的使用方法大體如下:
import pyautoguipyautogui.typewrite('Hello world!') # 輸入Hello world!字符串 pyautogui.typewrite('Hello world!', interval=0.25) # 每次輸入間隔0.25秒,輸入Hello world!pyautogui.press('enter') # 按下并松開(輕敲)回車鍵 pyautogui.press(['left', 'left', 'left', 'left']) # 按下并松開(輕敲)四下左方向鍵 pyautogui.keyDown('shift') # 按下`shift`鍵 pyautogui.keyUp('shift') # 松開`shift`鍵pyautogui.keyDown('shift') pyautogui.press('4') pyautogui.keyUp('shift') # 輸出 $ 符號(hào)的按鍵pyautogui.hotkey('ctrl', 'v') # 組合按鍵(Ctrl+V),粘貼功能,按下并松開'ctrl'和'v'按鍵# pyautogui.KEYBOARD_KEYS數(shù)組中就是press(),keyDown(),keyUp()和hotkey()函數(shù)可以輸入的按鍵名稱 pyautogui.KEYBOARD_KEYS = ['\t', '\n', '\r', ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.','/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@','[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l','m', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~','accept', 'add', 'alt', 'altleft', 'altright', 'apps', 'backspace', 'browserback','browserfavorites', 'browserforward', 'browserhome', 'browserrefresh', 'browsersearch','browserstop', 'capslock', 'clear', 'convert', 'ctrl', 'ctrlleft', 'ctrlright', 'decimal','del', 'delete', 'divide', 'down', 'end', 'enter', 'esc', 'escape', 'execute', 'f1', 'f10','f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17', 'f18', 'f19', 'f2', 'f20', 'f21', 'f22','f23', 'f24', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'final', 'fn', 'hanguel', 'hangul','hanja', 'help', 'home', 'insert', 'junja', 'kana', 'kanji', 'launchapp1', 'launchapp2','launchmail', 'launchmediaselect', 'left', 'modechange', 'multiply', 'nexttrack','nonconvert', 'num0', 'num1', 'num2', 'num3', 'num4', 'num5', 'num6', 'num7', 'num8', 'num9','numlock', 'pagedown', 'pageup', 'pause', 'pgdn', 'pgup', 'playpause', 'prevtrack', 'print','printscreen', 'prntscrn', 'prtsc', 'prtscr', 'return', 'right', 'scrolllock', 'select','separator', 'shift', 'shiftleft', 'shiftright', 'sleep', 'space', 'stop', 'subtract', 'tab','up', 'volumedown', 'volumemute', 'volumeup', 'win', 'winleft', 'winright', 'yen', 'command','option', 'optionleft', 'optionright' ]彈窗操作
我們?cè)?pyautogui 庫(kù)對(duì)于彈出窗口的使用方法大體如下:
import pyautogui# 顯示一個(gè)簡(jiǎn)單的帶文字和OK按鈕的消息彈窗。用戶點(diǎn)擊后返回button的文字。 pyautogui.alert(text='', title='', button='OK') b = pyautogui.alert(text='要開始程序么?', title='請(qǐng)求框', button='OK') print(b) # 輸出結(jié)果為OK# 顯示一個(gè)簡(jiǎn)單的帶文字、OK和Cancel按鈕的消息彈窗,用戶點(diǎn)擊后返回被點(diǎn)擊button的文字,支持自定義數(shù)字、文字的列表。 pyautogui.confirm(text='', title='', buttons=['OK', 'Cancel']) # OK和Cancel按鈕的消息彈窗 pyautogui.confirm(text='', title='', buttons=range(10)) # 10個(gè)按鍵0-9的消息彈窗 a = pyautogui.confirm(text='', title='', buttons=range(10)) print(a) # 輸出結(jié)果為你選的數(shù)字# 可以輸入的消息彈窗,帶OK和Cancel按鈕。用戶點(diǎn)擊OK按鈕返回輸入的文字,點(diǎn)擊Cancel按鈕返回None。 pyautogui.prompt(text='', title='', default='')# 樣式同prompt(),用于輸入密碼,消息用*表示。帶OK和Cancel按鈕。 # 用戶點(diǎn)擊OK按鈕返回輸入的文字,點(diǎn)擊Cancel按鈕返回None。 pyautogui.password(text='', title='', default='', mask='*')圖像操作
我們?cè)趐yautogui庫(kù)對(duì)于圖像的使用方法大體如下:
import pyautogui# 截全屏并設(shè)置保存圖片的位置和名稱 pyautogui.screenshot(r'C:\Users\ZDH\Desktop\PY\my_screenshot.png') # 截全屏并設(shè)置保存圖片的位置和名稱 im = pyautogui.screenshot(r'C:\Users\ZDH\Desktop\PY\my_screenshot.png') print(im) # 打印圖片的屬性# 不截全屏,截取區(qū)域圖片。截取區(qū)域region參數(shù)為:左上角XY坐標(biāo)值、寬度和高度 pyautogui.screenshot(r'C:\Users\ZDH\Desktop\PY\region_screenshot.png', region=(0, 0, 300, 400) )pix = pyautogui.screenshot().getpixel((220, 200)) # 獲取坐標(biāo)(220,200)所在屏幕點(diǎn)的RGB顏色 positionStr = ' RGB:(' + str(pix[0]).rjust(3) + ',' + \str(pix[1]).rjust(3) + ',' + str(pix[2]).rjust(3) + ')' print(positionStr) # 打印結(jié)果為RGB:( 60, 63, 65) pix = pyautogui.pixel(220, 200) # 獲取坐標(biāo)(220,200)所在屏幕點(diǎn)的RGB顏色與上面三行代碼作用一樣 positionStr = ' RGB:(' + str(pix[0]).rjust(3) + ',' + \str(pix[1]).rjust(3) + ',' + str(pix[2]).rjust(3) + ')' print(positionStr) # 打印結(jié)果為RGB:( 60, 63, 65)# 如果你只是要檢驗(yàn)一下指定位置的像素值,可以用pixelMatchesColor(x,y,RGB)函數(shù),把X、Y和RGB元組值穿入即可 # 如果所在屏幕中(x,y)點(diǎn)的實(shí)際RGB三色與函數(shù)中的RGB一樣就會(huì)返回True,否則返回False # tolerance參數(shù)可以指定紅、綠、藍(lán)3種顏色誤差范圍 pyautogui.pixelMatchesColor(100, 200, (255, 255, 255)) pyautogui.pixelMatchesColor(100, 200, (255, 255, 245), tolerance=10)# 獲得文件圖片在現(xiàn)在的屏幕上面的坐標(biāo),返回的是一個(gè)元組(top, left, width, height) # 如果截圖沒找到,pyautogui.locateOnScreen()函數(shù)返回None a = pyautogui.locateOnScreen(r'C:\Users\ZDH\Desktop\PY\region_screenshot.png') print(a) # 打印結(jié)果為Box(left=0, top=0, width=300, height=400) x, y = pyautogui.center(a) # 獲得文件圖片在現(xiàn)在的屏幕上面的中心坐標(biāo) print(x, y) # 打印結(jié)果為150 200# 這步與上面的四行代碼作用一樣 x, y = pyautogui.locateCenterOnScreen(r'C:\Users\ZDH\Desktop\PY\region_screenshot.png') print(x, y) # 打印結(jié)果為150 200# 匹配屏幕所有與目標(biāo)圖片的對(duì)象,可以用for循環(huán)和list()輸出 pyautogui.locateAllOnScreen(r'C:\Users\ZDH\Desktop\PY\region_screenshot.png') for pos in pyautogui.locateAllOnScreen(r'C:\Users\ZDH\Desktop\PY\region_screenshot.png'):print(pos) # 打印結(jié)果為Box(left=0, top=0, width=300, height=400) a = list(pyautogui.locateAllOnScreen(r'C:\Users\ZDH\Desktop\PY\region_screenshot.png')) print(a) # 打印結(jié)果為[Box(left=0, top=0, width=300, height=400)]參考資料
PyAutoGUI幫助文檔:
https://blog.csdn.net/qq_34053552/article/details/79776671
pyautogui圖形自動(dòng)化,擊敗重復(fù)性辦公任務(wù):
https://blog.csdn.net/qq_43017750/article/details/90575240
總結(jié)
以上是生活随笔為你收集整理的安卓手机 Python 自动化( uiautomation、uiautomation2、weditor )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网络云存储技术Windows serve
- 下一篇: python测试工具在线版_使用Dock