做按键精灵自动化脚本的时候,最头疼的往往不是点击和键鼠操作,而是“读字”。窗口标题是固定的还好办,碰到要识别验证码、读取单据编号、判断游戏内提示,截图拿到之后只能靠肉眼。按键精灵本身不擅长 OCR,但我们完全可以给它外挂一对“眼睛”——通过按键精灵调用 OCR 文字识别 API。这篇保姆级教程会从0到1,把申请接口、获取 token、图片转 Base64、发送识别请求、解析返回结果整个流程完整串起来,最后给出一份可运行的按键精灵 VBS 脚本。适合刚接触 API 调用的按键精灵用户,也适合想把 OCR 能力集成到自动化工作流里的朋友。
1. 项目概述与整体思路拆解
1.1 按键精灵的“眼睛”盲区:为什么需要外部 OCR
按键精灵的定位能力其实很强,找图、找色、多点找色都足够成熟,但它有一个天然盲区:没办法理解一张图片里的文字是什么意思。找图是基于像素模板匹配,哪怕同样一句话,换个字体、字号、颜色,模板就失效了。而 OCR 要解决的是更上层的问题——从图像中提取语义文本。比如你截了一张订单截图,要找里面的订单号,用找图得先有一张和当前界面完全一致的模板图,可订单号是动态变化的,模板永远跟不上。如果用 OCR,直接把整张图丢给识别接口,返回的字符串里就能找到那串动态数字。
为什么不推荐在本地装离线 OCR?我试过几种方案,最大的问题不是识别率,而是环境配置成本。离线 OCR 往往需要安装 Python 环境、下载语言模型、处理依赖库,对按键精灵用户来说门槛太高。而且很多离线识别引擎对中文场景的支持一般,复杂背景、倾斜文字、表格线干扰下,效果远不如在线接口。调用云端的 OCR 文字识别 API,优点非常明显:识别精度高、支持中英文混合、印刷体和手写体都有专项模型,调用方式也很简单,本质就是一次 HTTP 请求。缺点是需要联网,并且有配额控制,但对日常自动化脚本来说完全够用。
1.2 调用链路的整体设计:两次请求 + 一次编码
整套方案的核心链路是这样的:
- 按键精灵脚本启动。
- 读取指定路径下的截图文件。
- 把图片二进制数据转换成 Base64 字符串。
- 用 API Key 和 Secret Key 向鉴权接口换取 access_token。
- 将 Base64 图片和 token 一起提交给 OCR 识别接口。
- 解析返回的 JSON,提取文字内容并输出。
这里有两个必须理解的设计点。第一,为什么很多 OCR 接口需要“先拿 token,再调识别”?因为这些接口采用的是 OAuth 2.0 的客户端凭证模式。API Key 相当于账号,Secret Key 相当于密码,直接拿账号密码去识别接口不安全,也容易被滥用,所以先换一个有时效性的令牌。token 的有效期通常很长,比如 30 天,所以脚本完全可以把 token 缓存到本地文件,避免每次识别都重新请求。
第二,图片为什么不直接传二进制?因为 JSON 和表单都是文本协议,没法直接承载二进制字节流。Base64 编码就是把二进制数据映射成由 64 个可见字符组成的文本,这样图片就能安全地放进请求体里。代价是体积增大约三分之一,但对常见 OCR 接口来说,图片本身只要控制在几 MB 以内,完全没有问题。
2. 环境准备与前置配置
2.1 需要准备哪些运行环境
这个方案对运行环境的要求极低,因为按键精灵的 VBS 环境本质上是 Windows 脚本宿主的一个子集,可以直接调用系统自带的 COM 组件,不需要额外安装任何第三方运行库。我列一下必要条件:
- 一台安装了按键精灵客户端的 Windows 电脑,PC 版即可,版本越新对 VBS 的支持越完善。
- 系统自带 MSXML2.XMLHTTP 组件,用来发送 HTTP 请求,所有 Windows 系统都内置。
- 系统自带 ADODB.Stream 组件,用来读取文件二进制数据,同样系统内置。
- 能正常联网,因为 OCR 接口在云端。
如果按键精灵调试界面里认不出 COM 组件,先检查脚本是不是写在VBSBegin和VBSEnd之间的代码块里。还有一点要注意,按键精灵运行脚本时可能会被安全软件拦截 COM 调用,遇见这种情况把脚本目录加入白名单,否则CreateObject这步会直接报错。
2.2 申请 OCR 应用并获取密钥
不管是哪家云服务商,流程几乎都是统一的。打开控制台,找到文字识别服务,创建一个应用,然后在应用详情页里就能拿到两串关键字符串:API Key 和 Secret Key。有的平台叫 AppID、AccessKey、SecretKey,本质是一回事,一个是身份标识,一个是持凭证。
申请的时候有两个细节值得说一下。第一,免费额度通常够用。个人自动化脚本一天也就识别几百次,免费配额一般足够;但如果要做批量识别,建议先看限流策略,有的接口是 QPS 限制,有的按日调用量限制。第二,密钥千万别硬编码后随手把脚本分享出去。脚本里一旦出现真实的 Secret Key,等于把账号密码公开了。我写脚本的习惯是密钥留空,用的时候再填,或者抽到一个单独的配置文件里加载。
2.3 准备一张测试图片
调通之前,建议先别急着直接对接自动化流程,先用一张手头可控的测试图片把链路跑通。最简单的做法是用按键精灵自带的抓抓工具,框选屏幕上包含文字的区域,另存为 PNG 文件。没有现成文字界面的话,可以用记事本写一段话然后截图。
图片要求也不算苛刻,尽量保证文字清晰、背景不过于花哨、文字方向大致水平。如果图片里有复杂背景或者文字对比度很低,识别率会明显下降,这不是接口不给力,而是图像本身太难。我建议测试阶段用一张白底黑字的截图,遇到问题也容易排查。
3. 核心代码实现与模块拆解
3.1 模块一:获取 access_token
先看获取 token 的代码。这个请求很简单,把 API Key 和 Secret Key 拼到 URL 参数里,POST 过去,返回的 JSON 里就有 access_token。
Function GetToken(apiKey, secKey) Dim http, url, resp, reg, m Set http = CreateObject("MSXML2.XMLHTTP") url = TOKEN_URL & "?grant_type=client_credentials&client_id=" & apiKey & "&client_secret=" & secKey http.Open "POST", url, False http.Send vbNullString resp = http.responseText Set reg = CreateObject("VBScript.RegExp") reg.Pattern = """access_token""\s*:\s*""([^""]+)""" Set m = reg.Execute(resp) If m.Count > 0 Then GetToken = m(0).SubMatches(0) Else GetToken = "" End If End Function为什么这里用正则而不是 JSON 解析器?因为按键精灵的 VBS 环境没有内置 JSON 对象,手写一个通用 JSON 解析器既长又容易出 bug。正则只要匹配"access_token":"xxxxx"这个字段就足够了,提取起来速度快,代码也短。如果你的服务商返回的不是这个字段名,比如叫 accessToken 或 data.token,改动正则即可。
注意 http.Open 里的第三个参数是 False,表示同步请求。按键精灵脚本通常是线性流程,同步请求会让脚本在这一步等待接口返回,虽然可能卡住一两秒,但逻辑最简单。异步回调在按键精灵的 VBS 环境里非常别扭,能不用就不用。
3.2 模块二:图片转 Base64 编码
接下来的核心操作是把图片文件变成 Base64 字符串。这里用到 ADODB.Stream 读取文件二进制,再用自定义函数做 Base64 编码。
Function FileToBase64(filePath) Dim stream, bytes, b64 Set stream = CreateObject("ADODB.Stream") stream.Type = 1 stream.Open stream.LoadFromFile filePath bytes = stream.Read() stream.Close b64 = Base64Encode(bytes) FileToBase64 = b64 End FunctionFileToBase64本身不复杂,真正关键的是Base64Encode函数。Base64 的原理可以这样理解:每 3 个字节(24 bit)拆成 4 组,每组 6 bit,然后映射到 64 个可见字符上。字符表是固定的:A-Z、a-z、0-9加上+和/。如果末尾不够 3 个字节,用=补齐。下面是完整实现:
Function Base64Encode(bytes) Dim b64Table, result, i, lenBytes, b1, b2, b3 b64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" lenBytes = UBound(bytes) + 1 result = "" For i = 0 To lenBytes - 1 Step 3 b1 = bytes(i) If i + 1 < lenBytes Then b2 = bytes(i + 1) Else b2 = 0 End If If i + 2 < lenBytes Then b3 = bytes(i + 2) Else b3 = 0 End If result = result & Mid(b64Table, ((b1 And 252) \ 4) + 1, 1) result = result & Mid(b64Table, (((b1 And 3) * 16) + ((b2 And 240) \ 16)) + 1, 1) result = result & Mid(b64Table, (((b2 And 15) * 4) + ((b3 And 192) \ 64)) + 1, 1) result = result & Mid(b64Table, (b3 And 63) + 1, 1) Next If lenBytes Mod 3 = 1 Then result = Mid(result, 1, Len(result) - 2) & "==" ElseIf lenBytes Mod 3 = 2 Then result = Mid(result, 1, Len(result) - 1) & "=" End If Base64Encode = result End Function这个函数里最容易栽的坑是用了/而不是\。VBS 里/是浮点除法,会得到小数,比如(b1 And 252) / 4可能得到 23.5,Mid 函数去取字符下标时就错了。必须用\整除,确保结果是整数。我在最初写这个函数时就踩过这个坑,排查了很久才发现是除号的问题。另一个坑是 VBS 的数组下标从 0 开始,UBound(bytes)得到的是最后一个元素的下标,所以长度要加 1。
关于图片大小,务必注意。Base64 编码后体积会比原图增加约三分之一,而很多 OCR 接口规定请求体不超过 4MB 或图片不超过 10MB。如果测试时图片过大导致报错,先压缩图片或者把 BMP 转成 JPG,不要直接硬怼大图。
3.3 模块三:调用识别接口并解析结果
拿到 token 和 Base64 图片后,就可以请求识别接口了。请求体使用 JSON 格式,把图片数据塞进 image 字段:
Function DoOCR(token, imageBase64) Dim http, body, resp Set http = CreateObject("MSXML2.XMLHTTP") body = "{""image"":""" & imageBase64 & """}" http.Open "POST", OCR_URL, False http.setRequestHeader "Content-Type", "application/json" http.setRequestHeader "Authorization", "Bearer " & token http.Send body resp = http.responseText DoOCR = resp End Function请求头里的Content-Type必须设置为application/json,否则服务端可能按表单解析,导致识别不到 image 字段。Authorization头用 Bearer 方式带上 token,这也是主流做法。
返回结果一般是 JSON 数组结构,类似这样:
{ "words_result": [ { "words": "你好,世界" }, { "words": "订单号:20250101" } ] }VBS 里没法直接通过属性访问 JSON,所以我用正则把每个words字段都捞出来,逐条输出:
Sub ParseWords(jsonText) Dim reg, matches, i Set reg = CreateObject("VBScript.RegExp") reg.Pattern = """words""\s*:\s*""([^""]*)""" reg.Global = True Set matches = reg.Execute(jsonText) For i = 0 To matches.Count - 1 TracePrint "识别文本[" & i & "] = " & matches(i).SubMatches(0) Next End Sub注意reg.Global = True这行不能漏,否则正则只匹配第一个 words 就停了。实际返回的字段名可能叫 text 或者 word,根据服务商文档调整正则即可。
3.4 模块四:流程串联与边界处理
模块都写完,主流程就是把它们串起来。完整流程的伪代码逻辑如下:
' 1. 检查图片是否存在 ' 2. 获取 token ' 3. 图片转 Base64 ' 4. 调用 OCR ' 5. 解析结果图片不存在的情况一定要处理。按键精灵脚本经常在凌晨定时跑,路径稍微一变文件就找不到了,如果不判断直接读取,ADODB.Stream 会抛出一个让人摸不着头脑的异常。可以用文件系统对象判断一下:
Function IsFileExists(path) Dim fso Set fso = CreateObject("Scripting.FileSystemObject") IsFileExists = fso.FileExists(path) End Function另外,网络请求偶尔会超时,尤其是 OCR 接口处理大图时耗时比较长。我的习惯是给识别请求加一个简单的重试机制,失败后等 1 秒再试一次,最多重试 2 次。在 VBS 里没有现成的 Sleep 函数,按键精灵自带Delay命令,可以这么写:
Delay 10004. 完整可运行脚本与参数说明
4.1 可直接粘贴的完整脚本
下面是一份完整的按键精灵 VBS 脚本,把上面所有模块拼在一起,并加入了文件存在性判断。你需要把四个配置常量的值换成自己的。
VBSBegin ' ====== 配置区 ====== Dim API_KEY Dim SECRET_KEY Dim TOKEN_URL Dim OCR_URL Dim IMG_PATH API_KEY = "换成你的APIKey" SECRET_KEY = "换成你的SecretKey" TOKEN_URL = "https://api.example-ocr.com/oauth/2.0/token" OCR_URL = "https://api.example-ocr.com/rest/2.0/ocr/v1/general_basic" IMG_PATH = "C:\test.png" ' ====== 配置区结束 ====== Function IsFileExists(path) Dim fso Set fso = CreateObject("Scripting.FileSystemObject") IsFileExists = fso.FileExists(path) End Function Function GetToken(apiKey, secKey) Dim http, url, resp, reg, m Set http = CreateObject("MSXML2.XMLHTTP") url = TOKEN_URL & "?grant_type=client_credentials&client_id=" & apiKey & "&client_secret=" & secKey http.Open "POST", url, False http.Send vbNullString resp = http.responseText Set reg = CreateObject("VBScript.RegExp") reg.Pattern = """access_token""\s*:\s*""([^""]+)""" Set m = reg.Execute(resp) If m.Count > 0 Then GetToken = m(0).SubMatches(0) Else GetToken = "" End If End Function Function FileToBase64(filePath) Dim stream, bytes, b64 Set stream = CreateObject("ADODB.Stream") stream.Type = 1 stream.Open stream.LoadFromFile filePath bytes = stream.Read() stream.Close b64 = Base64Encode(bytes) FileToBase64 = b64 End Function Function Base64Encode(bytes) Dim b64Table, result, i, lenBytes, b1, b2, b3 b64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" lenBytes = UBound(bytes) + 1 result = "" For i = 0 To lenBytes - 1 Step 3 b1 = bytes(i) If i + 1 < lenBytes Then b2 = bytes(i + 1) Else b2 = 0 End If If i + 2 < lenBytes Then b3 = bytes(i + 2) Else b3 = 0 End If result = result & Mid(b64Table, ((b1 And 252) \ 4) + 1, 1) result = result & Mid(b64Table, (((b1 And 3) * 16) + ((b2 And 240) \ 16)) + 1, 1) result = result & Mid(b64Table, (((b2 And 15) * 4) + ((b3 And 192) \ 64)) + 1, 1) result = result & Mid(b64Table, (b3 And 63) + 1, 1) Next If lenBytes Mod 3 = 1 Then result = Mid(result, 1, Len(result) - 2) & "==" ElseIf lenBytes Mod 3 = 2 Then result = Mid(result, 1, Len(result) - 1) & "=" End If Base64Encode = result End Function Function DoOCR(token, imageBase64) Dim http, body, resp Set http = CreateObject("MSXML2.XMLHTTP") body = "{""image"":""" & imageBase64 & """}" http.Open "POST", OCR_URL, False http.setRequestHeader "Content-Type", "application/json" http.setRequestHeader "Authorization", "Bearer " & token http.Send body DoOCR = http.responseText End Function Sub ParseWords(jsonText) Dim reg, matches, i Set reg = CreateObject("VBScript.RegExp") reg.Pattern = """words""\s*:\s*""([^""]*)""" reg.Global = True Set matches = reg.Execute(jsonText) For i = 0 To matches.Count - 1 TracePrint "识别文本[" & i & "] = " & matches(i).SubMatches(0) Next End Sub ' ====== 主流程 ====== Dim sToken, sBase64, sResp If IsFileExists(IMG_PATH) = False Then TracePrint "图片不存在,请检查路径:" & IMG_PATH Else sToken = GetToken(API_KEY, SECRET_KEY) TracePrint "access_token = " & sToken If Len(sToken) > 0 Then sBase64 = FileToBase64(IMG_PATH) sResp = DoOCR(sToken, sBase64) TracePrint "OCR 原始返回:" TracePrint sResp Call ParseWords(sResp) Else TracePrint "获取 token 失败,请检查 API_KEY / SECRET_KEY" End If End If VBSEnd4.2 参数配置与运行说明
脚本里的配置区一共有 5 个必填参数,其中 TOKEN_URL 和 OCR_URL 要以你所用服务商的官方文档为准,不要直接照抄示例地址。
| 参数名 | 作用 | 填什么 |
|---|---|---|
| API_KEY | 客户端身份标识 | 服务商创建应用后分配 |
| SECRET_KEY | 客户端密钥 | 服务商创建应用后分配 |
| TOKEN_URL | 获取 access_token 的接口地址 | 服务商文档为准 |
| OCR_URL | 通用文字识别接口地址 | 服务商文档为准 |
| IMG_PATH | 待识别图片的完整路径 | 本地 PNG/JPG 文件路径 |
运行步骤很简单。打开按键精灵脚本编辑器,把上面的代码粘贴进去,改掉配置区的参数,F5 启动调试。所有输出都会打到调试控制台里。如果不想看控制台,想把结果弹窗显示,把TracePrint "识别文本..."改成MsgBox ...就行。但自动化脚本里不建议弹窗,弹窗会阻塞流程,适合手动调试。
5. 常见问题与排查技巧实录
5.1 高频报错速查表
真正上手跑的时候,容易在几个固定环节报错。我把实际踩过的坑整理成一张速查表。
| 报错或现象 | 可能原因 | 处理方法 |
|---|---|---|
| 获取 token 失败,返回空字符串 | API Key / Secret Key 填错 | 检查密钥有没有复制完整,注意别带空格 |
| access_token invalid / token expired | token 过期或拼写错误 | 重新获取 token,或检查 Authorization 头格式 |
| image format error | 图片格式不是接口支持的格式 | 转成 PNG 或 JPG |
| base64 decode error | Base64 编码过程有误 | 检查 Base64Encode 函数里是否误用了/除法 |
| file size too large | 图片超过接口限制 | 压缩图片、裁剪区域、或转 JPG |
| request timeout | 网络问题或接口处理超时 | 加 Delay 重试,换更小的图片 |
| 返回结果里没有文字 | 图片文字不清晰、角度倾斜 | 提高对比度、转灰度、旋转矫正后再识别 |
5.2 容易被忽视的实战细节
几个细节虽然不致命,但会影响体验,我单独拎出来说。
第一,关于 token 缓存。如果不做缓存,脚本每跑一次都要先请求 token,很多服务商对 token 接口也有频率限制。token 有效期通常长达 30 天,完全可以在第一次获取后写入本地文件,之后每次启动先判断本地文件里的 token 是否在有效期内。VBS 里可以用按键精灵自带的插件命令读写 INI 文件,也可以自己写一个纯文本缓存。我建议个人脚本先不缓存,调通功能后再优化。
第二,图片预处理对识别率的提升非常大。图片转成灰度、放大两倍、再提高对比度之后,OCR 识别率会有肉眼可见的提升。按键精灵抓抓工具自带简单的图像处理能力,也可以在截屏时直接固定一个处理好的区域。如果你的文字是从游戏截图或网页复杂背景中抠出来的,预处理更是不可跳过。
第三,按需保留返回 JSON。调试阶段可以把整个sResp打印出来看完整结构,但正式运行只提取需要的字段就行,既能减小日志体积,也能让脚本跑得更快。
第四,脚本文件的编码要留意。按键精灵脚本如果出现中文乱码,通常不是因为 OCR 接口返回,而是脚本文件本身编码和调试窗口不一致。尽量使用默认编码保存,或在输出时只打印关键数字和短文本。
第五,网络请求是同步模式,遇到网络波动时脚本会卡住较久。给 DoOCR 外层套一个简单的计数器,连续失败超过 3 次就退出本次识别,避免脚本名义上“正常运行”实际一直在等请求超时。
最后分享一点个人体会。按键精灵调用 OCR 文字识别 API 这个组合,是我在自动化工作流里用得最顺手的一条路子。它不复杂,核心就是一次 Base64 编码加两次 HTTP 请求,但胜在通用——验证码收集、单据录入、日志抓取,凡是需要把屏幕文字变成可处理文本的场景,都能套同一套代码逻辑。建议你第一次跑通时,先用一张固定的小图反复测试,把链路完全跑顺之后,再接入真正的自动化工位。跑通之后你会发现,按键精灵不仅能模拟手,还能模拟眼睛,这才是自动化脚本真正顺手的地方。