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_list3. 实现灵活的输入输出
工具的核心能力是处理各种输入,并按照我们想要的方式输出。输入可能是一张图,也可能是一个装满图片的文件夹。输出可能直接显示在屏幕上,也可能要保存成文件。
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星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
