ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于OCR的屏幕价格监控与自动点击工具实战

基于OCR的屏幕价格监控与自动点击工具实战 先交代一下背景。做这个工具完全是被一次抢购经历逼出来的。当时在“三角洲”那个交易场景里盯一件商品价格每隔几分钟浮动一次手点刷新再加鼠标挪到购买键反复几十次下来眼花了手也酸了最气人的是错过了一次明显低于市场价的瞬间。后来我就在想能不能写个东西替我盯着屏幕看到价格到位就自动点购买。于是就有了这个基于 OCR 价格识别加自动点击的小工具。如果你也有类似需求比如某个游戏内交易市场、某个二手平台、某个商品监控页面需要盯住一个数字、到了阈值就出手那这篇文章应该对你有用。我尽量把完整思路、代码实现、踩过的坑都摊开讲照着抄也能跑起来。1. 项目整体设计与思路拆解1.1 这个工具到底解决了什么问题先给这个项目定个位它解决的是“屏幕上的价格是个图片机器读不了人也盯不住”这两个问题。很多交易场景或者游戏内商城价格并不是以结构化数据接口暴露的而是直接渲染在界面上。你没法用爬虫去请求一个 JSON 才知道当前价格多少只能靠眼睛看屏幕上的阿拉伯数字。这就带来一个两难人眼盯盘精度高但根本盯不了那么久注意力一分散就漏掉普通按键脚本写死了坐标和时机但价格一变就失效更别说价格识别了。这个工具的思路也不玄乎定时截取屏幕上指定区域的图用 OCR 把图像里的数字抠出来转成浮点数再跟预设的目标价做比较。条件满足就触发一个鼠标点击动作直接点到购买按钮上。核心链路就是截图 - OCR - 判断 - 点击。整个过程里截图解决“数据获取”OCR 解决“数字读取”判断逻辑解决“要不要出手”自动点击解决“手速跟不上”。四个环节串起来等于把一个人从监控、识别、决策、执行四件事里解放了出来。1.2 为什么选 OCR 而不是别的方案当时摆在我面前的有三条路找官方 API、做图像模板匹配、做 OCR 文字识别。我没选前两条原因各有各的坑。先说明为什么不用官方 API。很多平台其实有开放接口但一是申请门槛高二是很多交易场景的数据压根不通过接口下发你拿不到实时价格。就算能拿到这种自动交易行为往往也违反平台规则接口调用频率一高反而容易被封。所以这条路从一开始就不太靠谱。模板匹配这个方案很多人也会想到。把价格数字的模板提前截下来比如“1”、“2”、“3”各存一张图然后在截图区域里滑动比对。但这里有个致命问题价格数字会变不同数字的宽度不一样同一个数字在不同背景下明暗也不同而且把“198”和“1980”放在一起模板匹配很难区分清楚边界。我前期试过这个方案识别率惨不忍睹价格一变小数点位置就飘。OCR 方案对比下来是综合最优的。它不关心数字在图像上的具体位置也不管背景是深是浅只要数字本身印刷清晰就能给你吐出一串文本。再加上 Tesseract、PaddleOCR 这些开源引擎已经非常成熟本地跑也很快完全可以在轮询间隔内完成识别。这不仅仅是技术上可行更重要的是它在通用性和鲁棒性之间找到了平衡点。1.3 整体架构与运行流程我把工具拆成了五个模块屏幕截图模块、图像预处理模块、OCR 识别模块、价格解析模块、自动点击模块。每个模块只做一件事互相之间通过简单接口调用这样后期单独替换某个环节也方便。单次循环的流程是这样的先根据预设的截取区域坐标抓取屏幕上价格区域和购买按钮区域两张图。价格区域的图做预处理放大、灰度化、二值化、去噪。预处理后的图送入 OCR 引擎提取文本。用正则表达式从文本里找出“数字可选小数点”的部分转成 float。跟目标阈值比较如果满足条件比如小于等于预设价就把鼠标移过去执行点击。不管是否触发点击写一条日志然后 sleep 一个设定好的间隔进入下一轮。这个流程看起来简单但每一环都有不少讲究。比如截图区域如果框大了OCR 识别到一堆无关文字解析就得花额外功夫如果框小了数字缺胳膊少腿也是白搭。所以模块拆开之后最大的好处就是可以单独调试每一环。模块化还带来一个额外收益出问题时不用从头查起。识别结果不对就查预处理和 OCR 参数没点击就查坐标和判断条件。这在后面调试阶段帮了我大忙。2. 核心技术选型与原理剖析2.1 OCR 引擎选型对比Tesseract、PaddleOCR 还是 Windows OCROCR 引擎是整个工具的大脑选型直接决定了识别成功率。我实际尝试过的方案有三个各有特点适合的场景也不一样这里做一个完整对比。第一个是 Tesseract OCR老牌开源方案。它最大的优势是轻量安装包不大Python 有 pytesseract 这种现成封装Java 也有 tess4j跨平台支持很好。精度上如果图像预处理做得好纯数字的识别率可以达到九成以上。但它的劣势也很明显对低分辨率图片非常敏感数字一旦粘连或者背景复杂识别结果就乱七八糟。如果你只识别纯数字、白底黑字这种高对比度场景Tesseract 完全够用。第二个是 PaddleOCR百度开源的中文 OCR 引擎。它的识别准确率明显高于 Tesseract尤其对中文和复杂背景下的文本识别效果好。但代价是依赖库很重。PaddleOCR 需要装了 PaddlePaddle 深度学习框架才能跑起来整个环境体积可能多达几个 G。而且第一次运行会下载模型对机器的 CPU 和内存都有一定要求。我自己的主力机器跑一次识别大概 200 到 400 毫秒还可以接受但在低配电脑上可能会出现明显的卡顿。第三个是 Windows 自带的 OCR 接口通过 WinRT 的 Windows.Media.Ocr 调用。它的好处是 Windows 10 以上系统自带不用装任何第三方组件C# 项目里引用 Windows.Media.Ocr 就能用。识别速度很快对系统 UI 元素的识别也不错。但问题是跨平台性差出了 Windows 就没法用而且对价格数字这种非标准字体的识别效果也不稳定。对比之后我是怎么选的呢如果只是识别纯数字价格我推荐先试 Tesseract因为它最轻、最容易部署。如果你的场景更复杂比如画面上既有价格又有商品名、备注信息需要从大段文字里筛出价格字段那就直接上 PaddleOCR省下跟识别结果较劲的时间。至于 Windows OCR适合你本身就在 Windows 平台上开发 C# 应用、又不想额外引入依赖的场景。2.2 为什么预处理是识别成功率的胜负手很多人直接把截图丢给 OCR 引擎结果识别率低就怪引擎不好。实际上OCR 引擎对输入图像的要求是有共识的高分辨率、高对比度、无噪声、字符清晰。屏幕截图这个东西恰恰经常对比度不够、还有各种阴影和杂边。我踩了一次大坑之后才意识到预处理做到位比换引擎管用得多。一套常规的预处理链路是放大 - 灰度 - 二值化 - 去噪。先放大。屏幕上价格区域的字有时候很小OCR 对过小的字符识别效果很差。我会把截图先放大两倍到三倍用 OpenCV 的 resize 方法插值。这样字符的像素更多边缘更圆润识别率提升非常明显。然后是灰度化。原图是 RGB 三通道每个像素有三个值信息冗余。灰度化之后每个像素只有一个值计算量小了关键是去掉了颜色干扰让 OCR 只关注亮度信息。接下来是二值化。这一步是为了让文字变成纯黑纯白背景变成纯白或纯黑。常用的方法是 OTSU 大津法它会自动找一个阈值把像素分成前景和背景两类。对于价格区域这种明暗分明的场景OTSU 的效果非常稳。最后是去噪用高斯模糊配合中值滤波把屏幕上那些细小的噪点抹掉。但要注意高斯模糊的核别设太大否则文字边缘也会被抹糊反而影响识别。这四条做完OCR 的输入质量会有质的飞跃。我当时用 Tesseract 测了一组截图未预处理的时候识别率只有六成左右加了这四步之后直接飙到九成五以上。所以遇到识别不准的问题先别急着换 OCR 引擎回头检查一下你的预处理链路。2.3 自动点击的两种实现方式与选型自动点击模块在 Windows 平台上主要有两条路一条是 pyautogui / pywin32 这条 Python 路线另一条是 C# 调 user32.dll 的 SendInput 接口。我两条路都写过聊聊感受。Python 的 pyautogui 上手极快代码就几行pyautogui.moveTo移动鼠标pyautogui.click点击鼠标直观得不得了。坏处是需要装依赖而且 pyautogui 的 click 是基于模拟鼠标事件实现的有些对安全性要求高的应用会检测这类模拟点击导致点击无效。C# 调 user32.dll 的 SendInput 则更接近底层。SendInput 是在驱动层面构造鼠标输入事件对应用来说它和真实用户操作几乎没有区别。实现上需要写 P/Invoke 签名代码量稍多但稳定性和兼容性好得多。如果这个工具只是自用、场景也不涉及高安全性应用那 pyautogui 完全够用快速实现是第一位的。如果你打算把工具做得更通用、或者目标应用对输入事件有校验那直接用 C# 调 SendInput 更稳妥别等上线了才发现点击被拦截。不过在这个项目里我用的是 Python 快速验证逻辑最后在实际部署版本里换成了 C# 封装。倒不是因为点击被拦截而是因为 C# 版本的启动速度和内存占用都优于 Python 的打包版本更适合长期挂着运行。后面会讲具体怎么做。2.4 多线程与轮询策略避免界面假死如果只跑一个 while True 循环从截图到点击之间全程单线程程序在 OCR 识别那几百毫秒里实际上是“卡住”的。虽然用户可能感知不到但日志不实时、界面按钮无响应体验很差。所以我在设计上加了一层简单的多线程主线程负责轮询控制工作线程负责截图、识别、点击。控制和执行分离之后主界面可以随时通过开关变量暂停或者停止程序工作线程在做完当前一轮识别后会检查开关再决定是否继续。轮询间隔也有讲究。OCR 识别本身需要几百毫秒所以轮询间隔不能太短否则 CPU 占用率拉满风扇狂转。我当时测试得到的经验值是价格波动不频繁的场景用 1 到 2 秒的间隔价格波动快的场景也至少留 0.5 秒的间隔。太频繁的轮询还容易引起目标应用卡顿反而影响真实用户的体验。另外工作线程里要加一个异常捕获的兜底。截图失败、OCR 引擎初始化失败、读取区域越界这些都是运行中可能冒出来的异常。如果不处理线程一崩工具就静默失效了表面上还在跑实际上已经死了。加一个 try-except 包住核心循环把异常堆栈写进日志比啥都强。3. 实操过程与核心环节实现3.1 环境准备与依赖安装我实际用的是 Python 3.9 作为快速验证环境操作系统 Windows 10。依赖库装这几个Pillow图像处理、OpenCV-Python预处理、pytesseractTesseract 的 Python 封装、pyautogui自动点击。如果要用 PaddleOCR还需要额外装 paddlepaddle 和 paddleocr。Tesseract 本体需要单独安装装完之后还要把 tesseract.exe 所在目录加到系统 PATH否则 pytesseract 找不到引擎。装的时候注意语言包如果只识别数字和英文默认的 eng 语言包就够用了不需要额外下中文包。安装阶段最容易出错的是 OpenCV 和 Pillow 的版本兼容问题尤其在 Python 3.9 以上环境装旧版 OpenCV 时很容易出编译错误。我的建议是直接装最新版别用老教程里的固定版本号。安装命令参考pip install opencv-python pillow pytesseract pyautogui如果要用 PaddleOCRpip install paddlepaddle paddleocr3.2 截图模块框选目标区域截图这一步的核心是确定“价格区域”和“购买按钮区域”两个坐标。我这里有两种做法都试过。一种粗糙但直接就是先手动截一张全屏图用画图工具打开把鼠标移到目标区域左上角和右下角记下坐标写进配置文件。这个方法胜在零成本几分钟就能跑通。坏处是如果窗口位置变了坐标就失效。另一种更稳妥是用 pyautogui 的截图功能配合locateOnScreen找参考元素。把价格区域旁边一个固定的图标作为锚点每次运行先找锚点位置再根据偏移量算出价格区域和按钮区域的实时坐标。这样即使窗口拖动到别处锚点找到了其他区域也能跟着定位。这个方法在最开始写起来稍麻烦但长期挂着跑非常省心。我这里给出第一种方法的简化代码先跑通再优化import pyautogui # 手动指定价格区域左上角和右下角坐标 PRICE_REGION (100, 200, 300, 230) # left, top, width, height # 手动指定购买按钮中心坐标 BUY_BUTTON_CENTER (200, 350) def capture_price_region(): img pyautogui.screenshot(regionPRICE_REGION) return imgpyautogui.screenshot的region参数接收的是一个四元组左边距、上边距、截图宽度、截图高度。这里注意顺序不是左上和右下两个点而是起点加宽高我第一次用的时候就搞反了截图一直截偏。3.3 图像预处理从 RGB 图到干净的二值图拿到价格区域的截图之后先做预处理。我这里的典型代码如下import cv2 import numpy as np from PIL import Image def preprocess_image(pil_img): # PIL 转 OpenCV 格式 img cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR) # 放大两倍提升小字识别率 img cv2.resize(img, None, fx2, fy2, interpolationcv2.INTER_CUBIC) # 灰度化 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 高斯去噪 blurred cv2.GaussianBlur(gray, (3, 3), 0) # OTSU 二值化 _, binary cv2.threshold(blurred, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU) return binary这里有一个细节值得多说一句二值化的时候我用了THRESH_BINARY_INV也就是反色把文字变成白色、背景变成黑色。为什么因为 Tesseract 内部对白字黑底的输入处理效果通常更好而这个方向在 PaddleOCR 上没有明显区别。如果你用的是 Tesseract记得用反色用 PaddleOCR 的话正反其实都可以但建议统一成反色保持输入一致性。预处理参数不要急着一次定死。我当时拿了三张不同背景下的价格截图分别跑预处理和识别对比结果后才把放大倍数固定为 2、高斯核固定为 3x3。不同场景下这些参数可能需要微调具体调参方法后面在问题排查章节会说。3.4 OCR 识别与价格解析正则提取数字预处理完的图送到 OCR 引擎里。Tesseract 的调用代码很简单import pytesseract from PIL import Image def ocr_image(binary_img): # 将 OpenCV 格式转回 PIL 格式 pil_img Image.fromarray(binary_img) text pytesseract.image_to_string( pil_img, config--psm 7 -c tessedit_char_whitelist0123456789. ) return text.strip()这里面的--psm 7和tessedit_char_whitelist两个参数特别关键。--psm 7是告诉 Tesseract 把整张图当作一行文本来识别。因为价格区域的内容通常就是一行数字用 psm 7 比默认的 psm 3自动分页检测更精准。如果价格区域可能包含多行信息比如上面是商品名、下面是价格那可以试试--psm 6把整块当作一个文本块处理。tessedit_char_whitelist0123456789.是字符白名单限制 Tesseract 只认数字和小数点。这一招能过滤掉大量英文字母误识别尤其是把 “S” 识别成 “5” 这种典型错误。但注意白名单在英文语言包下有效如果你加载的是中文语言包这种配置可能会失效。识别出的原始文本往往不是干干净净的一个数字可能带空格、带换行、甚至带个别误识别的符号。所以接下来要用正则做一次清洗import re def parse_price(text): # 匹配数字可能带小数点 match re.search(r\d(?:\.\d)?, text) if match: return float(match.group()) return None正则表达式\d(?:\.\d)?的含义是匹配整数部分以及可选的小数点和后面的小数部分。比如输入 “198.50”能正确提取 198.5输入 “1234”也能正确提取 1234.0。如果匹配不到返回 None说明这一轮识别失败。这里有一个我实际踩过的坑价格可能会有千分位分隔符比如 “1,299.00”这时候正则里的\d(?:\.\d)?只能匹配到 “1” 而不是完整价格。解决办法是先删掉所有逗号再匹配text text.replace(,, ) # 去掉千分位逗号3.5 自动点击模块精准命中购买按钮识别到了价格接下来就是判断和点击。判断逻辑很简单BUY_THRESHOLD 500.0 # 低于这个价格就买 def should_buy(price): if price is None: return False return price BUY_THRESHOLD点击部分如果用 pyautogui就两行import pyautogui import time def click_buy_button(): pyautogui.moveTo(BUY_BUTTON_CENTER[0], BUY_BUTTON_CENTER[1], duration0.2) time.sleep(0.05) pyautogui.click()duration0.2是让鼠标用 0.2 秒移动到目标位置模拟真实人类操作的速度而不是瞬移。瞬移在某些平台有反作弊检测容易被怀疑是脚本。这个细节虽然简单但很值得保留。C# 版本的 SendInput 调用会更底层一些核心代码类似这样[DllImport(user32.dll)] static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); public static void ClickAt(int x, int y) { SetCursorPos(x, y); INPUT mouseInput new INPUT(); mouseInput.type INPUT_MOUSE; mouseInput.mi.dwFlags MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP; SendInput(1, new[] { mouseInput }, Marshal.SizeOf(mouseInput)); }这段代码通过 SendInput 模拟鼠标左键按下和抬起。需要注意的是SetCursorPos移动的是系统级鼠标位置而SendInput发送的是驱动级输入事件两者配合才能完成一次完整的点击。如果只调SetCursorPos不调SendInput鼠标只是移过去并不会触发点击。点击时机也有讲究。OCR 识别到价格满足条件的瞬间并不意味着按钮一定可以点。有些界面上按钮有个加载状态比如“购买中”变灰之类这时候直接点可能无效。稳妥的做法是识别到低价之后先往下轮询两三次确认按钮区域的颜色或文本符合可点击状态再触发点击。这个确认逻辑虽然多花了两秒但能显著提高购买成功率。3.6 主循环与日志稳定运行的基石把上面的模块串起来主循环长这样import time import logging logging.basicConfig( levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s, handlers[ logging.FileHandler(tool.log, encodingutf-8), logging.StreamHandler() ] ) POLL_INTERVAL 1.0 # 轮询间隔单位秒 def main_loop(): while True: try: # 1. 截图 price_img capture_price_region() # 2. 预处理 binary_img preprocess_image(price_img) # 3. OCR 识别 raw_text ocr_image(binary_img) # 4. 价格解析 price parse_price(raw_text) # 5. 判断和点击 if should_buy(price): logging.info(f检测到低价: {price}尝试点击购买) click_buy_button() time.sleep(2.0) # 点击后暂停几秒避免连续误触 else: logging.debug(f当前价格: {price}未触发) except Exception as e: logging.exception(主循环异常) # 6. 按间隔进入下一轮 time.sleep(POLL_INTERVAL) if __name__ __main__: main_loop()日志这一点我想多说两句。很多人做这种小工具会忽略日志出了问题全凭猜。但自动购买工具的失败往往发生在你不在场的时候回来一看结果不对没有日志就只能干瞪眼。我加了一个双重输出既写tool.log文件也打到控制台。日志内容包含时间、当前识别到的价格、是否触发点击、异常堆栈排查问题有据可查比事后复盘靠谱得多。另外点击成功之后最好 sleep 一段时间比如 2 到 3 秒。这样做的目的是防止重复触发——如果点击之后价格仍然处于低位下一轮循环可能又会触发一次购买。加上暂停之后就给了购买动作一个冷却时间。3.7 从脚本到常驻工具C# 封装与托盘化Python 脚本验证完逻辑之后我把它封装成了 C# 的 Windows 程序加了系统托盘图标、全局热键和开机自启选项。这一步不是必须的但如果你打算长期挂机使用做这一步很值。C# 封装的核心其实是把 OCR 引擎替换成 Windows OCR 接口或者继续调用 Tesseract 的 DLL。我更推荐后者因为 Tesseract 的识别参数在 Python 版里已经调好了换成 C# 只需要用TesseractEngine类加载同样的参数就行。NuGet 上有Tesseract包可以直接用初始化代码大概是using Tesseract; var engine new TesseractEngine(./tessdata, eng, EngineMode.Default); engine.SetVariable(tessedit_char_whitelist, 0123456789.); var result engine.Process(pixFromBitmap); var text result.GetText();窗口本身做成托盘图标主界面只保留一个开关按钮和一个价格阈值输入框。托盘的好处是挂着不碍事查运行状态就看日志文件要暂停就双击托盘图标弹个菜单。整个东西做完之后运行内存大概三四十兆比 Python 打包版轻不少CPU 占用也不高非常适合丢在后台跑一整天。4. 常见问题与排查技巧实录4.1 OCR 识别不准先从图像质量下手我在开发过程中遇到最多的就是识别不准。典型症状是价格 123 识别成 123 后面多个 0、或者把 8 识别成 3。很多人第一反应是调 OCR 参数但我的经验是先去看输入图像长什么样。把预处理之后的二值图直接保存成文件肉眼检查一下文字是否断裂、是否连在一起、背景是否还有杂点。如果保存出来的图上文字清晰、白底黑字、没有多余噪点那 OCR 识别不准就是引擎参数问题调 psm 和字符白名单能解决大半。如果保存出来的图本身就是花的那 OCR 再强也白搭问题出在预处理环节。具体调参建议文字断裂就把放大倍数从 2 提到 3或者高斯模糊核从 3x3 降到 1x1文字连在一起就不放大或少放大增加二值化的对比度阈值背景有杂点就把高斯模糊核加大或者先跑一遍中值滤波。整个调参过程本质上就是在清晰度和噪声之间找平衡没有银弹只能按自己的实际场景试。4.2 识别结果有字母或乱码白名单没生效一个很常见的问题是识别结果里夹带着英文字母比如 “S123”、“l234” 之类。这通常有两个原因。一是字符白名单没生效。如果你用的是 Tesseract检查启动命令里tessedit_char_whitelist是否在 config 字符串里正确传入同时确认加载的语言包是 eng 而不是其他语言。另外注意白名单对 psm 3 的生效效果不如 psm 6 和 psm 7所以直接改用 psm 7 会更干脆。二是截的图里本身包含了价格之外的文字。如果价格区域框得比较大把商品名或者货币单位也圈进去了OCR 就会把所有文字都识别出来解析阶段虽然能用正则过滤但识别的时间变长、出错的概率也会增加。这时候最好的办法是重新精确框选价格数字的区域而不是依赖正则去删乱码。4.3 鼠标移动和点击没反应自动点击模块如果配置正确但实战中鼠标就是没动静先按这三个方向排查先确认鼠标坐标是不是在当前屏幕上。如果你用了多显示器pyautogui.moveTo的坐标体系和截图的坐标体系在跨屏时可能不一致导致鼠标在另一个屏幕上移动。这种问题通常表现为程序日志显示已经点击但你看的操作界面上没有反应。再确认目标应用是不是管理员权限运行。如果目标应用是以管理员身份启动的而你的工具不是那么模拟输入事件可能被系统拦截。这个在 Windows 的 UAC 权限模型里是个知名问题解决办法是让工具也以管理员身份运行。最后确认是不是点击太快没有给事件时间。SetCursorPos移动鼠标之后立刻发 SendInput有些窗口来不及处理鼠标进入事件点击会无效。在移动和点击之间加一个 30 到 50 毫秒的延迟往往就能解决。4.4 程序长时间运行后变卡或失效挂机一天之后工具可能开始变得迟钝甚至完全不工作。这种情况我排查下来主要有两个原因。一个是内存泄漏。如果用的是 Python 的 PIL 和 OpenCV循环里反复创建图像对象垃圾回收不及时内存占用会持续上涨。解决思路是在循环里显式del掉不再使用的图像对象或者改用函数内部的局部变量让它们自然回收。C# 版本也有类似问题需要记得Dispose掉Bitmap和Pix对象。另一个原因是 Windows 锁屏或者屏幕熄灭。有些 OCR 依赖屏幕内容如果电脑锁屏或者关闭了显示器截图模块可能拿到黑屏或锁屏画面识别自然就会失败。解决方法是关闭自动锁屏或者设置电源计划为从不睡眠。这是最容易被忽视的一个问题我一开始亏了好几次直到加了日志才发现识别文本全是空字符串。4.5 识别速度慢影响轮询节奏OCR 识别一次花 200 到 500 毫秒如果用的还是 PaddleOCR可能上到 1 秒。这个时间本身没问题但如果你把这个时间叠加到轮询间隔上轮询节奏就乱套了。我的处理方法是把单次循环的耗时考虑进 sleep 里。目标是让每次循环之间的总间隔保持稳定而不是固定 sleep 一个数。可以简单改成start_time time.time() # ... 执行一轮识别和判断 ... elapsed time.time() - start_time time.sleep(max(0, POLL_INTERVAL - elapsed))这样保证了每一轮的周期基本都是POLL_INTERVAL不会因为 OCR 偶尔变慢导致下一轮被推迟。另一个优化思路是“识别和点击分线程”。截图线程按固定间隔截图识别线程把截图放入队列慢慢处理点击线程只在识别结果满足条件时触发。这样即使 OCR 变慢截图频率也不会跟着掉。不过对于我实际的价格监控场景单线程加周期校正已经足够用了分线程属于锦上添花。5. 避坑指南与最终使用心得这个项目从开始写到稳定运行前后折腾了小两周踩过的坑上面也基本都列了。如果让我总结几条最想让当时的自己知道的教训大概是这几条第一先处理图像再调 OCR 参数。这两步的顺序不要反。图像不干净参数调一万遍都没用图像干净了OCR 默认参数往往已经能跑出不错的效果。第二日志一定要有并且要记录识别出来的原始文本。我自己调 bug 时最常做的一件事就是翻日志看某次识别到底读出了什么内容。如果日志只有判断结果而没有原始文本遇到识别错误就只能靠猜。第三轮询频率不是越快越好。太快的轮询会让 CPU 占用飙升也会给目标应用造成负担。我最后实测下来1 到 1.5 秒的轮询间隔综合体验最好基本不会错过价格变化同时也能保证工具长时间运行的稳定性。第四自动化点击要在“够用”和“不违规”之间找平衡。这类工具如果用在真实交易场景务必确认不违反平台规则。作为技术练手项目开发没问题但不要拿去刷单、抢购、扰乱正常交易秩序。做技术的人更要有边界感工具能做什么和应该用来做什么是两回事。如果后续还要扩展这个工具我觉得有两个方向值得做。一是把价格数据和识别结果保存到本地数据库这样后面可以做历史价格分析看什么时间段价格更容易低。二是加一个声音或者弹窗通知识别到低价的时候即使不自动点击也能第一时间提醒真人来操作。这两个功能都不复杂但会把工具从“替你做”升级成“辅助你决策”实用价值更高。暂时就写到这里。这个项目麻雀虽小五脏俱全从截图到识别再到自动操作几乎把桌面自动化的核心链路完整走了一遍。希望这篇文章能给你省下一些摸索的时间照着思路跑通一遍你大概就能举一反三把这些招式用到其他自动化的场景里去。
返回列表