安卓模拟器
import datetime
import os
import random
import shutil
import time
from xml.dom.minidom import parseString
import socket
import sys
import aircv as ac
import cv2 as cv
import numpy as np
import read_file
import writelog
# 注意pc下的C:/Users/冯攀/Documents/雷电模拟器/Pictures/和安卓上面的/sdcard/Pictures/文件夹是相通的
class DnPlayer(object):
def __init__(self, info: list):
super(DnPlayer, self).__init__()
# 索引,标题,顶层窗口句柄,绑定窗口句柄,是否进入android,进程PID,VBox进程PID
self.index = int(info[0])
self.name = info[1]
self.top_win_handler = int(info[2])
self.bind_win_handler = int(info[3])
self.is_in_android = True if int(info[4]) == 1 else False
self.pid = int(info[5])
self.vbox_pid = int(info[6])
def is_running(self) -> bool:
return self.is_in_android
def __str__(self):
index = self.index
name = self.name
r = str(self.is_in_android)
twh = self.top_win_handler
bwh = self.bind_win_handler
pid = self.pid
vpid = self.vbox_pid
return "\nindex:%d name:%s top:%08X bind:%08X running:%s pid:%d vbox_pid:%d\n" % (
index, name, twh, bwh, r, pid, vpid)
def __repr__(self):
index = self.index
name = self.name
r = str(self.is_in_android)
twh = self.top_win_handler
bwh = self.bind_win_handler
pid = self.pid
vpid = self.vbox_pid
return "\nindex:%d name:%s top:%08X bind:%08X running:%s pid:%d vbox_pid:%d\n" % (
index, name, twh, bwh, r, pid, vpid)
class UserInfo(object):
def __init__(self, text: str = ""):
super(UserInfo, self).__init__()
self.info = dict()
if len(text) == 0:
return
self.__xml = parseString(text)
nodes = self.__xml.getElementsByTagName('node')
res_set = [
# 用户信息节点
]
name_set = [
'id', 'id', 'following', 'fans', 'all_like', 'rank', 'flex',
'signature', 'location', 'video', 'name'
]
number_item = ['following', 'fans', 'all_like', 'video', 'videolike']
for n in nodes:
name = n.getAttribute('resource-id')
if len(name) == 0:
continue
if name in res_set:
idx = res_set.index(name)
text = n.getAttribute('text')
if name_set[idx] not in self.info:
self.info[name_set[idx]] = text
print(name_set[idx], text)
elif idx == 9:
self.info['videolike'] = text
elif idx < 2:
if len(text) == 0:
continue
if self.info['id'] != text:
self.info['id'] = text
for item in number_item:
if item in self.info:
self.info[item] = int(self.info[item].replace('w', '0000').replace('.', ''))
def __str__(self):
return str(self.info)
def __repr__(self):
return str(self.info)
class Dnconsole:
# 请根据自己电脑配置
console = 'D:\\Changzhi\\dnplayer2\\dnconsole.exe '
ld = 'D:\\Changzhi\\dnplayer2\\ld.exe '
share_path = 'C:\\Users\\yys53\\OneDrive\\python\\bestscript\\screen_picture'
type = sys.getfilesystemencoding()
# 获取模拟器列表
@staticmethod
def get_list():
cmd = os.popen(Dnconsole.console + 'list2')
text = cmd.read()
cmd.close()
info = text.split('\n')
result = list()
for line in info:
if len(line) > 1:
dnplayer = line.split(',')
result.append(DnPlayer(dnplayer))
return result
# 获取正在运行的模拟器列表
@staticmethod
def list_running() -> list:
result = list()
all = Dnconsole.get_list()
for dn in all:
if dn.is_running() is True:
result.append(dn)
return result
# 检测指定序号的模拟器是否正在运行
@staticmethod
def is_running(index: int) -> bool:
all = Dnconsole.get_list()
if index >= len(all):
raise IndexError('%d is not exist' % index)
return all[index].is_running()
# 执行shell命令
@staticmethod
def dnld(index: int, command: str, silence: bool = True):
cmd = Dnconsole.ld + '-s %d %s' % (index, command)
if silence:
os.system(cmd)
return ''
process = os.popen(cmd)
result = process.read()
process.close()
return result
# 执行adb命令,不建议使用,容易失控
@staticmethod
def adb(index: int, command: str, silence: bool = False) -> str:
cmd = Dnconsole.console + 'adb --index %d --command "%s"' % (index, command)
if silence:
os.system(cmd)
return ''
process = os.popen(cmd)
result = process.read()
process.close()
return result
# 安装apk 指定模拟器必须已经启动
@staticmethod
def install(index: int, path: str):
shutil.copy(path, Dnconsole.share_path + str(index) + '/update.apk')
time.sleep(1)
Dnconsole.dnld(index, 'pm install /sdcard/Pictures/update.apk')
# 卸载apk 指定模拟器必须已经启动
@staticmethod
def uninstall(index: int, package: str):
cmd = Dnconsole.console + 'uninstallapp --index %d --packagename %s' % (index, package)
process = os.popen(cmd)
result = process.read()
process.close()
return result
# 启动App 指定模拟器必须已经启动
@staticmethod
def invokeapp(index: int, package: str):
cmd = Dnconsole.console + 'runapp --index %d --packagename %s' % (index, package)
process = os.popen(cmd)
result = process.read()
process.close()
print(result)
return result
# 停止App 指定模拟器必须已经启动
@staticmethod
def stopapp(index: int, package: str):
cmd = Dnconsole.console + 'killapp --index %d --packagename %s' % (index, package)
process = os.popen(cmd)
result = process.read()
process.close()
return result
# 输入文字
@staticmethod
def input_text(index: int, text: str):
cmd = Dnconsole.console + 'action --index %d --key call.input --value %s' % (index, text)
process = os.popen(cmd)
result = process.read()
process.close()
return result
# 获取安装包列表
@staticmethod
def get_package_list(index: int, silence: bool = True) -> list:
cmd = Dnconsole.ld + '-s %d pm list packages' % index
process = os.popen(cmd)
result = process.read()
process.close()
if silence:
os.system(cmd)
return result
return result
# 检测是否安装指定的应用
@staticmethod
def has_install(index: int, package: str):
if Dnconsole.is_running(index) is False:
return False
return package in Dnconsole.get_package_list(index)
# 启动模拟器
@staticmethod
def launch(index: int):
cmd = Dnconsole.console + 'launch --index ' + str(index)
process = os.popen(cmd)
result = process.read()
process.close()
return result
# 关闭模拟器
@staticmethod
def quit(index: int):
cmd = Dnconsole.console + 'quit --index ' + str(index)
process = os.popen(cmd)
result = process.read()
process.close()
return result
# 设置屏幕分辨率为1080×1920 下次启动时生效
@staticmethod
def set_screen_size(index: int):
cmd = Dnconsole.console + 'modify --index %d --resolution 1080,1920,480' % index
process = os.popen(cmd)
result = process.read()
process.close()
return result
# 点击或者长按某点
@staticmethod
def touch(index: int, x: int, y: int, delay: int = 0):
if delay == 0:
Dnconsole.dnld(index, 'input tap %d %d' % (x, y))
else:
Dnconsole.dnld(index, 'input touch %d %d %d' % (x, y, delay))
# 滑动
@staticmethod
def swipe(index, coordinate_leftup: tuple, coordinate_rightdown: tuple, delay: int = 0):
x0 = coordinate_leftup[0]
y0 = coordinate_leftup[1]
x1 = coordinate_rightdown[0]
y1 = coordinate_rightdown[1]
if delay == 0:
Dnconsole.dnld(index, 'input swipe %d %d %d %d' % (x0, y0, x1, y1))
else:
Dnconsole.dnld(index, 'input swipe %d %d %d %d %d' % (x0, y0, x1, y1, delay))
# 复制模拟器,被复制的模拟器不能启动
@staticmethod
def copy(name: str, index: int = 0):
cmd = Dnconsole.console + 'copy --name %s --from %d' % (name, index)
process = os.popen(cmd)
result = process.read()
process.close()
return result
# 添加模拟器
@staticmethod
def add(name: str):
cmd = Dnconsole.console + 'add --name %s' % name
process = os.popen(cmd)
result = process.read()
process.close()
return result
# 设置自动旋转
@staticmethod
def auto_rate(index: int, auto_rate: bool = False):
rate = 1 if auto_rate else 0
cmd = Dnconsole.console + 'modify --index %d --autorotate %d' % (index, rate)
process = os.popen(cmd)
result = process.read()
process.close()
return result
# 改变设备信息 imei imsi simserial androidid mac值
@staticmethod
def change_device_data(index: int):
# 改变设备信息
cmd = Dnconsole.console + 'modify --index %d --imei auto --imsi auto --simserial auto --androidid auto --mac auto' % index
process = os.popen(cmd)
result = process.read()
process.close()
return result
# 改变CPU数量
@staticmethod
def change_cpu_count(index: int, number: int):
# 修改cpu数量
cmd = Dnconsole.console + 'modify --index %d --cpu %d' % (index, number)
process = os.popen(cmd)
result = process.read()
process.close()
return result
@staticmethod
def get_cur_activity_xml(index: int):
# 获取当前activity的xml信息
Dnconsole.dnld(index, 'uiautomator dump /sdcard/Pictures/activity.xml')
time.sleep(1)
f = open(Dnconsole.share_path + '/activity.xml', 'r', encoding='utf-8')
result = f.read()
f.close()
return result
@staticmethod
def get_user_info(index: int) -> UserInfo:
xml = Dnconsole.get_cur_activity_xml(index)
usr = UserInfo(xml)
if 'id' not in usr.info:
return UserInfo()
return usr
# 获取当前activity名称
@staticmethod
def get_activity_name(index: int):
text = Dnconsole.dnld(index, '"dumpsys activity top | grep ACTIVITY"', False)
text = text.split(' ')
for i, s in enumerate(text):
if len(s) == 0:
continue
if s == 'ACTIVITY':
return text[i + 1]
return ''
# 等待某个activity出现
@staticmethod
def wait_activity(index: int, activity: str, timeout: int) -> bool:
for i in range(timeout):
if Dnconsole.get_activity_name(index) == activity:
return True
time.sleep(1)
return False
# 找图
@staticmethod
def find_pic(screen: str, template: str, threshold: float):
try:
scr = cv.imread(screen)
tp = cv.imread(template)
result = cv.matchTemplate(scr, tp, cv.TM_SQDIFF_NORMED)
except cv.error:
print('文件错误:', screen, template)
time.sleep(1)
try:
scr = cv.imread(screen)
tp = cv.imread(template)
result = cv.matchTemplate(scr, tp, cv.TM_SQDIFF_NORMED)
except cv.error:
return False, None
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result)
print(max_val)
if min_val > threshold:
print(template, min_val, max_val, min_loc, max_loc)
return False, None
print(template, min_val, min_loc)
return True, min_loc
# 等待某个图片出现,然后点击
@staticmethod
def wait_picture(index: int, timeout: int, template: str) -> bool:
count = 0
while count < timeout:
Dnconsole.dnld(index, 'screencap -p /sdcard/Pictures/apk_scr.png')
time.sleep(2)
ret, loc = Dnconsole.find_pic(Dnconsole.share_path + '/apk_scr.png', template, 0.001)
if ret is False:
print(loc)
time.sleep(2)
count += 2
continue
print(loc)
# 点击
Dnconsole.touch(index, int(loc[0]), int(loc[1]), 0) # x和y相反
return loc
else:
return False
# 在当前屏幕查看模板列表是否存在,是返回存在的模板,如果多个存在,返回找到的第一个模板
@staticmethod
def check_picture(index: int, templates: list):
Dnconsole.dnld(index, 'screencap -p /sdcard/Pictures/apk_scr.png')
time.sleep(1)
for i, t in enumerate(templates):
ret, loc = Dnconsole.find_pic(Dnconsole.share_path + '/apk_scr.png', t, 0.001)
if ret is True:
return i, loc
return -1, None
@staticmethod
def open_url(index: int, url):
Dnconsole.dnld(index, "am start -a android.intent.action.VIEW -d %s" % url)
@staticmethod
def dnld_find_picture(index, imgobj, times, click=1):
"""
#循环找图或单次找图
:param index: 模拟器从0开始
:param imgobj: 图片名字,不带后缀
:param times: 找图次数
:param click:是否需要点击=1默认点击.其他不点击
"""
# 记录超时时间
start_time = time.time()
print("开始找图:%s,第一次获取总秒数=%d" % (imgobj, start_time))
i = 1
while i <= times:
a = random.randint(1, 5) / 10
print("随机数:%f" % a)
time.sleep(a) # 每隔查找一次
len_pic = read_file.file_list("C:\\Users\\yys53\\OneDrive\\python\\bestscript\\find_picture\\phone\\",
"(^" + imgobj + "\\d+.\\w+)") # ^是字符串开头
if len_pic: # 正则遍历图片个数,找几张图:图片都是名字+数字组成
print(len(len_pic))
for j in range(0, len(len_pic)):
pic = len_pic[j][0]
print(pic)
try:
# x和y传送两个值,所以可以这样写
Dnconsole.dnld(index, 'screencap -p /sdcard/Pictures/apk_scr.png')
imgsrc = Dnconsole.share_path + '\\apk_scr.png'
imsrc = ac.imread(imgsrc)
imobj = ac.imread(
"C:\\Users\\yys53\\OneDrive\\python\\bestscript\\find_picture\\phone\\" + pic)
match_result = ac.find_template(imsrc, imobj, 0.9) # 相似度大于0.9 才满足
if match_result is not None:
for i in match_result:
pass
print("图片:%s,坐标:%s,范围:%s,相似度:%s" % (
imgobj, match_result['result'], match_result['rectangle'], match_result['confidence']))
x = match_result['result'][0]
y = match_result['result'][1]
# 当前x y为识别图片的中心点,可以进行直接点击
if click == 1:
Dnconsole.touch(index, int(x), int(y), 0)
if x and y >= 0:
print("找到图片:%s,坐标:x=%s,y=%s,第%d张" % (imgobj, x, y, j + 1))
time.sleep(a)
writelog.write_file("找到图片:%s,坐标:x=%s,y=%s,第%d张" % (imgobj, x, y, j + 1))
return int(x), int(y)
except Exception as result:
print("未知错误%s" % result)
print("正在查找:%s,第%s次失败,正在进行%s次,第%d张" % (imgobj, i, i + 1, j + 1))
i += 1
else:
end_time = time.time()
spend_time = end_time - start_time
if times > 20: # 大于多少次后不用提示超时和截图
print("|超时|第%s次真的找不到,本次找图花费秒数=%d秒" % (i, spend_time))
writelog.write_file("|超时|第%s次,真的找不到:%s,,本次找图花费秒数=%d秒" % (i, imgobj, spend_time))
Dnconsole.timeout_screenshot(index, "超时截图,找%s," % imgobj)
return -1, -1
@staticmethod
def find_half_picture(index, imgobj, times, click=1):
"""
#循环找图或单次找图
:param index: 模拟器从0开始
:param imgobj: 图片名字,不带后缀
:param times: 找图次数
:param click:是否需要点击=1默认点击.其他不点击
"""
# 记录超时时间
start_time = time.time()
print("开始找图:%s,第一次获取总秒数=%d" % (imgobj, start_time))
i = 1
while i <= times:
a = random.randint(1, 5) / 10
print("随机数:%f" % a)
time.sleep(a) # 每隔查找一次
len_pic = read_file.file_list("C:\\Users\\yys53\\OneDrive\\python\\bestscript\\find_picture\\phone\\",
"(^" + imgobj + "\\d+.\\w+)") # ^是字符串开头
if len_pic: # 正则遍历图片个数,找几张图:图片都是名字+数字组成
print(len(len_pic))
for j in range(0, len(len_pic)):
pic = len_pic[j][0]
print(pic)
try:
# x和y传送两个值,所以可以这样写
Dnconsole.dnld(index, 'screencap -p /sdcard/Pictures/apk_scr'+str(index)+'.jpg')
imgsrc = Dnconsole.share_path + '\\half'+str(index)+'.jpg'
imsrc = ac.imread(imgsrc)
imobj = ac.imread(
"C:\\Users\\yys53\\OneDrive\\python\\bestscript\\find_picture\\phone\\" + pic)
match_result = ac.find_template(imsrc, imobj, 0.9) # 相似度大于0.9 才满足
if match_result is not None:
for i in match_result:
pass
print("图片:%s,坐标:%s,范围:%s,相似度:%s" % (
imgobj, match_result['result'], match_result['rectangle'], match_result['confidence']))
x = match_result['result'][0]
y = match_result['result'][1]
# 当前x y为识别图片的中心点,可以进行直接点击
if click == 1:
Dnconsole.touch(index, int(x), int(y), 0)
if x and y >= 0:
print("找到图片坐标:x=%d,y=%d,第%d张" % (x, y, j))
time.sleep(a)
writelog.write_file("找到图片坐标:x=%d,y=%d,第%d张" % (x, y, j))
return int(x), int(y)
except Exception as result:
print("未知错误%s" % result)
print("正在查找:%s,第%s次失败,正在进行%s次,第%d张" % (imgobj, i, i + 1, j))
i += 1
else:
end_time = time.time()
spend_time = end_time - start_time
if times > 20: # 大于多少次后不用提示超时和截图
print("|超时|第%s次真的找不到,本次找图花费秒数=%d秒" % (i, spend_time))
writelog.write_file("|超时|第%s次,真的找不到:%s,,本次找图花费秒数=%d秒" % (i, imgobj, spend_time))
Dnconsole.timeout_screenshot(index, "超时截图,找%s," % imgobj)
return -1, -1
@classmethod
def timeout_screenshot(cls, index, even):
"""
超时截图
:param even: 图片名字
"""
i = datetime.datetime.now()
date = ("%s年%02d月%02d日,%02d时%02d分%02d秒" % (i.year, i.month, i.day, i.hour, i.minute, i.second))
# print(date)
# 路径 = ('C:\\Users\\yys53\\OneDrive\\python\\bestscript\\screen_picture\\phonetimeout\\%s%s.png' % (even, date))
Dnconsole.dnld(index, 'screencap -p /sdcard/Pictures/phonetimeout/' + even + date + '.png')
@classmethod
def coin_screenshot(cls, index, even):
"""
超时截图
:param index: 模拟器名,从0开始
:param even: 图片名字
"""
# 路径= ('C:\\Users\\yys53\\OneDrive\\python\\bestscript\\screen_picture\\Android\\%s.png' % even)
Dnconsole.dnld(index, 'screencap -p /sdcard/Pictures/Android/' + even + '.png')
@staticmethod
def find_picture1(index, imgobj):
# 模板匹配
Dnconsole.dnld(index, 'screencap -p /sdcard/Pictures/apk_scr.png')
img_rgb = cv.imread(Dnconsole.share_path + '/apk_scr.png')
img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY)
template = cv.imread("C:\\Users\\yys53\\OneDrive\\python\\bestscript\\find_picture\\phone\\" + imgobj, 0)
h, w = template.shape[:2]
res = cv.matchTemplate(img_gray, template, cv.TM_CCOEFF_NORMED)
threshold = 0.9
# 取匹配程度大于%80的坐标
loc = np.where(res >= threshold)
print(res)
# np.where返回的坐标值(x,y)是(h,w),注意h,w的顺序
for pt in zip(*loc[::-1]):
bottom_right = (pt[0] + w, pt[1] + h)
print(bottom_right)
x, y = pt[0] + w / 2, pt[1] + h / 2 # 中心点
print("x=%d,y=%d" % (x, y))
cv.rectangle(img_rgb, pt, bottom_right, (0, 0, 255), 2)
Dnconsole.touch(index, int(y), int(x), 0) # x和y相反
# return int(x), int(y)
# cv.imshow('img_rgb', img_rgb)
# cv.waitKey(0)
@staticmethod
def aircv_multiple_find_picture(index, img, times, click="点击", back="不返回"):
"""
#循环找图或单次找图
:param index: 模拟器从0开始
:param img: 图片名字,不带后缀
:param times: 找图次数
:param click:是否需要点击图片
:param back:返回一次
"""
# 记录超时时间
start_time = time.time()
print("开始找图:%s,第一次获取总秒数=%d" % (img, start_time))
i = 1
while i <= times:
a = random.randint(1, 5) / 10
print("随机数:%f" % a)
time.sleep(a) # 每隔查找一次
Dnconsole.dnld(index, 'screencap -p /sdcard/Pictures/apk_scr.png')
for k in range(len(img)):
imgobj = img[k]
len_pic = read_file.file_list("C:\\Users\\yys53\\OneDrive\\python\\bestscript\\find_picture\\phone\\",
"(^" + imgobj + "\\d+.\\w+)") # ^是字符串开头
if len_pic: # 正则遍历图片个数,找几张图:图片都是名字+数字组成
print(len(len_pic))
for j in range(0, len(len_pic)):
pic = len_pic[j][0]
print(pic)
try:
# x和y传送两个值,所以可以这样写
imgsrc = Dnconsole.share_path + '\\apk_scr.png'
imsrc = ac.imread(imgsrc)
imobj = ac.imread(
"C:\\Users\\yys53\\OneDrive\\python\\bestscript\\find_picture\\phone\\" + pic)
match_result = ac.find_template(imsrc, imobj, 0.9, rgb=True) # 相似度大于0.9 才满足
if match_result is not None:
for i in match_result:
pass
print("找到图片:%s,坐标:%s,范围:%s,相似度:%s" % (
pic, match_result['result'], match_result['rectangle'],
match_result['confidence']))
writelog.write_file("找到图片:%s,坐标:%s,范围:%s,相似度:%s" % (
pic, match_result['result'], match_result['rectangle'],
match_result['confidence']))
time.sleep(a)
x = match_result['result'][0]
y = match_result['result'][1]
# 当前x y为识别图片的中心点,可以进行直接点击
if click == "点击":
Dnconsole.touch(index, int(x), int(y), 0)
return [int(x), int(y)], k
except Exception as result:
print("未知错误%s" % result)
print("正在查找:%s,第%s次失败,正在进行%s次,第%d张" % (imgobj, i, i + 1, j + 1))
if back == "返回":
print("返回一次")
time.sleep(1)
Dnconsole.dnld(index, "input keyevent BACK") # 返回
i += 1
else:
end_time = time.time()
spend_time = end_time - start_time
print("|超时|,模拟器%d,第%s次真的找不到,本次找图花费秒数=%d秒" % (index, i, spend_time))
return [-1, -1], -1
@staticmethod
def screen(index):
import win32gui
import win32ui
import win32con
from PIL import Image
# 获取后台窗口的句柄,注意后台窗口不能最小化
# 获取Pid(类名, 标题)
main_hwnd = win32gui.FindWindow("LDPlayerMainFrame", "雷电模拟器" + str(index)) # 获得父句柄
# 获取句柄窗口的大小信息
hwndChildList = []
win32gui.EnumChildWindows(main_hwnd, lambda hwnd, param: param.append(hwnd), hwndChildList)
hWnd = hwndChildList[0] # 子句柄的第一个句柄
# print(hWnd)
left, top, right, bot = win32gui.GetWindowRect(hWnd)
if right < 1100:
# 获取句柄窗口的大小信息
print("窗口太小,进行最大化")
win32gui.ShowWindow(main_hwnd, win32con.SW_MAXIMIZE)
hwndChildList = []
win32gui.EnumChildWindows(main_hwnd, lambda hwnd, param: param.append(hwnd), hwndChildList)
hWnd = hwndChildList[0] # 子句柄的第一个句柄
left, top, right, bot = win32gui.GetWindowRect(hWnd)
width = right - left
height = bot - top
# 返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框
hWndDC = win32gui.GetWindowDC(hWnd)
# 创建设备描述表
mfcDC = win32ui.CreateDCFromHandle(hWndDC)
# 创建内存设备描述表
saveDC = mfcDC.CreateCompatibleDC()
# 创建位图对象准备保存图片
saveBitMap = win32ui.CreateBitmap()
# 为bitmap开辟存储空间
saveBitMap.CreateCompatibleBitmap(mfcDC, width, height)
# 将截图保存到saveBitMap中
saveDC.SelectObject(saveBitMap)
# 保存bitmap到内存设备描述表
saveDC.BitBlt((0, 0), (width, height), mfcDC, (0, 0), win32con.SRCCOPY)
# 保存图像
# 方法二(第一部分):PIL保存
# # 获取位图信息
bmpinfo = saveBitMap.GetInfo()
bmpstr = saveBitMap.GetBitmapBits(True)
# 生成图像
im_PIL = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpstr, 'raw', 'BGRX', 0, 1)
im_PIL = im_PIL.resize((720, 1280), Image.ANTIALIAS) # 图片分辨率跳到720*1280
im_PIL.save('C:\\Users\\yys53\\OneDrive\\python\\bestscript\\screen_picture\\apk_scr'+str(index)+'.jpg') # 保存
@staticmethod
def multiple_find_picture(index, img, times, click="点击", back="不返回"):
"""
#循环找图或单次找图
:param index: 模拟器从0开始
:param img: 图片名字,不带后缀
:param times: 找图次数
:param click:是否需要点击图片
:param back:返回一次
"""
# 记录超时时间
hostname = socket.gethostname()
start_time = time.time()
# print("开始找图:%s,第一次获取总秒数=%d" % (img, start_time))
i = 1
while i <= times:
a = random.randint(1, 5) / 10
# print("随机数:%f" % a)
time.sleep(a) # 每隔查找一次
# 方法一:用pillow截图
# try:
# Dnconsole.screen(index)
# except Exception as result:
# writelog.write_file("截图出现问题%s" % result)
# 方法二:用雷电截图截图
Dnconsole.dnld(index, 'screencap -p /sdcard/Pictures/apk_scr%d-%s.jpg' % (index, hostname)) # 第几个模拟器就第几个截图
for k in range(len(img)):
imgobj = img[k]
len_pic = read_file.file_list("C:\\Users\\yys53\\OneDrive\\python\\bestscript\\find_picture\\phone\\",
"(^" + imgobj + "\\d+.\\w+)") # ^是字符串开头
# print(len_pic)
if len_pic: # 正则遍历图片个数,找几张图:图片都是名字+数字组成
# print(len(len_pic))
for j in range(0, len(len_pic)):
pic = len_pic[j][0]
# print(pic)
try:
# x和y传送两个值,所以可以这样写
imgsrc = Dnconsole.share_path + '\\apk_scr%d-%s.jpg' % (index, hostname) # 第几个模拟器就第几个截图
imsrc = cv.imread(imgsrc) # ,1表示原图加载彩色图片,0以灰度模式,包括alpha,可以直接写-1
imobj = cv.imread(
"C:\\Users\\yys53\\OneDrive\\python\\bestscript\\find_picture\\phone\\" + pic)
h, w = imobj.shape[:2] # 取彩色图片的高、宽
res = cv.matchTemplate(imsrc, imobj, cv.TM_CCOEFF_NORMED)
threshold = 0.9
# 取匹配程度大于%90的坐标
loc = np.where(res >= threshold)
# np.where返回的坐标值(x,y)是(h,w),注意h,w的顺序
for pt in zip(*loc[::-1]):
# bottom_right = (pt[0] + w, pt[1] + h)
# print(bottom_right)
x, y = pt[0] + w / 2, pt[1] + h / 2 # 中心点
# print("x=%d,y=%d" % (x, y))
if int(x) and int(y) >= 0:
print("[模拟器%d]找到图片%s坐标:x=%s,y=%s" % (index, pic, x, y))
writelog.write_file("[模拟器%d]找到图片%s坐标:x=%s,y=%s" % (index, pic, x, y))
time.sleep(a)
if click == "点击":
Dnconsole.touch(index, int(x), int(y), 0)
return [int(x), int(y)], k
except Exception as result:
# print("未知错误%s" % result)
pass
# print("正在查找:%s,第%s次失败,正在进行%s次,第%d张" % (imgobj, i, i + 1, j + 1))
if back == "返回":
print("返回一次")
time.sleep(1.5)
Dnconsole.dnld(index, "input keyevent BACK") # 返回
i += 1
else:
end_time = time.time()
spend_time = end_time - start_time
# print("|找图超过规定次数|,模拟器%d,第%s次真的找不到%s,本次找图花费秒数=%d秒" % (index, i, img, spend_time))
if i > 10:
writelog.write_file("|找图超过规定次数|,模拟器%d,第%s次真的找不到%s,本次找图花费秒数=%d秒" % (index, i, img, spend_time))
return [-1, -1], -1
2.蓝叠安卓模拟器开发者版本命令行整理帖
首先找到蓝叠安卓模拟器命令行程序,安装目录---bsconsole.exe,大家可以cmd执行试试。
蓝叠官方将放出数十条命令,攻城狮们陆续完善中,让我们一起来看看各个命令吧~
1. 启动模拟器
launch <--name mnq_name | --index mnq_idx> |
|
<command> |
launch |
[parameter] |
<--name mnq_name | --index mnq_idx>: 必须,二选一 --name:模拟器的标题栏的名字 --index:模拟器的索引,第一个是0,第二个是1,以此类推 |
示例 |
D:\BluestacksCN>bsconsole.exe launch --name 蓝叠模拟器 D:\BluestacksCN>bsconsole.exe launch --index 0 |
2. 启动模拟器并开启应用
launchex <--name mnq_name | --index mnq_idx> <--packagename apk_package_name> |
|
<command> |
launchex |
[parameter] |
<--name mnq_name | --index mnq_idx>: 必须,二选一 --name:模拟器的标题栏的名字 --index:模拟器的索引,第一个是0,第二个是1,以此类推 <--packagename apk_package_name>: 必须 --packagename: 应用包名 |
示例 |
D:\BluestacksCN>bsconsole.exe launchex --name 蓝叠模拟器 --packagename com.tencent.qq |
3. 退出模拟器
quit <--name mnq_name | --index mnq_idx> |
|
<command> |
quit |
[parameter] |
<--name mnq_name | --index mnq_idx>: 必须,二选一 --name:模拟器的标题栏的名字 --index:模拟器的索引,第一个是0,第二个是1,以此类推 |
示例 |
D:\BluestacksCN>bsconsole.exe quit --name 蓝叠模拟器 |
4. 退出所有模拟器
quitall |
|
<command> |
quitall |
[parameter] |
- |
示例 |
D:\BluestacksCN>bsconsole.exe quitall |
5. 查询模拟器
list |
|
<command> |
list |
[parameter] |
- |
示例 |
D:\BluestacksCN>bsconsole.exe list list一次性返回了多个信息,依次是:索引,标题,顶层窗口句柄,绑定窗口句柄,是否进入android,进程PID,VBox进程PID |
6. 查询运行中模拟器
runninglist |
|
<command> |
runninglist |
[parameter] |
- |
示例 |
D:\BluestacksCN>bsconsole.exe runninglist |
7. 判断指定模拟器是否运行
isrunning <--name mnq_name | --index mnq_idx> |
|
<command> |
isrunning |
[parameter] |
<--name mnq_name | --index mnq_idx>: 必须,二选一 --name:模拟器的标题栏的名字 --index:模拟器的索引,第一个是0,第二个是1,以此类推 |
示例 |
D:\BluestacksCN>bsconsole.exe isrunning --name 蓝叠模拟器 D:\BluestacksCN>bsconsole.exe isrunning --index 0 |
8. 重启模拟器
reboot <--name mnq_name | --index mnq_idx> |
|
<command> |
reboot |
[parameter] |
<--name mnq_name | --index mnq_idx>: 必须,二选一 --name:模拟器的标题栏的名字 --index:模拟器的索引,第一个是0,第二个是1,以此类推 |
示例 |
D:\BluestacksCN>bsconsole.exe reboot --name 蓝叠模拟器 |
9. 新增模拟器
add [--name mnq_name] |
|
<command> |
add |
[parameter] |
[--name mnq_name]: 可选 --name:模拟器的标题栏的名字 |
示例 |
D:\BluestacksCN>bsconsole.exe add --name 蓝叠模拟器 |
10. 复制模拟器
copy [--name mnq_name] <--from mnq_idx> |
|
<command> |
copy |
[parameter] |
[--name mnq_name]: 可选 --name:模拟器的标题栏的名字 <--from mnq_idx>:必须 --from:模拟器的索引,第一个是0,第二个是1,以此类推 |
示例 |
D:\BluestacksCN>bsconsole.exe copy --name 蓝叠模拟器 --from 0 |
11. 删除模拟器
remove <--name mnq_name | --index mnq_idx> |
|
<command> |
remove |
[parameter] |
<--name mnq_name | --index mnq_idx>: 必须,二选一 --name:模拟器的标题栏的名字 --index:模拟器的索引,第一个是0,第二个是1,以此类推 |
示例 |
D:\BluestacksCN>bsconsole.exe remove --name 蓝叠模拟器 D:\BluestacksCN>bsconsole.exe remove --index 1 |
12. 重命名模拟器
rename [--name <mnq_name | --index mnq_idx>] <--title mnq_title> |
|
<command> |
rename |
[parameter] |
[--name <mnq_name | --index mnq_idx>]:可选 --name:模拟器的标题栏的名字 --index:模拟器的索引,第一个是0,第二个是1,以此类推 <--title mnq_title>:必须 --title:模拟器标题栏新名字 |
示例 |
D:\BluestacksCN>bsconsole.exe rename --name 蓝叠模拟器 --title 新蓝叠模拟器 D:\BluestacksCN>bsconsole.exe rename --index 1 --title 新蓝叠模拟器 |
13. 修改属性
modify <--name mnq_name | --index mnq_idx> [--resolution <w,h,dpi>] [--cpu <1 | 2 | 3 | 4>] [--memory <256 | 512 | 768 | 1024 | 1536 | 2048 | 4096 | 8192>] [--jixing <manufacturor,model,brand>] [--pnumber 13900000000] [--imei <auto | 860000000000000>] [--mac <auto | 000000000000>] |
|
<command> |
modify |
[parameter] |
<--name mnq_name | --index mnq_idx>: 必须,二选一 --name:模拟器的标题栏的名字 --index:模拟器的索引,第一个是0,第二个是1,以此类推 [--resolution <w,h,dpi>]: 可选,自定义分辨率 [--cpu <1 | 2 | 3 | 4>] : 可选:cpu设置 [--memory <256 | 512 | 768 | 1024 | 1536 | 2048 | 4096 | 8192>] :可选,内存设置 [--jixing <manufacturor,model,brand>]:可选,机型信息 [--pnumber 13900000000]:可选,手机号码 [--imei <auto | 860000000000000>]:可选,手机imei [--mac <auto | 000000000000>]:可选,手机mac |
示例 |
修改默认模拟器的分辨率为600*360,dpi 160,cpu为1核,内存1024,机型为sanxing、note9、glaxy,手机号13988888888, imei随机: D:\BluestacksCN>bsconsole.exe modify --index 0 --resolution 600,360,160 --cpu 1 --memory 1024 --jixing sanxing,note9,glaxy --pnumber 13988888888 --imei auto |
下载地址:http://aliosscdn.bluestacks.cn/client/BlueStacksDev.exe
评论列表 (0 条评论)