<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Python on 随手记</title><link>https://www.bufio.cn/tags/python/</link><description>Recent content in Python on 随手记</description><generator>Hugo</generator><language>zh-cn</language><copyright>© 2026 &lt;a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener"&gt;苏ICP备2023022553号-1&lt;/a&gt;</copyright><lastBuildDate>Fri, 15 May 2026 12:00:00 +0800</lastBuildDate><atom:link href="https://www.bufio.cn/tags/python/index.xml" rel="self" type="application/rss+xml"/><item><title>在 macOS 上打包 Windows EXE 的好办法：用 GitHub Actions 自动编译</title><link>https://www.bufio.cn/posts/macos-build-windows-exe-github-actions/</link><pubDate>Fri, 15 May 2026 12:00:00 +0800</pubDate><guid>https://www.bufio.cn/posts/macos-build-windows-exe-github-actions/</guid><description>&lt;p&gt;如果你平时在 macOS 上写 Python 脚本、桌面小工具或命令行工具，最后却要发给 Windows 用户使用，最容易遇到的问题就是：我能不能直接在 Mac 上打包出 &lt;code&gt;.exe&lt;/code&gt;？&lt;/p&gt;
&lt;p&gt;结论先说清楚：&lt;strong&gt;不建议在 macOS 本机强行交叉打包 Windows EXE。更稳的办法是把代码推到 GitHub，让 GitHub Actions 在 Windows 环境里自动打包。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这篇文章按使用教程来写，从准备项目、创建 workflow、触发构建、下载产物，到常见问题排查，完整走一遍。&lt;/p&gt;
&lt;h2 id="总览为什么要用-github-actions-打包-exe"&gt;总览：为什么要用 GitHub Actions 打包 EXE&lt;/h2&gt;
&lt;p&gt;PyInstaller 这类打包工具通常不是“万能交叉编译器”。也就是说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;要打 Windows &lt;code&gt;.exe&lt;/code&gt;，最好在 Windows 上运行打包命令。&lt;/li&gt;
&lt;li&gt;要打 macOS 应用，就在 macOS 上打。&lt;/li&gt;
&lt;li&gt;要打 Linux 可执行文件，就在 Linux 上打。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这不是 GitHub Actions 的特殊限制，而是很多 Python 原生依赖、动态库、运行时文件和系统 API 都跟目标操作系统绑定。你在 macOS 上直接打包，得到的通常是 macOS 可执行文件，而不是 Windows 真正可用的 &lt;code&gt;.exe&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;GitHub Actions 的思路是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;macOS 本地开发
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; git push 到 GitHub
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; GitHub Actions 启动 Windows Runner
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 安装 Python 和依赖
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 执行 PyInstaller
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 上传 exe 产物
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -&amp;gt; 在 Actions 页面下载
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样做的好处是：&lt;/p&gt;</description></item><item><title>RapidOCR 入门：英文 OCR 识别、常规测评与使用注意事项</title><link>https://www.bufio.cn/posts/rapidocr-english-ocr-evaluation-usage-notes/</link><pubDate>Wed, 06 May 2026 11:17:28 +0800</pubDate><guid>https://www.bufio.cn/posts/rapidocr-english-ocr-evaluation-usage-notes/</guid><description>&lt;p&gt;OCR 这类工具最容易被误用：看起来只要把图片丢进去就能得到文字，但真正放到项目里时，还会遇到图片质量、方向、字体、语言、速度、批量处理和错误纠正等问题。本文以一个最小的 RapidOCR 英文识别项目为例，整理它适合做什么、怎么跑起来、怎么做常规测评，以及使用时需要注意哪些细节。&lt;/p&gt;
&lt;p&gt;本文不是完整排行榜式横向评测，而是偏工程落地的使用说明：先让脚本能稳定运行，再用一组可复现的指标判断它是否满足当前业务。&lt;/p&gt;
&lt;h2 id="rapidocr-是什么"&gt;RapidOCR 是什么&lt;/h2&gt;
&lt;p&gt;RapidOCR 可以理解为一个轻量级 OCR 推理方案。当前示例项目使用的是 &lt;code&gt;rapidocr-onnxruntime==1.2.3&lt;/code&gt;，底层通过 ONNX Runtime 执行 OCR 模型推理，典型链路包括：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;文本检测：先在图片中找出可能包含文字的区域。&lt;/li&gt;
&lt;li&gt;方向分类：判断文本是否需要旋转或方向修正。&lt;/li&gt;
&lt;li&gt;文本识别：对检测出来的文字区域逐行识别。&lt;/li&gt;
&lt;li&gt;结果整理：输出文本框、文字内容和置信度等结果。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在这个项目里，我们只保留最常用的输出：把图片中的文字逐行打印出来。它适合做轻量脚本、批处理、小工具、后台任务，也适合在正式接入大系统前做 OCR 方案验证。&lt;/p&gt;
&lt;h2 id="适用场景"&gt;适用场景&lt;/h2&gt;
&lt;p&gt;RapidOCR 更适合这些场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;识别清晰图片里的英文、数字、短标签、票据字段、车牌周边信息等。&lt;/li&gt;
&lt;li&gt;在本地或服务器上离线运行，不想依赖外部 OCR API。&lt;/li&gt;
&lt;li&gt;希望用 Python 快速接入，先验证效果，再决定是否封装成服务。&lt;/li&gt;
&lt;li&gt;对部署体积、调用方式、推理依赖有一定要求，希望用 ONNX Runtime 这类通用推理后端。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;它不太适合直接裸用在这些场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;图片严重模糊、过曝、反光、压缩严重。&lt;/li&gt;
&lt;li&gt;版面复杂，需要结构化还原表格、段落、字段层级。&lt;/li&gt;
&lt;li&gt;需要极高准确率的财务、证件、合同等强校验场景。&lt;/li&gt;
&lt;li&gt;需要直接理解语义，而不只是把图片转成文字。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些场景不是不能做，而是要加预处理、后处理、规则校验，甚至引入专门模型或人工复核流程。&lt;/p&gt;
&lt;h2 id="最小项目结构"&gt;最小项目结构&lt;/h2&gt;
&lt;p&gt;当前项目可以保持很简单：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rapidOCR/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── README.md
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── ocr.py
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── IMG_20260506_110642.jpg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── IMG_20260506_110656.jpg
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── venv/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;核心脚本 &lt;code&gt;ocr.py&lt;/code&gt; 的职责很清楚：接收一张图片路径，调用 RapidOCR，然后把识别出的每行文字打印出来。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;argparse&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;rapidocr_onnxruntime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RapidOCR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;OCR text recognition using RapidOCR&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;--input&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Path to input image file&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RapidOCR&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;No text detected.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的 &lt;code&gt;result&lt;/code&gt; 通常包含文本框坐标、识别文本、置信度等信息。示例脚本只打印 &lt;code&gt;line[1]&lt;/code&gt;，也就是文字内容。如果后续要做测评或业务校验，建议保留完整结果，不要过早只取纯文本。&lt;/p&gt;</description></item></channel></rss>