有些操作每天要做几十遍:等某个按钮出现、点它、等下一屏、再点。眼睛盯着、手在动,脑子完全没参与。这种活最适合交给脚本。
Text_Recognition_Clicker 就是这么来的:Python + PaddleOCR,框选屏幕区域,识别到指定文字就点指定坐标,循环执行,随时能停。
为什么是 PaddleOCR
三个理由:
- 中文识别准。界面上的字多是中文,Tesseract 在这种场景下经常连「确定」都认不出来;
- 完全离线。不用联网、不用调 API、没有额度;
- 有方向检测。横排文字、轻微倾斜的按钮都能处理。
代价是重。PaddlePaddle 装完几个 G,第一次加载模型要等十几秒。所以脚本启动时加载一次,后面复用同一个引擎实例。
版本锁定这一步别省
这是整个项目最容易卡住的地方。PaddleOCR 的依赖链很挑版本:
pip install paddlex==2.0.0 paddlepaddle==2.4.2
这两个必须配对,Python 也要在 3.8–3.10 之间。用 3.11 或 3.12 会遇到编译好的 wheel 不存在,现场编译基本失败。
装不上不是你的问题,是版本没对上。先固定 Python 版本,再固定 paddle 版本,别倒过来。
区域选择:把「看哪里」变成配置
不让脚本全屏找文字——太慢,而且容易误判。改成先框选区域,运行时只截那一小块。
流程是:点「选择区域」→ 全屏半透明遮罩 → 拖拽出矩形 → 记下 (x, y, w, h) → 保存到配置。运行时 mss 或 PIL.ImageGrab 只截这块,识别量从 1920×1080 降到 300×60,速度快一个数量级。
import mss
from PIL import Image
def grab(region):
with mss.mss() as sct:
shot = sct.grab({"left": region[0], "top": region[1],
"width": region[2], "height": region[3]})
return Image.frombytes("RGB", shot.size, shot.rgb)
result = ocr.ocr(np.array(grab(region)), cls=False)
texts = [line[1][0] for line in result[0]] if result[0] else []
文本标准化:空格会害死你
OCR 出来的结果不是你以为的样子。「确认提交」可能被识别成「确 认 提 交」,全角冒号可能变成半角,数字 0 和字母 O 会混。
所以匹配前先做一轮清洗:
- 去掉所有空白字符;
- 全角转半角;
- 统一大小写;
- 可选:去掉标点,只留汉字和字母数字。
import re, unicodedata
def normalize(s):
s = unicodedata.normalize("NFKC", s) # 全角 -> 半角
s = re.sub(r"\s+", "", s) # 去空白
return s.lower()
清洗完再用 target in normalized 判断,命中率会从「时好时坏」变成「基本稳定」。
循环、快捷键、停止条件
自动化脚本最危险的不是跑不起来,是停不下来。所以控制逻辑要放在最前面设计:
| 能力 | 实现 |
|---|---|
| 开始 / 暂停 | F8,用 keyboard 库全局监听 |
| 紧急停止 | F9,立刻跳出循环并释放资源 |
| 暂停确认 | 暂停后要求再按一次才恢复,防止误触 |
| 循环上限 | 设定最大次数,跑满自动停 |
| 停止条件 | 监控一个区域,出现指定文本就终止 |
「暂停-确认-恢复」这个设计看起来多余,实际很必要:手滑按到 F8 之后,脚本如果立刻继续点,可能已经点错了三下。
稳定性靠间隔,不靠运气
两类间隔必须能配:
- 元素间隔:识别完一个区域到处理下一个之间,等多久;
- 按钮间隔:点完一个按钮到下一个之间,等多久。
给太短,界面还没反应过来,脚本已经在点下一屏;给太长,效率还不如手动。我的经验是先从 0.8 秒起步,跑三轮没问题再往下压。
另外每个动作都包在 try 里,异常记日志但不停机——单次识别失败不该让整轮白跑。
边界
这类工具只适合自己有权操作的界面:自己的软件、自己的账号、允许自动化的流程。它本质上是在模拟人手,不是绕过什么。
真要上线之前,先跑一遍「只识别不点击」的干跑模式,看清楚它到底认到了什么。很多问题在这一步就能发现,不用等它点错地方。