學了python之後想寫個手遊腳本練練手,碰到的第一個問題就是如何獲取手機屏幕的截圖,嘗試了幾種方法,這裏做一個總結,測試了幾種方法如下:
- adb獲取截圖,這是網上流傳最廣的方法。
優點:簡單(實際上並沒有啥優勢)
缺點:效率極低啊,獲取一張截圖需2~4秒。- Minicap & Airtest方式
優點:0.2秒獲取一張截圖,使用簡單
缺點:需安裝第三方包- 將手機投影到PC,獲取PC截圖
優點:速度極快,0.04秒獲取一張截圖
缺點:使用較複雜,PC和手機都需安裝軟件- 採集手機屏幕,使用流媒體RTSP服務
優點:讀取方便,採集頻率高
缺點:延時高,1秒以上- 備註
獲取截圖是爲了獲取元素座標,可以通過Poco之類的方法直接獲取頁面佈局,這裏不做詳細介紹。
adb方式
adb應該是流傳最廣的方法了,原理是通過python調用系統命令,執行adb。
- 首先需準備adb工具,windows版本的百度網盤鏈接: https://pan.baidu.com/s/15azhmvrNBBDj6GcevFUZJg,提取碼: rs6a。
adb工具不需要加入系統環境。 - 使用adb截圖借用了PyMacro代碼。
import subprocess
import os
import sys
def pull_screenshot(img_path, SCREENSHOT_WAY):
if 1 <= SCREENSHOT_WAY <= 3:
process = subprocess.Popen(
'adb shell screencap -p',
shell=True, stdout=subprocess.PIPE)
binary_screenshot = process.stdout.read()
if SCREENSHOT_WAY == 2:
binary_screenshot = binary_screenshot.replace(b'\r\n', b'\n')
elif SCREENSHOT_WAY == 1:
binary_screenshot = binary_screenshot.replace(b'\r\r\n', b'\n')
lenb = len(binary_screenshot)
if lenb > 0:
f = open(img_path, 'wb')
f.write(binary_screenshot)
f.close()
else:
print("error! no screenshot data!")
elif SCREENSHOT_WAY == 0:
screenshot_name = "screenshot.png"
os.system('adb shell screencap -p /sdcard/{}'.format(screenshot_name))
os.system('adb pull /sdcard/{} {}'.format(screenshot_name, img_path))
SCREENSHOT_WAY = 0時,先截圖保存於手機端,再傳輸到電腦。
SCREENSHOT_WAY = 1、2、3時,使用subprocess.Popen()直接獲取圖片數據,因此效率高一些,但有些手機無法使用,使用什麼方式需根據手機進行測試。
圖片會保存到img_path,有時需對圖片進行處理,可以直接將獲取的圖片轉換爲opencv的numpy格式,使用如下:
import subprocess
import os
import cv2
import numpy as np
def check_screenshot():
for i in range(4):
if pull_screenshot(3-i) is not None:
return 3-i
def pull_screenshot(SCREENSHOT_WAY):
if 1 <= SCREENSHOT_WAY <= 3:
process = subprocess.Popen(
'adb shell screencap -p',
shell=True, stdout=subprocess.PIPE)
image_bytes = process.stdout.read(30000000)
if SCREENSHOT_WAY == 2:
image_bytes = image_bytes.replace(b'\r\n', b'\n')
elif SCREENSHOT_WAY == 1:
image_bytes = image_bytes.replace(b'\r\r\n', b'\n')
img = cv2.imdecode(np.fromstring(image_bytes, np.uint8), cv2.IMREAD_COLOR)
return img
elif SCREENSHOT_WAY == 0:
screenshot_name = "screenshot.png"
os.system('adb shell screencap -p /sdcard/{}'.format(screenshot_name))
os.system('adb pull /sdcard/{} {}'.format(screenshot_name, 'screenshot.png'))
img = cv2.imread('screenshot.png')
return img
else:
return None
Minicap & Airtest方式
adb方式實在太慢,Airtest是網易的跨平臺UI自動化測試編輯器,Airtest使用了Minicap獲取屏幕截圖。Airtest提供了IDE,配置相關環節較爲方便,也可以只安裝Airtest的python包,使用 pip 來安裝包。
pip install -U airtest
獲取截圖的方式如下:
from airtest.core.api import *
snapshot('screenshot.png')
也可以直接使用Minicap獲取截圖:
from airtest.core.api import *
from airtest.core.android.minicap import *
import cv2
import numpy as np
adb = connect_device("Android:///").adb
cap = Minicap(adb)
image_bytes = cap.get_frame_from_stream()
img = cv2.imdecode(np.fromstring(image_bytes, np.uint8), cv2.IMREAD_COLOR)
流媒體RTSP服務
採集手機屏幕,使用流媒體RTSP服務,這樣可以直接使用opencv讀取。
import cv2
cap = cv2.VideoCapture('rstp://xxx.xxx.xxx.xxxx:xxxx') #RTSP服務地址
while True:
ret, img = cap.read()
但是怎麼使用流媒體RTSP服務呢,有一個軟件EasyScreenLive,可以將手機屏幕和攝像頭採集生成流媒體RTSP服務。缺點是延時很高,1s多吧。
將手機投影到PC,獲取PC截圖
這是一種妥協,但這是我找到的效率最高的方法。我使用了TC Games,可以將手機圖像實時的傳輸到電腦屏幕,高效的電腦截圖的方法在下一篇進行總結,0.04秒就可以獲取一張截圖,但需要安裝軟件,每次都需要啓動軟件,比較麻煩。