使用 Python 构建UI自动化脚本
颜色处理篇
py
import pyautogui
def compare_color(color1: tuple[int, int, int], color2: tuple[int, int, int], sim: float) -> bool:
"""
对比两个BGR颜色
"""
ar = color1[2]
ag = color1[1]
ab = color1[0]
br = color2[2]
bg = color2[1]
bb = color2[0]
fz = 10000 - sim * 10000
return ((ar - br) * (ar - br) + (ag - bg) * (ag - bg) + (ab - bb) * (ab - bb)) <= fz
def cv_color(color: str) -> tuple[int, int, int]:
b = int(color[0:2], 16)
g = int(color[2:4], 16)
r = int(color[4:6], 16)
return b, g, r
def get_color(x: int, y: int, screen=None, ) -> tuple[int, int, int]:
"""
返回CV图像指定坐标的颜色(BGR)
"""
if screen is None:
rgb = pyautogui.pixel(x, y)
return rgb[2], rgb[1], rgb[0]
else:
return screen[y, x]
def is_color(pos: tuple[int, int], color: str, sim: float, screen=None, ) -> bool:
"""
颜色判定
:param screen:截图
:param pos:坐标(x,y)
:param color:颜色
:param sim:相似度
"""
screen_color = get_color(pos[0], pos[1], screen)
return compare_color(cv_color(color), screen_color, sim)
图像匹配篇(opencv)
py
import cv2
import numpy
import pyautogui
def image_search(template, mask = None):
target = pyautogui.screenshot()
target = numpy.array(target)
target = cv2.cvtColor(target, cv2.COLOR_RGB2BGR)
# 获得模板图片的高宽尺寸
t_height, t_width = template.shape[:2]
# 执行模板匹配,采用的匹配方式cv2.TM_SQDIFF_NORMED
result = cv2.matchTemplate(target, template, cv2.TM_SQDIFF_NORMED, mask=mask)
# 归一化处理
# cv2.normalize(result, result, 0, 1, cv2.NORM_MINMAX, -1)
# 寻找矩阵(一维数组当做向量,用Mat定义)中的最大值和最小值的匹配结果及其位置
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
# 匹配值转换为字符串
# 对于cv2.TM_SQDIFF及cv2.TM_SQDIFF_NORMED方法min_val越趋近与0匹配度越好,匹配位置取min_loc
# 对于其他方法max_val越趋近于1匹配度越好,匹配位置取max_loc
str_min_val = str(min_val)
# 绘制矩形边框,将匹配区域标注出来
# min_loc:矩形定点
# (min_loc[0]+t_width,min_loc[1]+t_height):矩形的宽高
# (0,0,225):矩形的边框颜色;2:矩形边框宽度
# cv2.rectangle(target, min_loc, (min_loc[0] + t_width, min_loc[1] + t_height), (0, 0, 225), 2)
# cv2.imshow("MatchResult----MatchingValue=" + str_min_val, target)
# cv2.waitKey()
return min_loc, min_val
按键监听篇
鼠标
py
from pynput import mouse
# 鼠标click监听
def on_click(x, y, button, pressed):
# print(f'Click position: ({x}, {y})')
if pressed:
print(f'Click button: {button}')
# print(f'Click state: {"Pressed" if pressed else "Release"}')
with mouse.Listener(on_click=on_click) as listener:
listener.join()
键盘
py
def on_press(key):
if hasattr(key, 'char'):
pass
elif key == k.Key.esc:
pass
with k.Listener(on_press=on_press) as listener:
listener.join()
记一种线程强制中断方式
py
def _async_raise(tid, exctype):
"""raises the exception, performs cleanup if needed"""
tid = ctypes.c_long(tid)
if not inspect.isclass(exctype):
exctype = type(exctype)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
if res == 0:
raise ValueError("invalid thread id")
elif res != 1:
# """if it returns a number greater than one, you're in trouble,
# and you should call it again with exc=NULL to revert the effect"""
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
raise SystemError("PyThreadState_SetAsyncExc failed")
def stop_thread(thread):
try:
_async_raise(thread.ident, SystemExit)
except SystemError:
pass
关于 pyautogui 按键延迟的问题
可通过 PAUSE
调整按键之间的延迟。
py
pyautogui.PAUSE = 0