Python獲取安卓屏幕截圖的幾種方法

學了python之後想寫個手遊腳本練練手,碰到的第一個問題就是如何獲取手機屏幕的截圖,嘗試了幾種方法,這裏做一個總結,測試了幾種方法如下:

  1. adb獲取截圖,這是網上流傳最廣的方法。
    優點:簡單(實際上並沒有啥優勢)
    缺點:效率極低啊,獲取一張截圖需2~4秒。
  2. Minicap & Airtest方式
    優點:0.2秒獲取一張截圖,使用簡單
    缺點:需安裝第三方包
  3. 將手機投影到PC,獲取PC截圖
    優點:速度極快,0.04秒獲取一張截圖
    缺點:使用較複雜,PC和手機都需安裝軟件
  4. 採集手機屏幕,使用流媒體RTSP服務
    優點:讀取方便,採集頻率高
    缺點:延時高,1秒以上
  5. 備註
    獲取截圖是爲了獲取元素座標,可以通過Poco之類的方法直接獲取頁面佈局,這裏不做詳細介紹。

adb方式

adb應該是流傳最廣的方法了,原理是通過python調用系統命令,執行adb。

  1. 首先需準備adb工具,windows版本的百度網盤鏈接: https://pan.baidu.com/s/15azhmvrNBBDj6GcevFUZJg,提取碼: rs6a。
    adb工具不需要加入系統環境。
  2. 使用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秒就可以獲取一張截圖,但需要安裝軟件,每次都需要啓動軟件,比較麻煩。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章