
本文详解如何重构嵌套异常式图像查找逻辑,通过函数化封装与状态控制,实现多阶段自动化点击任务的无缝循环重启,避免因单次失败导致整个流程中断。
本文详解如何重构嵌套异常式图像查找逻辑,通过函数化封装与状态控制,实现多阶段自动化点击任务的无缝循环重启,避免因单次失败导致整个流程中断。
在使用 pyautogui 构建基于图像识别的自动化流程(如游戏辅助、UI 测试或批量操作)时,一个常见痛点是:当某张目标图片未被识别到,程序本应“回退重试第一阶段”,但原始代码中层层 try/except 嵌套 + 手动布尔标志(如 should_restart = False)极易导致控制流失控——第一轮循环退出后无法再次激活,第二轮执行完毕即终止,整体流程不可持续。
根本问题在于:原始逻辑混淆了“单步重试”与“全局重启”的语义。continue 在最外层 while should_restart: 中本应触发整轮重试,但由于所有 except 块最终都走向 should_restart = False,且无重置机制,流程自然“一去不返”。
✅ 正确解法是:将“查找-点击”抽象为原子操作,用函数返回值明确表达成功/失败,并用 continue 或循环结构天然支持重入。
以下为推荐的重构方案(兼顾健壮性与可维护性):
1. 封装核心操作:find_and_click()
import pyautogui
import time
def find_and_click(png_path, grayscale=False, confidence=0.7):
"""安全查找并点击指定图像,失败返回 False,成功返回 True"""
print(f"? 正在查找 {png_path}...")
try:
pos = pyautogui.locateCenterOnScreen(png_path, confidence=confidence, grayscale=grayscale)
if not pos:
print(f"⚠️ 未定位到 {png_path}")
return False
pyautogui.moveTo(pos, duration=0.2) # 添加平滑移动
time.sleep(0.1)
pyautogui.mouseDown()
time.sleep(0.5)
pyautogui.mouseUp()
pyautogui.moveTo(1200, 600, duration=0.2) # 归位防误触
print(f"✅ 成功点击 {png_path}")
return True
except Exception as e:
print(f"❌ 查找 {png_path} 时发生异常: {e}")
return False2. 分阶段循环:清晰分离关注点
def main():
print("? 启动自动化流程...")
# 阶段一:主物品识别循环(失败则从头重试)
while True:
print("\n? 进入阶段一:主物品扫描")
if not find_and_click("Yellow_FL.png"): continue
if not find_and_click("Green_FL.png", grayscale=True): continue
if not find_and_click("Purple_FL.png", grayscale=True): continue
if not find_and_click("Brown_Battery.png", grayscale=True): continue
if not find_and_click("green_battery.png"): continue
if not find_and_click("Purple_Lens.png", grayscale=True): continue
if not find_and_click("yellow_amp.png"): continue
if not find_and_click("Styptic.png"): continue
print("✅ 阶段一全部完成,进入下一阶段")
break # 全部成功才退出本阶段
# 阶段二:后续操作循环(同理)
while True:
print("\n? 进入阶段二:镜头与注射器处理")
if not find_and_click("yellow_lens.png"): continue
if not find_and_click("Syringe.png", grayscale=True): continue
if not find_and_click("AutoBloodweb.png", grayscale=True): continue
print("✅ 阶段二完成,流程结束")
break
if __name__ == "__main__":
time.sleep(2) # 启动前预留人工切换窗口时间
main()⚠️ 关键注意事项:
- 永远不要用裸 except: —— 它会捕获 KeyboardInterrupt(Ctrl+C),导致无法中止程序。应捕获 pyautogui.ImageNotFoundException 或 Exception 并显式处理。
- 归位坐标(moveTo(1200, 600))建议设为安全区域,避免悬停在按钮上干扰下一次识别。
- 若需“无限等待直到出现”,可将 find_and_click 替换为 wait_for_find_and_click(内部加 time.sleep(1) 循环),但需警惕死锁风险。
- 调试优先:开启 pyautogui.FAILSAFE = True(默认开启),鼠标移至屏幕左上角可强制中断;添加 print() 日志是定位卡点的最快方式。
通过函数化、分阶段、显式返回值的设计,你不仅解决了“无法重启第一循环”的问题,更获得了可扩展、易调试、易添加新步骤的健壮架构。自动化脚本的可靠性,永远始于清晰的控制流设计。

















