
Monkey see, monkey do 这种命名方式放在 macOS 原生 OCR 场景里尤其好理解图像里的文字被你看到然后被程序“复现”出来变成可复制的文本。它解决的正是从截图、PDF、照片中提取文字的老问题但和常见云 OCR 不同的是整个识别过程完全在本地完成不依赖网络也不会上传任何图片。适合经常需要整理资料的 Mac 用户也适合想在本地批量跑文字识别的开发者。最值得关注的不是“能不能识别”而是它把 macOS 自带的 Vision 框架用到了什么程度能不能用一条命令让屏幕里的文字直接变成剪贴板内容。我最近看到有人在分享这类小工具时用了“Monkey see, monkey do”这个名字觉得很形象。它本质上做的事情是先“看”图片里的文字再把文字“做”出来也就是输出到剪贴板、文件或者直接输入到当前光标位置。听起来不复杂但实际落地时涉及系统版本、权限、识别语言、脚本批处理和结果验证每一步都可能出问题。下面我按实际使用顺序拆一遍。1. 先厘清 Monkey see, monkey do 这类工具的真实定位1.1 不是又一个云 OCR而是完全离线处理很多人在 Mac 上碰到“需要提取图片文字”时第一反应是打开在线 OCR 网站或者装一个带云端的截图工具。这类方案确实方便但有两个问题图片要上传到别人的服务器隐私上不踏实网络差的时候速度没保证批量处理更不现实。Monkey see, monkey do 这类工具不一样。它调用的是 macOS 自带的 Vision 框架里面的文字识别能力就是“实况文本”背后的技术。也就是说Mac 本身已经具备图片文字识别能力只是默认入口藏得比较深不太适合批量使用。这些工具等于把这个能力拆出来做成命令行、脚本或快捷指令让你能更灵活地调用。这样做的好处很直接不联网离线可用图片不离开本机隐私风险低不依赖第三方服务的免费额度和系统结合紧密可以配合截图、剪贴板、快捷键一起用。我实测下来一张普通截图里的清晰文字从运行命令到输出结果通常一两秒内就能完成。这个速度在本地 OCR 里已经算很理想。1.2 适合谁不适合谁先说适合谁。如果你平时需要从截图里提取文字、把图片版PPT转成文本、把扫描PDF中的某一段复制出来或者经常处理包含联系人信息、账号、订单号、代码片段等内容的图片这类工具非常合适。因为任务不大不需要重型方案本地识别足够。如果你是开发者想做一个“截图后自动提取文字并复制”的工作流这种思路也很有价值。它可以在不引入外部依赖的情况下用 Swift 脚本或快捷指令快速实现甚至可以批量处理一个文件夹里的所有图片。再说清楚边界。它不适合处理结构复杂的扫描件比如带复杂表格、多栏排版、手写批注、模糊扫描的文档。Vision 框架能识别普通印刷体但遇到强背景干扰、文字倾斜过大、图片分辨率太低的情况准确率会明显下降。如果目标是专业级文档识别比如银行回单、发票、行业报告你可能需要更专门的 OCR 引擎或云服务。另外如果你需要识别小语种、少数民族语言或带特殊符号的公式原生方案不一定支持。具体支持哪些语言要以你当前系统的语言列表为准。2. 跑之前先确认环境macOS 版本、硬件和权限2.1 系统和硬件要求想用 Vision 框架做文字识别需要较新的 macOS。实况文本和相关的 Vision API 在 macOS Monterey 之后才比较完善所以建议至少使用 Monterey 或更新版本。如果系统太老代码可能编译不过或者识别能力明显缺失。硬件方面Intel 芯片的 Mac 和 Apple Silicon 都能跑。Apple Silicon 上通常更快但并不意味着旧机器不能用。我早期在 Intel MacBook Pro 上跑过类似脚本单张 1080p 截图耗时慢一些但没有到不可接受的程度。如果你要批量处理几十张高分辨率图片内存最好在 8GB 以上否则同时加载大图时可能出现明显卡顿。图片本身也会影响资源占用。一张 4000x3000 的照片和一张 800x600 的截图识别耗时差距很大。普通场景下我建议先缩小图片或降低分辨率再识别而不是直接丢原图。2.2 需要开启的权限这是最容易忽视的一环。如果你只对一张现成的图片文件运行 OCR基本不需要额外权限只要终端能读取到文件路径即可。但如果你的流程里包含“屏幕截图”这一步或者需要模拟键盘输入就必须处理权限。屏幕录制权限系统设置 → 隐私与安全性 → 屏幕录制。终端、iTerm 或运行脚本的 App 需要出现在允许列表里否则截屏时只能截到桌面壁纸或者直接黑屏。辅助功能权限如果你想让识别出来的文字自动输入到当前光标位置或者模拟点击、粘贴就需要把对应的终端或 App 加入“辅助功能”列表。完全磁盘访问权限某些情况下脚本需要读取“桌面”“下载”“文稿”等受保护目录里的文件。如果发现文件明明存在却读取不到可以检查终端是否拥有完全磁盘访问权限。建议先开屏幕录制权限因为“截图后直接识别文字”是最常见的组合。权限开完之后最好重启一下终端应用确保系统缓存刷新。2.3 不需要联网也不需要训练模型这一点是原生方案最大的优势。整个识别过程在系统内部完成不需要上传图片也不需要安装本地模型包。系统在首次使用相关能力时可能会初始化一些资源但不需要主动联网下载。如果想在离线环境下使用只要系统版本满足要求这个方案依然可以正常工作。这也是我倾向于推荐它的原因之一。3. 最省事的用法用系统自带能力完成“看到文字并复制”3.1 “实况文本”是最容易被忽略的入口先从最简单的方式说起。macOS 自带“实况文本”在很多系统应用里都能直接使用。比如用“预览”打开一张包含文字的图片把鼠标光标移到文字上光标会变成文本选择光标。此时可以直接选中文字右键拷贝或者用快捷键复制。这在单张图片、偶尔提取一次的场景下非常方便不需要安装任何东西。除了“预览”“照片”App、访达的快速预览、Safari 网页里的部分图片也支持类似操作。你甚至可以在桌面上直接选中截图里的文字。这个能力本质就是 Vision 框架只是入口做得比较隐蔽。不过“实况文本”有两个短板一是没法批量处理二是没法把文字直接输入到某个输入框里。你识别出来之后还得手动粘贴。所以它适合“轻量使用”不适合“工作流”。3.2 用“快捷指令”做成“截图提取文字”自动化如果你想要一个更省事的入口我建议用 macOS 自带的“快捷指令”App。创建一条快捷指令大致流程如下新建快捷指令添加“拍摄屏幕截图”操作再添加“从图像中提取文本”操作最后添加“拷贝到剪贴板”操作。这样你运行这条快捷指令时会先进入截图状态框选屏幕任意区域系统自动识别里面的文字并把识别结果复制到剪贴板。整个过程不到五秒。你还可以在快捷指令设置里绑定一个快捷键。比如设定为OptionCommandX之后在任何界面按下快捷键就能框选并复制文字。这个体验比打开截图工具再拖去识别要顺畅很多。如果你的需求不是复制到剪贴板而是把识别文本追加到备忘录或发送到某个文档也可以继续拼装操作。比如加一个“追加到备忘录”操作截图后直接生成笔记。工具本身支持很多结果处理方式关键是先把“从图像中提取文本”这一步跑通。3.3 输出到哪里剪贴板、文本文件还是直接输入“输出到哪里”决定了这个工具好不好用。日常推荐输出到剪贴板因为后续粘贴非常自由。你可以在浏览器搜索、写邮件、填写表单时直接粘贴。批量任务则推荐输出到文本文件每张图片对应一个.txt方便后面合并或查找。还有一类需求是把识别结果“直接输入到当前光标位置”。比如你在某个不支持上传图片的聊天框里想快速把截图里的文字输入进去。这时候可以用“辅助功能”权限加 AppleScript 模拟粘贴也可以用第三方工具模拟按键。说实话这种场景我一般更推荐剪贴板方案因为模拟输入在中文输入法状态下容易出现混乱粘贴更稳定。4. 开发者路线用 Swift 调用 Vision 框架实现 OCR 复制4.1 核心代码识别图片中的文字如果你需要摆脱图形界面或者想批量处理图片Swift 脚本是最直接的路线。下面这段代码是一个最小实现从命令行读入图片路径用 Vision 框架识别文字然后逐行打印到终端。import Vision import AppKit guard CommandLine.arguments.count 1 else { print(用法: swift ocr.swift 图片路径) exit(1) } let path CommandLine.arguments[1] guard let image NSImage(contentsOfFile: path), let cgImage image.cgImage(forProposedRect: nil, context: nil, hints: nil) else { print(无法读取图片: \(path)) exit(1) } let request VNRecognizeTextRequest { request, error in guard let observations request.results as? [VNRecognizedTextObservation] else { return } for observation in observations { if let candidate observation.topCandidates(1).first { print(candidate.string) } } } request.recognitionLevel .accurate request.recognitionLanguages [zh-Hans, en-US] request.usesLanguageCorrection true let handler VNImageRequestHandler(cgImage: cgImage, options: [:]) try? handler.perform([request])保存为ocr.swift后在终端运行swift ocr.swift 截图.png如果系统提示缺少命令行工具先安装 Xcode Command Line Toolsxcode-select --install这段代码有几个关键点recognitionLevel决定识别速度和准确率。.accurate更准.fast更快。recognitionLanguages定义识别语言。我习惯把中文放在前面英文放在后面这样中英混排时效果更稳定。usesLanguageCorrection开启词语纠错对整句识别有帮助。我建议先跑通这版最小的再根据自己需求扩展。4.2 把识别结果交给剪贴板或模拟键盘终端打印只是第一步。如果要复制到剪贴板可以直接用 macOS 自带的pbcopy命令swift ocr.swift 截图.png | pbcopy运行完之后剪贴板里就是识别出来的文字直接CommandV粘贴即可。如果你看到多行文本但希望粘贴时按原格式排列pbcopy会保留换行符。这和直接复制图片里的文字效果一致。模拟输入则稍微复杂。最简单的方式是先把识别结果复制到剪贴板再用 AppleScript 模拟CommandV粘贴swift ocr.swift 截图.png | pbcopy osascript -e tell application System Events to keystroke v using command down这段命令要求当前终端拥有“辅助功能”权限否则会报错。另外在中文输入法下模拟CommandV通常没问题因为粘贴动作不依赖输入法状态。4.3 从截图到复制一条龙如果你要把“截图 OCR 复制”合成一条命令可以这样做screencapture -x -o /tmp/ocr_screen.png swift ocr.swift /tmp/ocr_screen.png | pbcopy-x表示截图时不出声音-o表示不显示鼠标指针。执行后会先让你框选区域框选结束后自动识别文字并复制到剪贴板。这其实就实现了 Monkey see, monkey do 的核心体验眼睛看到屏幕内容手不用重新打字文字直接被“放”到剪贴板里。不过我一般不会每次都敲命令。我会把这条命令写成一个函数放到 shell 配置文件里ocrcopy() { screencapture -x -o /tmp/ocr_screen.png swift /path/to/ocr.swift /tmp/ocr_screen.png | pbcopy }之后在终端输入ocrcopy直接框选截图识别结果就进剪贴板了。如果你不在终端环境用快捷指令更顺手。5. 批量处理多张图片脚本化、队列化和命名规则5.1 用 shell 循环处理文件夹里所有图片单张图片跑通之后批量就顺理成章了。但我建议先做一个步骤把 Swift 脚本编译成可执行文件避免每次循环都重复编译。swiftc -O ocr.swift -o ocr编译一次之后./ocr就是一个本地二进制程序运行速度比swift ocr.swift快很多。然后写一个循环脚本mkdir -p output for img in images/*.png; do name$(basename $img .png) ./ocr $img output/$name.txt echo 完成: $img done这个循环会读取images文件夹下所有.png图片把识别结果存到output文件夹文件名和原图保持一致后缀改为.txt。如果图片格式不统一可以再加一个判断或者直接用find命令枚举文件find images -type f \( -name *.png -o -name *.jpg -o -name *.jpeg \) | while read img; do name$(basename $img) ./ocr $img output/$name.txt done5.2 输出文件命名与覆盖问题批量任务最容易踩的坑是覆盖。如果两张图片名字一样比如都在不同子目录里都叫screen.png上面的脚本就会互相覆盖。我建议在输出文件名里加上子目录名或序号。比如这样for img in images/*/*.png; do dir$(dirname $img | tr / _) base$(basename $img .png) ./ocr $img output/${dir}_${base}.txt done如果任务本身不要求保留原文件名也可以统一用序号i1 for img in images/*.png; do ./ocr $img output/$(printf %03d $i).txt i$((i1)) done命名规则没有标准答案但至少要保证不会互相覆盖并且看到文件名能大致判断来源。5.3 失败重试和日志怎么看批量处理时不能只盯着“能不能跑完”还要看失败率。我把标准做法分成三层标准输出保存识别文本错误信息单独存到日志每次循环记录退出状态。示例mkdir -p output logs i1 for img in images/*.png; do name$(printf %03d $i) if ./ocr $img output/$name.txt 2 logs/$name.err; then echo 成功: $img - output/$name.txt else echo 失败: $img fi i$((i1)) done如果某张图片识别结果为空但退出码依然是 0说明程序正常执行但没有找到文字。这种情况需要更细的判断比如检查输出文件是否为空if [ -s output/$name.txt ]; then echo 有内容: $img else echo 空结果: $img fi批量任务里“空结果”往往比“程序报错”更常见。原因通常是图片本身就是空白文字、文字太小、图片方向不对或者语言设置没覆盖到。不要只把退出码当作成功标准。6. 实操中容易踩的坑权限、语言、图像质量和速度6.1 权限问题截屏黑屏或者识别结果为空如果截图后识别结果为空先看看是不是权限问题。当你运行包含screencapture的命令时如果终端没有被授予“屏幕录制”权限系统会拒绝记录屏幕内容截出来的图片可能是一张纯色壁纸根本没有任何文字。解决办法是去“系统设置 → 隐私与安全性 → 屏幕录制”里把终端勾选上然后完全退出终端再重新打开。如果图片文件本身存在但脚本读取不到优先检查“完全磁盘访问权限”。尤其是图片放在“桌面”或“下载”目录时受保护目录的访问经常会触碰到权限限制。另外还有一种情况你在终端里运行脚本可以正常识别但在快捷指令里调用同样的命令却失败。这是因为快捷指令是独立进程权限范围不一定继承自终端。需要单独给“快捷指令”App 授权。6.2 语言设置中文识别不出或夹杂英文很多人在识别中文图片时遇到两个问题一是中文完全识别不出来二是中英文混排时顺序混乱。第一个问题通常是“没有把中文加进识别语言列表”。在 Vision 框架里recognitionLanguages没有指定中文系统可能只按默认语言处理。我的习惯是固定写[zh-Hans, en-US]优先简体中文其次英文。如果你有繁体和日文需求也可以把对应语言代码加进去。第二个问题是语言混排时的顺序。把哪种语言放在前面会影响系统对歧义字符的判断。比如一段文字里同时有“中文”和“OCR”如果英文在前OCR会被识别得更准如果中文在前中文部分会更稳定。没有绝对最优需要根据你的数据来源调整。值得注意的是语言设置不是越多越好。语言列表过长反而可能降低准确率因为系统需要在更多候选之间做判断。我建议只保留实际需要的两到三种语言。6.3 图像质量与版式为什么有的图怎么调都不行识别准确率不全是代码的问题图像质量影响很大。Vision 框架对印刷体、黑底白字、高对比度图片的识别很稳。但遇到这些情况效果会明显下降文字被水印或背景纹理干扰文字倾斜超过 30 度图片分辨率太低文字边缘发虚多栏排版阅读顺序混乱表格线、下划线、删除线跟文字重叠。我遇到过一张非常清晰的截图但因为文字带了粉色高亮背景识别结果里的一部分字被替换成了相近的方块。后来把图片转成灰度图并适当提高对比度正确率才恢复。如果你遇到“怎么调都不行”的情况建议先做预处理用sips调整尺寸放大到合适分辨率用图像处理工具提高对比度把彩色图转成灰度图手动裁剪掉无关区域。不要指望 OCR 能解决所有画质问题。脚本不能识别的内容先改图再跑识别。6.4 速度和资源占用怎么看单张图片的运行速度可以用time命令测量time ./ocr test.png如果输出时间超过几秒优先检查图片尺寸。一张 5000 像素宽的高清图比 1000 像素宽的截图耗时大很多。系统处理大图时内存占用也会上升。批量任务时不建议一上来就并行跑几十个进程。虽然xargs -P可以提高吞吐但每个进程都会占用内存和 CPU。以我的经验先用单线程把所有图片跑完记录耗时再考虑要不要并行。Apple Silicon 上并行效果不错Intel 老机器并行反而可能导致系统卡顿。如果对速度要求高把recognitionLevel改成.fast。代价是准确率略降但速度可以提升不少。在批量任务里我会先用.fast跑一遍粗略预览再用.accurate处理重要的几张。7. 和云 OCR、Tesseract 相比这类原生工具的优势和边界7.1 表格对比选型时可以把这几种方案放在一起对比。下面是我常用的判断维度。维度原生 OCRVision云 OCRTesseract网络依赖不需要需要不需要隐私性图片留在本机图片上传服务器图片留在本机使用成本系统自带可能有免费额度或按量计费免费开源中文识别支持体验尚可通常较强需要额外下载语言包手写识别有限支持部分服务支持支持较弱表格结构弱只输出文本部分支持结构化输出弱自定义训练不支持部分支持支持部署和调用系统 API简单需要 SDK 和网络请求需要安装依赖批量处理适合本地脚本受网络和并发限制适合本地脚本从这个表能看出来原生 OCR 的核心优势是“本地、简单、免费、隐私安全”。云 OCR 的核心优势是“功能全、识别强、后处理丰富”。Tesseract 的核心优势是“可定制、可训练、可控”。7.2 什么时候该用原生 OCR什么时候别硬撑我的建议很明确如果你只是想把截图里的文字变成可编辑文本不涉及复杂版式直接用原生方案。它最稳、最快、最省事。如果你需要处理的是扫描合同、发票、答题卡等必须输出表格字段原生方案会非常吃力。这时候正常的选择不是硬写正则去拆文本而是用云 OCR 或专业文档解析工具。如果你对隐私要求极高比如处理身份证、病历、合同信息本地优先。哪怕云 OCR 服务商声称不保存数据很多人心理上也不踏实。原生方案至少保证图片不出本机这点是实实在在的信任优势。如果你需要识别小语种先检查一下当前系统是否包含对应语言。如果包含原生方案可以跑如果不包含Tesseract 的语言包能补充一部分但训练质量和识别率要看具体语种。8. 实用建议从截图到文本的最小可用工作流8.1 我的默认组合日常使用我推荐两条路线按需求不同选择。第一条是“快捷指令路线”适合截图识别、临时提取文字、偶尔快速复制。优点是无需写代码和系统结合紧密能绑定快捷键。缺点是批量能力弱自定义程度低。第二条是“Swift 命令行路线”适合批量文件夹、循环处理、自动化脚本。优点是可控性强能精确处理文件命名、日志、重试和输出格式。缺点是需要写少量代码还要处理权限。这两个组合并不冲突。我一般把快捷指令作为默认入口批量任务时才用命令行。如果你平时工作大量依赖终端也可以直接把命令行作为主力不需要再开快捷指令。8.2 清单式落地步骤如果你想自己搭一套“截图即复制文本”的流程可以按这个清单走确认 macOS 版本较新建议 Monterey 或更新。打开终端安装 Xcode Command Line Tools。保存ocr.swift脚本先用一张包含清晰文字的图片测试。确认中文和英文都能识别必要时调整recognitionLanguages。用pbcopy测试识别结果是否能顺利进入剪贴板。如果需要截图后再识别测试screencapture并去系统设置里开启屏幕录制权限。把常用命令封装成函数或快捷指令绑定快捷键。批量任务时先编译成二进制再写循环脚本注意输出命名和错误日志。遇到结果为空先检查权限、图片质量和语言列表。需要更高准确率时对图片做预处理再切换到.accurate模式。这套流程不需要额外安装大型依赖也不依赖云服务能解决绝大部分“图片转文本”的需求。8.3 最后留一句经验踩过几次之后我发现很多工具不是能力不够而是前置条件和输入材料没有处理干净。Monkey see, monkey do 这类原生 OCR 工具真正落地时最值得盯住的不是“识别准确率有多高”而是权限是否开齐、语言是否配好、批量任务里的命名和日志是否可控。把这些基础工作做扎实它就能成为很趁手的本地效率工具。