使用Python开发一个图片OCR管理和文章下载工具
在日常工作中,我们经常面临两个零碎但繁琐的需求:一是管理大量的OCR(文字识别)图片素材,需要频繁查看、缩放图片并保存识别结果;二是看到优质的公众号文章,想把里面的图片批量下载下来保存素材。
今天,我将通过一个完整的 Python GUI 项目,分享如何使用 wxPython 将这两个功能整合到一个工具中。我们将重点分析如何自定义支持缩放/拖拽的图片控件、实现“智能保存”逻辑以及编写多线程爬虫。
技术栈概览
GUI 框架: wxPython (主要用于界面构建)
图像处理: Pillow (PIL) (用于图片加载和预处理)
网络爬虫: requests + BeautifulSoup4 (用于抓取微信文章)
系统交互: subprocess (调用外部OCR程序), threading (防界面卡死)
架构设计
程序的主体结构采用 wx.Notebook(选项卡)布局,将应用分为两个独立的 Panel:
OCRPanel: 负责图片导入、预览、调用外部OCR工具以及工程文件的保存(JSON格式)。
DownloaderPanel: 负责解析微信文章URL,批量下载图片。
核心亮点一:自定义可缩放、拖拽的图片画布 (ImageCanvas)
在早期的 wxPython 开发中,我们常用 wx.StaticBitmap 显示图片,但它不支持缩放和移动,查看大图细节非常不便。为了解决这个问题,我重写了一个 ImageCanvas 类。
1. 原理分析
这个控件继承自 wx.Panel,核心在于绑定 EVT_PAINT 事件,使用 wx.GraphicsContext 进行高性能绘图。
平移(Pan): 监听 EVT_MOTION 和鼠标点击事件,计算鼠标移动的 dx 和 dy,更新图片的绘制偏移量 offset_x 和 offset_y。
缩放(Zoom): 监听 EVT_MOUSEWHEEL。当滚轮滚动时,更新 self.scale 变量。
2. 代码解析
def on_paint(self, event):
dc = wx.BufferedPaintDC(self) # 使用双缓冲防止闪烁
dc.Clear()
if self.image:
gc = wx.GraphicsContext.Create(dc)
if gc:
gc.PushState()
# 核心变换逻辑:先平移,再缩放
gc.Translate(self.offset_x, self.offset_y)
gc.Scale(self.scale, self.scale)
bmp = wx.Bitmap(self.image)
gc.DrawBitmap(bmp, 0, 0, self.image.GetWidth(), self.image.GetHeight())
gc.PopState()这段代码的精髓在于 wx.GraphicsContext,它让我们不需要手动计算每个像素的位置,而是通过矩阵变换(Translate/Scale)轻松实现视图操作。
核心亮点二:工程文件的“智能保存”逻辑
在许多工具软件中,每次点击保存都弹出“另存为”对话框是非常糟糕的体验。我们在 OCRPanel 中实现了类似 Word 的保存逻辑。
1. 状态管理
我们在类中增加了一个变量 self.current_project_file 来记录当前工程是否已经关联了磁盘上的文件。
2. 逻辑流
新建/清空时:将 self.current_project_file 置为 None。
点击保存时:
Case A (已有文件): 如果 current_project_file 存在,直接写入 JSON,不弹窗。
Case B (新文件): 弹出 wx.TextEntryDialog 询问工程名,保存成功后更新 current_project_file。
def on_save_project(self, event):
# ... 省略数据收集代码 ...
# 智能判断:是“保存”还是“另存为”
if self.current_project_file and os.path.exists(self.current_project_file):
# === 直接保存 ===
with open(self.current_project_file, 'w', encoding='utf-8') as f:
json.dump(self.current_project, f, ...)
else:
# === 新建工程,询问名称 ===
dlg = wx.TextEntryDialog(self, "请输入工程名称:", "保存新工程")
if dlg.ShowModal() == wx.ID_OK:
# ... 保存并更新 self.current_project_file ...
核心亮点三:健壮的微信文章图片获取
微信公众号文章的图片下载有两个难点:懒加载(Lazy Load)和防盗链参数。
1. 对抗懒加载
微信文章的 HTML 中,真实的图片 URL 通常不在 src 属性中(src 往往是一个占位图),而是藏在 data-src 中。我们的爬虫采用了多重策略提取 URL:
BeautifulSoup 解析: 优先查找 data-src、data-original 等属性。
正则兜底: 如果 HTML 解析遗漏,使用正则表达式 re.findall 直接从源码中暴力匹配 https://mmbiz.qpic.cn/... 格式的链接。
2. URL 清洗
微信图片 URL 往往带有大量的参数(如 tp=webp),直接下载可能导致格式混乱。代码中实现了 clean_image_url 方法,提取基础 URL,并根据 Content-Type 智能判断文件后缀(.jpg, .png, .gif)。
3. 多线程防卡死
GUI 程序最忌讳在主线程进行网络请求。我们在 DownloaderPanel 中使用了 threading:
# 错误做法:直接调用下载函数,界面会卡死直到下载完成 # self.download_images(url, save_path) # 正确做法:开启新线程 threading.Thread(target=self.run_download_task, args=(url, save_path)).start()
同时,为了在子线程中安全地更新 UI(如进度条),我们使用了 wx.CallAfter,确保 UI 操作回到主线程执行。
运行结果

到此这篇关于使用Python开发一个图片OCR管理和文章下载工具的文章就介绍到这了,更多相关Python图片OCR管理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Pycharm中安装Pygal并使用Pygal模拟掷骰子(推荐)
这篇文章主要介绍了Pycharm中安装Pygal并使用Pygal模拟掷骰子,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2020-04-04
python代码 if not x: 和 if x is not None: 和 if not x is None:使用
这篇文章主要介绍了python代码 if not x: 和 if x is not None: 和 if not x is None:使用介绍,需要的朋友可以参考下2016-09-09
Python读取Word文档中的Excel嵌入文件的方法详解
这篇文章主要为大家详细介绍了Python读取Word文档中的Excel嵌入文件的方法,文中的示例代码讲解详细,具有一定的借鉴价值,需要的可以参考一下2022-12-12


最新评论