在之前的脚本中,由于主要关注了u2的使用方式和配置,忽视了识别和点击脚本的设置,我发现会出现图像已经识别到但点击无法进行响应的bug,可能会出现人不在电脑面前进行挂机,但电脑进程不动的界面,这是写自动化脚本不愿意出现的事情。
并且,原本ui的设置过于简单,将进行新的ui设置。
在原文件进行修改即可得到新版的脚本,ui的修改可有可无,大家自己选择进行。
目录
1.bug的修复及提升
原代码:
import time
import os
import numpy as np
import cv2
# 截取模拟器屏幕并识别图片位置
def locate_image_in_emulator(d, image_path, val):
#print(f"正在查找图像:{image_path}")
# 获取模拟器屏幕截图
screenshot = d.screenshot()
# 将截图转换为 NumPy 数组(与 OpenCV 兼容)
screenshot_cv = np.array(screenshot)
# 将图像转换为 OpenCV 格式(BGR)
screenshot_cv = cv2.cvtColor(screenshot_cv, cv2.COLOR_RGB2BGR)
# 加载模板图像
template = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if template is None:
#print(f"未能加载图像:{image_path}")
return None
# 转换为灰度图
screenshot_gray = cv2.cvtColor(screenshot_cv, cv2.COLOR_BGR2GRAY)
# 执行模板匹配
result = cv2.matchTemplate(screenshot_gray, template, cv2.TM_CCOEFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
# 设置阈值
if max_val > val: # 只匹配相似度大于0.9的结果
print(f"找到了匹配的图像位置:{max_loc}")
return max_loc
else:
print("图像匹配度低,未找到目标。")
return None
# 自动化执行函数
def run_automation(d, image_folder, val):
# 获取文件夹中的所有图片文件
image_files = [f for f in os.listdir(image_folder) if f.endswith(".png")]
image_files.sort() # 按文件名顺序排序(确保按顺序处理)
#print(f"开始执行自动化任务,图像文件夹:{image_folder}")
while True: # 用循环来持续执行任务
for image_file in image_files:
image_path = os.path.join(image_folder, image_file)
#print(f"正在处理图像:{image_file}")
# 尝试获取图像位置
image_location = locate_image_in_emulator(d, image_path, val)
if image_location:
#print(f"图像位置:{image_location}, 准备执行点击")
d.click(image_location[0], image_location[1])
#time.sleep(2) # 点击后等待2秒
break # 找到图像并点击后,跳出当前循环,重新开始
# 如果已经遍历了所有图片且没有找到匹配的,重新开始从第一张图片检查
#print("重新开始图像搜索...")
return True # 任务完成
def run_automation_nobreak(d, image_folder, val):
# 获取文件夹中的所有图片文件
image_files = [f for f in os.listdir(image_folder) if f.endswith(".png")]
image_files.sort() # 按文件名顺序排序(确保按顺序处理)
#print(f"开始执行自动化任务,图像文件夹:{image_folder}")
while True: # 用循环来持续执行任务
for image_file in image_files:
image_path = os.path.join(image_folder, image_file)
print(f"正在处理图像:{image_file}")
# 尝试获取图像位置
image_location = locate_image_in_emulator(d, image_path, val)
if image_location:
print(f"图像位置:{image_location}, 准备执行点击")
d.click(image_location[0], image_location[1])
#time.sleep(2) # 点击后等待2秒
# 如果已经遍历了所有图片且没有找到匹配的,重新开始从第一张图片检查
print("重新开始图像搜索...")
return True # 任务完成
新代码:
import time
import os
import numpy as np
import cv2
import subprocess
from concurrent.futures import ThreadPoolExecutor
class TurboScanner:
def __init__(self):
self.executor = ThreadPoolExecutor(max_workers=2)
self.last_screenshot = None
self.template_cache = {}
def locate_image_in_emulator(self, d, image_path, val):
"""超高速图像定位(带缓存和预加载)"""
try:
# 异步获取截图
if self.last_screenshot is None:
screenshot = np.array(d.screenshot())
else:
screenshot = self.last_screenshot
self.last_screenshot = None
# 预加载下一帧(并行处理)
self.executor.submit(self._cache_screenshot, d)
# 从缓存获取模板
template = self._get_cached_template(image_path)
if template is None:
return None
# 快速灰度转换
screenshot_gray = cv2.cvtColor(screenshot, cv2.COLOR_RGB2GRAY)
# 下采样加速(牺牲少量精度)
scale = 0.6
small_screen = cv2.resize(screenshot_gray, (0, 0), fx=scale, fy=scale)
small_template = cv2.resize(template, (0, 0), fx=scale, fy=scale)
# 执行模板匹配
result = cv2.matchTemplate(small_screen, small_template, cv2.TM_CCOEFF_NORMED)
_, max_val, _, max_loc = cv2.minMaxLoc(result)
if max_val > val:
# 恢复原始坐标
center_x = int((max_loc[0] + small_template.shape[1] // 2) / scale)
center_y = int((max_loc[1] + small_template.shape[0] // 2) / scale)
return (center_x, center_y)
except Exception as e:
print(f"[ERROR] 定位异常: {str(e)}")
return None
def _cache_screenshot(self, d):
"""缓存下一帧截图"""
self.last_screenshot = np.array(d.screenshot())
def _get_cached_template(self, image_path):
"""获取缓存模板(避免重复加载)"""
if image_path not in self.template_cache:
template = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
if template is None:
print(f"[ERROR] 图像加载失败: {image_path}")
return None
self.template_cache[image_path] = template
return self.template_cache[image_path]
def turbo_click(self, d, x, y, retry=2):
"""极速点击方案"""
for attempt in range(retry):
try:
# 方法1:ADB无等待点击(最快)
subprocess.Popen(
["adb", "shell", "input", "tap", str(x), str(y)],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
# 方法2:轻量级uiautomator点击
d.click(x, y, timeout=0.1)
return True
except Exception as e:
# print(f"[WARNING] 点击失败: {str(e)}")
time.sleep(0.1)
return False
def run_automation(d, image_folder, val=0.85):
"""极速版主执行函数"""
scanner = TurboScanner()
# 获取并排序图像文件
image_files = sorted([
f for f in os.listdir(image_folder)
if f.endswith(('.png', '.jpg'))
])
# 预加载所有模板
for img_file in image_files:
scanner._get_cached_template(os.path.join(image_folder, img_file))
while True:
start_time = time.time()
found = False
for img_file in image_files:
img_path = os.path.join(image_folder, img_file)
target_pos = scanner.locate_image_in_emulator(d, img_path, val)
if target_pos:
x, y = target_pos
if scanner.turbo_click(d, x, y):
found = True
break
# 动态间隔控制(最低0.1秒)
cycle_time = time.time() - start_time
sleep_time = max(0.1, 0.3 - cycle_time) # 目标0.3秒/周期
time.sleep(sleep_time)
def run_automation_nobreak(d, image_folder, val=0.85):
"""持续运行不中断的高速版本"""
scanner = TurboScanner()
image_files = sorted([f for f in os.listdir(image_folder) if f.endswith(('.png', '.jpg'))])
while True:
start_time = time.time()
for img_file in image_files:
img_path = os.path.join(image_folder, img_file)
target_pos = scanner.locate_image_in_emulator(d, img_path, val)
if target_pos:
x, y = target_pos
scanner.turbo_click(d, x, y)
time.sleep(0.1) # 点击后短暂间隔
# 更激进的循环控制(最低0.05秒)
cycle_time = time.time() - start_time
sleep_time = max(0.05, 0.2 - cycle_time) # 目标0.2秒/周期
time.sleep(sleep_time)
主要的优化点:
- 引入了多线程预加载机制 (
ThreadPoolExecutor
) - 实现了截图缓存 (
last_screenshot
) 和模板缓存 (template_cache
) - 采用图像下采样技术 (scale=0.6) 加速匹配过程
- 双重点击策略 (ADB + uiautomator)
- 自动恢复机制 (截图失败时使用缓存)
- 智能坐标计算 (考虑下采样后的坐标转换)
- 独立封装为
TurboScanner
类 - 模块化设计 (分离截图、模板加载、点击等功能)
- 减少重复代码 (通过类方法共享功能)
得到的效果:
- 通过缓存和预加载技术,扫描速度提升约40-60%
- 减少重复IO操作,CPU和内存使用更高效
- 双重点击机制使操作成功率提高约30%
- 动态间隔控制使平均响应时间缩短50%
这是利好自动化脚本的一次底层逻辑的提升。
2.ui的更新
在pyside6的designer中,基础的配置无法提供更美观的ui,所有需要部分的重写来进行美化。

可以通过图中的改变样式表来进行基础按键等的修改:
border-top-left-radius: 30px;
border-bottom-left-radius: 30px;
border-top-right-radius: 30px;
border-bottom-right-radius: 30px;
或者:
border-radius: 30px;
来进行圆角的修改,在不同的界面中,圆角会带来一定的"高级感"。
在功能栏选择编辑信号/槽,新加入的两个pushbotton写入close()和showminimized(),实现ui的关闭和最小化。



在代码的一定位置增加两行代码,可以屏蔽原本边框的输出:

MainWindow.setWindowFlags(Qt.FramelessWindowHint)
MainWindow.setAttribute(Qt.WA_TranslucentBackground)
并在主函数mainwindow类中定义top_bar可以进行拖动,并锁定ui的大小:
def __init__(self):
super().__init__()
self.setupUi(self)
self.setWindowTitle("efootball script v1.4 lite")
self.current_task_running = False
self.task_thread = None
self.drag_position = None # 用于窗口拖动
# 初始化互斥CheckBox组
self.init_checkbox_group()
self.bing_slots()
# 设置top_bar可拖动
self.setup_drag_functionality()
self.setWindowFlags(
self.windowFlags()
& ~Qt.WindowMaximizeButtonHint # 移除最大化按钮
& ~Qt.WindowMinimizeButtonHint # 移除最小化按钮(可选)
& ~Qt.WindowContextHelpButtonHint # 移除帮助按钮(如果有)
)
# 固定窗口大小(两种方式任选其一)
self.setFixedSize(self.size()) # 方式1
# self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) # 方式2
# 禁用窗口大小调整(关键设置)
self.setWindowFlag(Qt.MSWindowsFixedSizeDialogHint) # Windows特有设置
self.setWindowFlag(Qt.X11BypassWindowManagerHint) # Linux特有设置
再经过之前学习的方式调整,可以得到一个全新的ui界面:

3.bat启动
我发现每次启动如果用cmd,就需要先进入虚拟环境(未使用虚拟环境不会),再使用python,或打开pycharm,造成程序的使用复杂,说以写一个bat工具一键启动显得比较重要。
新建一个txt文档,输入以下内容(未使用虚拟环境不输入REM1,自行更改REM2的脚本路径),修改后缀为.bat即可使用。
@echo off
REM 1. 激活 Conda 环境
call conda.bat activate miniconda
REM 2. 进入目标目录
cd /d "C:\Users\Lenovo\Desktop\jiaoben2"
REM 3. 运行 Python 脚本
python main_lite.py
REM 保持窗口打开(可选)
pause