1 前言
垃圾策划还不出个自动开星盘的小助手脚本,自己动手,丰衣足食。
本脚本为使用python自动开星盘。
2 环境搭建
下载相关所需库:pip install pyautogui opencv-python pyscreeze Pillow numpy
其中,pyautogui
用于模拟键鼠操作,OpenCV
用于图像识别。
3 实操
思路:
完整代码:
import time
import pyautogui
import cv2
import pygetwindow as gw
import numpy as np
import logging
logging.basicConfig(
level=logging.INFO,
format='[%(asctime)s] - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('log.txt', encoding='utf-8'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
def check_astrolabe(attribute='spell', times=1):
# 使用 pytesseract 读取图片中的文本
attackImg = cv2.imread(rf"res\{attribute}.png")
shotImg = cv2.imread(rf"screenshot.png")
match = cv2.matchTemplate(shotImg, attackImg, cv2.TM_CCOEFF_NORMED)
threshold = 0.8 # 设置阈值
matching_count = np.sum(match >= threshold)
if matching_count >= times:
logging.info(f"该星盘符合要求,{attribute}大于{times}条")
return True
else:
logging.info(f"该星盘不符合要求,{attribute}小于{times}条")
return False
def check_all_astrolabe(avg, attribute='spell', times=1):
avg_dont_match = []
for i in avg:
window = gw.getWindowsWithTitle(f'{account}')[0] # 替换为实际窗口标题
window.activate() # 激活窗口以确保它在前台
window.restore() # 如果窗口最小化,恢复窗口
pyautogui.moveTo(i)
time.sleep(1)
pyautogui.screenshot(region=(window.left, window.top, window.width, window.height)).save("./screenshot.png")
if not check_astrolabe(attribute, times):
avg_dont_match.append(i)
return avg_dont_match
def check_career(account):
print(account)
xy = get_xy(r"res/astrolabe-jo.png", account, 0.8)
if len(xy) >0:
return ['剑灵', 'res/astrolabe-jo.png']
xy = get_xy(r"res/astrolabe-yx.png", account, 0.8)
if len(xy) > 0:
return ['月仙', 'res/astrolabe-yx.png']
xy = get_xy(r"res/astrolabe-yj.png", account, 0.8)
if len(xy) > 0:
return ['妖精', 'res/astrolabe-yj.png']
xy = get_xy(r"res/astrolabe-mm.png", account, 0.8)
if len(xy) > 0:
return ['羽灵', 'res/astrolabe-mm.png']
xy = get_xy(r"res/astrolabe-mo.png", account, 0.8)
if len(xy) > 0:
return ['魅灵', 'res/astrolabe-mo.png']
xy = get_xy(r"res/astrolabe-wx.png", account, 0.8)
if len(xy) > 0:
return ['武侠', 'res/astrolabe-wx.png']
else:
logger.error(f"缺少该职业星盘")
return
def devour_astrolabe(avg, account):
"""
:param avg: 待吞噬星盘的坐标。[tuple, tuple...]
:param account:
:return:
"""
if len(avg) == 0:
logger.info(f"{account}没有星盘需要吞噬")
return
devAvg = get_xy('res/Button-devour.png', account)
if len(devAvg) == 0:
giftBoxAvg = get_xy('res/Button-giftBox.png', account)
if len(giftBoxAvg) == 0:
pracAvg = get_xy('res/Button-practice.png', account)
if len(pracAvg) == 0:
logger.error(f"{account}找不到修行按钮")
return
auto_Click(pracAvg[0], lef='left')
giftBoxAvg = get_xy('res/Button-giftBox.png', account)
auto_Click(giftBoxAvg[0], lef='left')
devAvg = get_xy('res/Button-devour.png', account)
auto_Click(devAvg[0], lef='left')
time.sleep(2)
for i in avg:
auto_Click(i, lef='left')
pyautogui.press('y')
time.sleep(0.5)
pyautogui.press('y')
keepAvg = get_xy(r"res/Button-keep.png", account)
auto_Click(keepAvg[0], lef='left')
time.sleep(0.5)
astAvg = get_xy('res/ast-w.png', account)
auto_Click(astAvg[0], lef='left')
time.sleep(0.5)
exitAvg = get_xy('res/ast-exit.png', account)
auto_Click(exitAvg[0], lef='right')
auto_Click(exitAvg[0], lef='left')
return
def get_xy(img_model_path, account, threashold=0.8):
"""
:param img_model_path:用来检测的图片
:return:以元组形式返回检测到的区域中心的坐标
"""
# 获取窗口大小位置
window = gw.getWindowsWithTitle(f'{account}')[0] # 替换为实际窗口标题
window.activate() # 激活窗口以确保它在前台
window.restore() # 如果窗口最小化,恢复窗口
time.sleep(0.5)
pyautogui.screenshot(region=(window.left, window.top, window.width, window.height)).save("./screenshot.png") # 截图
all_img = cv2.imread("./screenshot.png") # 待读取图像
origin_img = cv2.imread(f"{img_model_path}") # 模板图像
all_img = cv2.cvtColor(all_img, cv2.COLOR_BGR2GRAY)
origin_img = cv2.cvtColor(origin_img, cv2.COLOR_BGR2GRAY)
match = cv2.matchTemplate(all_img, origin_img, cv2.TM_CCOEFF_NORMED) # 开始匹配
threshold = threashold # 设置阈值
loc = np.where(match >= threshold)
h, w = origin_img.shape[:2]
matches = []
for pt in zip(*loc[::-1]): # *loc[::-1] 解压坐标
top_left = pt
bottom_right = (top_left[0] + w, top_left[1] + h)
center = (int((top_left[0] + bottom_right[0]) / 2), int((top_left[1] + bottom_right[1]) / 2))
avg = (center[0] + window.left, center[1] + window.top)
# 检查新点与已有点之间的距离
if not any(np.linalg.norm(np.array(avg) - np.array(m)) < 10 for m in matches):
matches.append(avg)
return matches
def auto_Click(var_avg, lef='left'):
"""
输入一个元组,自动点击
:param var_avg: 坐标元组
:return: None
"""
pyautogui.click(var_avg[0], var_avg[1], button=f'{lef}')
time.sleep(0.5)
def main(account, attribute='spell', times=1):
"""
循环:
0.【根据装备星盘判断职业】
1.循环判断每个星盘属性,不是双攻的记录坐标
2.吞噬所有非双攻的
3.无星盘礼盒→结束
4.判断包裹空位>0
5.开星盘,开当前页面空位个
"""
if attribute not in ['spell', 'physical', 'health']:
logger.info(f"{attribute}属性不在范围内")
return
career = check_career(account) # [职业, 星盘模板路径]
try:
logger.info(f"{account}职业为{career[0]}, 资源路径为{career[1]}")
except Exception as e:
logger.error(f"{account}背包未打开,无星盘")
return
while True:
pyautogui.moveTo(1,1)
xy = get_xy(career[1], f"{account}", 0.6)
# print(xy, len(xy))
if len(xy) > 1:
logger.info(f"有多余星盘{len(xy)-1}个,开始判断属性")
avg_not_match = check_all_astrolabe(xy[1:], attribute, times)
logger.info("开始吞噬星盘")
devour_astrolabe(avg_not_match,account)
logger.info("吞噬完毕,开始开星盘")
avg_giftBox = get_xy(r"res\giftBox.png", account)
giftBoxTimes = len(avg_giftBox)
if giftBoxTimes == 0:
logger.info(f"{account}无星盘礼盒,脚本结束")
return
spaceTimes = len(get_xy(r"res/table.png", account))
if spaceTimes == 0:
logger.info(f"{account}无包裹空位,脚本结束")
return
for i in range(spaceTimes):
auto_Click(avg_giftBox[0], lef='right')
if __name__ == '__main__':
account = "角色名"
main(account, attribute='属性', times=条数)
目录结构:
├── res
│ ├── ast-exit.png
│ └── ast-w.png
│ └── astrolabe-jo.png
│ └── astrolabe-mm.png
│ └── astrolabe-mo.png
│ └── astrolabe-wx.png
│ └── astrolabe-yj.png
│ └── astrolabe-yx.png
│ └── Button-devour.png
│ └── Button-giftBox.png
│ └── Button-keep.png
│ └── Button-practice.png
│ └── giftBox.png
│ └── health.png
│ └── spell.png
│ └── physical.png
│ └── table.png
└── 星盘.py
找不到好用的图床,粗略放个图吧。
以上。