GLM-OCR命令行工具开发:打造便捷的本地文档解析利器
GLM-OCR命令行工具开发:打造便捷的本地文档解析利器
你是不是经常需要从一堆图片或者PDF里提取文字?手动操作费时费力,用在线工具又担心数据安全。今天,咱们就来动手做一个属于自己的本地文档解析利器——一个基于GLM-OCR的命令行工具。有了它,你只需要在终端敲一行命令,就能轻松把图片、PDF里的文字提取出来,还能保存成JSON或者TXT格式,方便后续处理。
这个工具最大的好处就是完全本地运行,你的文档数据不用上传到任何地方,安全又私密。而且,一旦做好,你可以把它集成到任何自动化脚本里,批量处理成千上万的文档都不在话下。接下来,我就手把手带你从零开始,把这个工具做出来。
1. 环境准备与项目初始化
在开始敲代码之前,我们得先把“厨房”收拾好,把需要的“食材”备齐。整个过程很简单,跟着步骤走就行。
1.1 安装Python与必要库
首先,确保你的电脑上安装了Python。打开终端,输入下面的命令检查一下:
python3 --version
如果显示了Python 3.7或更高的版本号,那就没问题。如果没有,你需要先去Python官网下载安装。
接下来,我们用pip安装这个项目需要的几个核心库。打开终端,一行命令搞定:
pip install paddlepaddle paddleocr glm-ocr click
我来简单解释一下这几个库是干什么的:
- paddlepaddle & paddleocr: 这是百度开源的OCR引擎,识别图片文字的核心就靠它,非常强大。
- glm-ocr: 这可能是一个对PaddleOCR的封装或特定模型接口,我们用它来调用OCR功能。
- click: 一个超级好用的Python库,专门用来创建漂亮的命令行工具,比Python自带的
argparse写起来更简单、更直观。
1.2 创建项目结构
安装好库之后,我们创建一个清晰的项目文件夹,把东西都放得整整齐齐。在终端里执行以下命令:
mkdir glm-ocr-cli
cd glm-ocr-cli
touch ocr_tool.py
touch requirements.txt
touch README.md
现在,你的项目文件夹里应该有这三个文件了。ocr_tool.py将是我们工具的主程序,requirements.txt用来记录项目依赖,README.md可以写点使用说明。
为了让环境更干净,我建议创建一个Python虚拟环境。还是在项目根目录下,运行:
python3 -m venv venv
然后激活它:
- 在Linux或Mac上:
source venv/bin/activate - 在Windows上:
venv\Scripts\activate
激活后,你的命令行提示符前面通常会显示(venv),表示已经在虚拟环境里了。在这个环境里再次安装依赖,就不会影响系统其他Python项目。
pip install paddlepaddle paddleocr glm-ocr click
把安装好的库版本记录到requirements.txt里,方便以后复现环境:
pip freeze > requirements.txt
好了,准备工作全部完成,我们可以开始编写核心工具了。
2. 使用Click构建命令行工具
为什么选Click而不是argparse?Click写起来更简洁,功能也更强大,自动帮你生成好看的帮助文档,还支持复杂的命令行参数。我们用Click来定义工具怎么用。
2.1 定义工具的基本框架
打开ocr_tool.py文件,我们开始写代码。首先,导入必要的模块。
import click
import os
import json
import sys
from pathlib import Path
from typing import List, Optional
# 注意:这里假设glm_ocr是一个可用的OCR模块。
# 实际使用时,请根据`glm-ocr`库的真实导入方式进行调整。
try:
from glm_ocr import OCRProcessor # 示例导入,请替换为实际类名
OCR_AVAILABLE = True
except ImportError:
OCR_AVAILABLE = False
click.echo("警告:未找到glm_ocr模块。请确保已正确安装。", err=True)
接下来,我们用@click.command()装饰器来告诉Click,这是一个命令行命令。@click.option()用来定义每一个命令行参数。
@click.command()
@click.argument('input_path', type=click.Path(exists=True))
@click.option('-o', '--output', 'output_path', type=click.Path(), help='输出文件或目录的路径。如果未指定,结果将打印到控制台。')
@click.option('-f', '--format', 'output_format', type=click.Choice(['json', 'txt'], case_sensitive=False), default='txt', help='输出结果的格式:json 或 txt。默认为 txt。')
@click.option('-m', '--mode', 'ocr_mode', type=click.Choice(['fast', 'accurate'], case_sensitive=False), default='accurate', help='OCR识别模式:fast(快速)或 accurate(精确)。默认为 accurate。')
@click.option('-r', '--recursive', is_flag=True, help='如果输入路径是目录,则递归处理其子目录下的所有支持文件。')
@click.option('--verbose', '-v', is_flag=True, help='打印更详细的处理信息。')
def cli(input_path, output_path, output_format, ocr_mode, recursive, verbose):
"""
GLM-OCR 命令行工具。
对指定的图片或PDF文件(INPUT_PATH)进行OCR文字识别,
并将结果以指定格式输出。
"""
if not OCR_AVAILABLE:
click.echo("错误:OCR功能不可用。请检查glm-ocr库是否安装正确。", err=True)
sys.exit(1)
# 将输入路径转换为Path对象,处理起来更方便
input_path_obj = Path(input_path)
# 核心处理逻辑将在这里调用
process_input(input_path_obj, output_path, output_format, ocr_mode, recursive, verbose)
上面这段代码,我们已经把工具的“骨架”搭好了。它定义了用户需要提供的参数:
INPUT_PATH:必须提供的输入文件或文件夹路径。-o:可选,指定结果输出到哪里。-f:可选,选择输出格式是JSON还是纯文本。-m:可选,选择要速度还是要精度。-r:一个“开关”,如果加上,就会递归处理子文件夹。-v:另一个“开关”,加上后会显示更多运行细节。
现在,工具已经能响应--help参数了。在终端里试一下:
python ocr_tool.py --help
你应该能看到一个自动生成的、格式工整的帮助信息,列出了所有参数和说明。是不是比从头写argparse省事多了?
2.2 实现核心处理逻辑
骨架有了,现在需要填充“血肉”,也就是实际处理文件的函数。我们在cli函数上面,添加一个process_input函数。
这个函数要处理几种情况:输入是单个文件,还是一个文件夹?输出路径指定了没有?我们要根据这些情况来决定怎么做。
def process_input(input_path: Path, output_path: Optional[str], output_format: str, ocr_mode: str, recursive: bool, verbose: bool):
"""
根据输入路径的类型(文件/目录)分发处理任务。
"""
# 初始化OCR处理器,这里用‘accurate’或‘fast’模式初始化
# 注意:此处为示例,初始化方式需根据glm_ocr库的实际API调整
try:
# 假设OCRProcessor这样初始化
ocr_processor = OCRProcessor(mode=ocr_mode)
except Exception as e:
click.echo(f"初始化OCR处理器失败:{e}", err=True)
sys.exit(1)
# 判断输入是文件还是目录
if input_path.is_file():
if verbose:
click.echo(f"正在处理文件:{input_path}")
result = process_single_file(input_path, ocr_processor, verbose)
handle_output(result, input_path, output_path, output_format, verbose)
elif input_path.is_dir():
if verbose:
click.echo(f"正在处理目录:{input_path},递归模式:{recursive}")
# 收集目录下所有支持的文件
file_list = collect_files(input_path, recursive)
if not file_list:
click.echo(f"在 {input_path} 中未找到支持处理的文件。")
return
all_results = {}
for file in file_list:
if verbose:
click.echo(f" 处理中:{file}")
result = process_single_file(file, ocr_processor, verbose)
# 以文件相对路径作为键,存储结果,方便在批量输出时区分
rel_path = str(file.relative_to(input_path))
all_results[rel_path] = result
handle_batch_output(all_results, input_path, output_path, output_format, verbose)
else:
click.echo(f"错误:输入路径 {input_path} 既不是文件也不是目录。", err=True)
sys.exit(1)
这里出现了几个我们需要实现的子函数:process_single_file(处理单个文件)、collect_files(收集文件列表)和handle_output(处理输出)。我们一个一个来实现。
首先,是识别单个文件的函数。这里就是真正调用OCR模型的地方。
def process_single_file(file_path: Path, ocr_processor, verbose: bool) -> dict:
"""
对单个文件执行OCR,返回结构化的识别结果。
"""
# 检查文件类型,这里示例支持.png, .jpg, .jpeg, .pdf
suffix = file_path.suffix.lower()
supported_image = ['.png', '.jpg', '.jpeg', '.bmp', '.tiff']
supported_pdf = ['.pdf']
if suffix not in supported_image + supported_pdf:
if verbose:
click.echo(f" 跳过不支持的文件类型:{file_path}")
return {"error": f"不支持的格式:{suffix}", "text": "", "blocks": []}
try:
# 此处调用OCR处理器的识别方法
# 假设ocr_processor.run()方法返回一个包含‘text’和‘blocks’等字段的字典
# 具体API请查阅glm-ocr库的文档
result = ocr_processor.run(str(file_path))
# 确保结果字典中有我们需要的字段
ocr_text = result.get('text', '')
ocr_blocks = result.get('blocks', []) # 假设blocks包含框坐标和文字信息
return {
"file": str(file_path),
"text": ocr_text,
"blocks": ocr_blocks,
"status": "success"
}
except Exception as e:
error_msg = f"处理文件 {file_path} 时出错:{e}"
if verbose:
click.echo(f" {error_msg}", err=True)
return {
"file": str(file_path),
"text": "",
"blocks": [],
"status": "error",
"error": error_msg
}
然后,是遍历目录收集文件的函数。
def collect_files(directory: Path, recursive: bool) -> List[Path]:
"""
收集目录下所有支持处理的文件。
"""
extensions = {'.png', '.jpg', '.jpeg', '.bmp', '.tiff', '.pdf'}
file_list = []
# 根据是否递归选择遍历方法
if recursive:
pattern = '**/*'
else:
pattern = '*'
for ext in extensions:
for file in directory.glob(f'{pattern}{ext}'):
if file.is_file():
file_list.append(file)
# 再匹配一次大写扩展名(虽然不常见)
for file in directory.glob(f'{pattern}{ext.upper()}'):
if file.is_file() and file not in file_list:
file_list.append(file)
return file_list
3. 实现灵活的输入输出
工具的核心能力是处理各种输入,并按照我们想要的方式输出。输入可能是一张图,也可能是一个装满图片的文件夹。输出可能直接显示在屏幕上,也可能要保存成文件。
3.1 处理单个与批量输出
我们之前提到了handle_output和handle_batch_output函数,现在来实现它们。这两个函数负责把OCR识别出来的结果,按照用户选择的格式(txt或json)写到正确的地方。
先看处理单个文件结果的函数:
def handle_output(result: dict, input_path: Path, output_path: Optional[str], output_format: str, verbose: bool):
"""
处理并输出单个文件的结果。
"""
output_text = format_output(result, output_format)
# 决定输出到哪里
if output_path:
output_file = Path(output_path)
# 如果指定的输出路径是个已存在的目录,则在该目录下生成一个与输入文件同名的输出文件
if output_file.is_dir():
output_file = output_file / (input_path.stem + get_extension(output_format))
# 确保输出目录存在
output_file.parent.mkdir(parents=True, exist_ok=True)
try:
with open(output_file, 'w', encoding='utf-8') as f:
f.write(output_text)
if verbose:
click.echo(f"结果已保存至:{output_file}")
except IOError as e:
click.echo(f"写入输出文件失败:{e}", err=True)
else:
# 如果没有指定输出路径,则打印到控制台
click.echo(output_text)
对于批量处理(输入是文件夹),逻辑类似,但我们需要把每个文件的结果组织起来,可以选择输出到一个汇总的文件里,或者为每个输入文件单独生成一个输出文件。
def handle_batch_output(all_results: dict, input_dir: Path, output_path: Optional[str], output_format: str, verbose: bool):
"""
处理并输出批量文件的结果。
"""
if not output_path:
# 如果没有指定输出,则将汇总结果打印到控制台
combined_output = format_batch_output(all_results, output_format)
click.echo(combined_output)
return
output_dir = Path(output_path)
# 如果指定的输出路径不存在,将其视为一个目录名
if not output_dir.exists():
output_dir.mkdir(parents=True, exist_ok=True)
if output_dir.is_dir():
# 模式1:在指定目录下,为每个输入文件生成单独的输出文件
for rel_path, result in all_results.items():
file_stem = Path(rel_path).stem
# 避免子目录结构冲突,这里简单处理,用下划线替换路径分隔符
safe_name = rel_path.replace(os.sep, '_').replace('/', '_').replace('\\', '_')
single_output_file = output_dir / (safe_name + get_extension(output_format))
single_output_file.parent.mkdir(parents=True, exist_ok=True)
single_output_text = format_output(result, output_format)
try:
with open(single_output_file, 'w', encoding='utf-8') as f:
f.write(single_output_text)
except IOError as e:
click.echo(f"写入文件 {single_output_file} 失败:{e}", err=True)
if verbose:
click.echo(f"批量结果已保存至目录:{output_dir}")
else:
# 模式2:指定的输出是一个文件路径,将所有结果汇总写入这一个文件
combined_output = format_batch_output(all_results, output_format)
output_dir.parent.mkdir(parents=True, exist_ok=True)
try:
with open(output_dir, 'w', encoding='utf-8') as f:
f.write(combined_output)
if verbose:
click.echo(f"批量汇总结果已保存至:{output_dir}")
except IOError as e:
click.echo(f"写入汇总文件失败:{e}", err=True)
3.2 格式化输出内容
最后,我们需要两个小函数来把Python字典格式的结果,转换成真正的文本或JSON字符串。
def get_extension(format_type: str) -> str:
"""根据格式类型返回文件扩展名。"""
return '.json' if format_type.lower() == 'json' else '.txt'
def format_output(result: dict, format_type: str) -> str:
"""将单个结果字典格式化为字符串。"""
if format_type.lower() == 'json':
# 使用json.dumps美化输出,缩进4个空格
return json.dumps(result, ensure_ascii=False, indent=4)
else: # txt
# 对于txt格式,我们只输出纯文本内容
return result.get('text', '') + '\n' # 确保末尾有换行
def format_batch_output(all_results: dict, format_type: str) -> str:
"""将批量结果字典格式化为字符串。"""
if format_type.lower() == 'json':
return json.dumps(all_results, ensure_ascii=False, indent=4)
else:
# 对于txt,将所有文件的文本内容拼接起来,用分隔线隔开
output_lines = []
for rel_path, result in all_results.items():
output_lines.append(f"\n{'='*60}")
output_lines.append(f"文件:{rel_path}")
output_lines.append(f"{'='*60}\n")
output_lines.append(result.get('text', ''))
return '\n'.join(output_lines)
4. 工具测试与使用示例
代码写完了,最重要的一步就是测试。我们写几个简单的例子,看看这个工具到底怎么用。
别忘了在ocr_tool.py文件的最后,加上启动的入口:
if __name__ == '__main__':
cli()
现在,打开终端,进入你的项目目录,确保虚拟环境是激活状态,然后就可以开始测试了。
示例1:识别单张图片,结果打印到屏幕
python ocr_tool.py /path/to/your/image.jpg
这会把图片里的文字直接提取出来,显示在终端里。
示例2:识别单张图片,结果保存为JSON文件
python ocr_tool.py /path/to/your/image.jpg -o result.json -f json
这样会生成一个result.json文件,里面不仅包含识别出的文字,还有每个文字块的位置信息,结构非常清晰。
示例3:处理整个文件夹的图片,递归搜索,结果保存到另一个文件夹
python ocr_tool.py /path/to/your/images/ -o ./output_results/ -r -v
加上-r参数,它会自动搜索images文件夹及其所有子文件夹里的图片。加上-v参数,你会看到它处理每个文件的进度信息。所有结果会以单独的.txt文件(默认格式)保存在output_results目录下。
示例4:处理PDF文件,使用快速模式
python ocr_tool.py document.pdf -m fast -o document_text.txt
如果你对速度要求高,可以用-m fast模式。对于纯文本文档的PDF,速度会快很多。
测试的时候,你可能会遇到一些问题,比如某个图片格式不支持,或者PDF文件是加密的。我们代码里已经做了基本的错误捕获,会提示你问题出在哪里。这时候,你可以根据错误信息去调整输入文件,或者看看是不是需要安装额外的库(比如处理PDF可能需要pdf2image库)。
5. 总结与后续优化建议
整个工具做下来,你会发现用Click库开发命令行工具确实很高效。我们只用了一个主函数加几个装饰器,就定义了一套完整的参数规则,还自动生成了帮助文档。核心的OCR功能通过调用成熟的glm-ocr库来实现,我们只需要关注怎么把输入输出和用户指令对接好。
这个工具现在已经具备了基本可用的功能,但如果你愿意,还可以让它变得更强大。比如,可以增加对更多文件格式的支持(像Word、Excel),或者加入图片预处理功能(自动调整角度、去噪),这样对模糊照片的识别率会更高。你还可以把识别后的文本,通过接口直接发送到笔记软件或者数据库里,实现真正的自动化流水线。
最关键的是,这个工具完全运行在你自己的电脑上,所有数据都不会离开本地,对于处理敏感文档来说,这是最大的优势。你可以放心地把它集成到你的自动化脚本、爬虫项目或者日常的工作流里,让它成为你的得力助手。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐


所有评论(0)