0%

用Tesseract批量提取中文PDF文件文本

本文展示如何用Python编写一个自动化工具,批量提取PDF中的文字内容。

这里从一个实际的Python脚本出发,详细讲解OCR(光学字符识别)技术的原理和应用,适合编程小白和技术爱好者阅读。

什么是OCR技术?

基本概念

OCR(Optical Character Recognition,光学字符识别)是指电子设备(如扫描仪或数码相机)检查纸上打印的字符,通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机文字的过程。

OCR的工作原理

  1. 图像预处理:对输入图像进行降噪、二值化、倾斜校正等处理
  2. 文字定位:找到图像中文字所在的位置
  3. 字符分割:将文字行分割成单个字符
  4. 特征提取:提取每个字符的特征
  5. 字符识别:将特征与字符库进行匹配,识别出对应字符
  6. 后处理:对识别结果进行校正和优化

    Tesseract OCR引擎

这里使用的Tesseract是一个开源的OCR引擎,最初由惠普开发,后由Google维护。它支持超过100种语言,包括中文简体和繁体。

项目需求分析

这个工具要实现的功能包括:

  • 批量读取指定目录下的PDF文件
  • 将PDF页面转换为图像
  • 对图像进行OCR文字识别
  • 将识别结果保存为文本文件
  • 提供友好的进度提示和错误处理

核心技术栈

Python库介绍

  1. pytesseract:Tesseract OCR的Python封装
  2. pypdfium2:PDF处理库,用于将PDF页面转换为图像
  3. PIL(Pillow):Python图像处理库
  4. os和glob:用于文件和目录操作

代码实现详解

下面来逐段分析这个73行的Python脚本:

1. 导入必要的库

1
2
3
4
5
import pytesseract          # Tesseract OCR封装
import pypdfium2 as pdfium  # PDF处理
from PIL import Image       # 图像处理
import os                   # 操作系统接口
import glob                 # 文件模式匹配

这里导入了所有需要的第三方库。每个库都有其特定的用途,缺一不可。

2. 路径配置

1
2
3
INPUT_DIR = './pdfs/'       # PDF文件输入目录
OUTPUT_DIR = './out/'       # 文本文件输出目录
PDF_PATTERN = os.path.join(INPUT_DIR, '*.pdf'# PDF文件匹配模式

这里使用了硬编码的路径配置。os.path.join()是一个很好的实践,它可以自动处理不同操作系统的路径分隔符差异。

3. 输出目录创建

1
2
3
if not os.path.exists(OUTPUT_DIR):
    os.makedirs(OUTPUT_DIR)
    print(f"✅ 创建输出目录: {OUTPUT_DIR}")

这是一个防御性编程的例子。程序在开始处理前先检查输出目录是否存在,如果不存在就创建它,避免后续操作因目录不存在而失败。

4. 文件发现和验证

1
2
3
4
5
6
7
pdf_files = glob.glob(PDF_PATTERN)

if not pdf_files:
    print(f"⚠️ 警告: 未在目录 {INPUT_DIR} 中找到任何 PDF 文件。请确保该目录存在且包含 PDF 文件。")
   
total_files = len(pdf_files)
print(f"共找到 {total_files} 个 PDF 文件待处理。")

glob.glob()是一个非常实用的函数,它可以根据通配符模式查找匹配的文件。这里用*.pdf模式查找所有PDF文件。

5. 核心处理循环

1
2
3
4
5
6
for index, pdf_path in enumerate(pdf_files):
    filename_with_ext = os.path.basename(pdf_path)
    filename_base = os.path.splitext(filename_with_ext)[0]
    output_txt_path = os.path.join(OUTPUT_DIR, f"{filename_base}.txt")

    print(f"[{index + 1}/{total_files}] 正在处理文件: {filename_with_ext}...")

这里使用了几个重要的文件操作技巧:

  • os.path.basename():提取文件名(不含路径)
  • os.path.splitext():分离文件名和扩展名
  • enumerate():同时获取索引和值,便于显示进度

    6. PDF处理核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
doc = pdfium.PdfDocument(pdf_path)
n_pages = len(doc)

with open(output_txt_path, 'w', encoding='utf-8') as f_out:
    for i in range(n_pages):
        page = doc.get_page(i)

        # 渲染 PDF 页面为 PIL 图像对象 (高分辨率 3.0)
        bitmap = page.render(scale=3.0)
        pil_image = bitmap.to_pil()

        # 执行 Tesseract OCR 识别
        text = pytesseract.image_to_string(pil_image, lang='chi_sim', config='--psm 6')
        # 写入 TXT 文件
        f_out.write(f"\n======== Page {i + 1} ========\n")
        f_out.write(text.strip() + "\n")

这段代码是整个脚本的核心,让我们详细分析每个步骤:

PDF页面渲染

1
2
bitmap = page.render(scale=3.0)
pil_image = bitmap.to_pil()
  • scale=3.0:将页面放大3倍渲染。为什么要放大?因为OCR引擎在处理高分辨率图像时识别准确率更高
  • to_pil():将位图转换为PIL图像对象,这是Tesseract需要的格式

OCR识别

1
text = pytesseract.image_to_string(pil_image, lang='chi_sim', config='--psm 6')

这里的参数很重要:

  • lang='chi_sim':指定使用中文简体语言模型
  • config='--psm 6':页面分割模式6,表示”假定单一统一文本块”

Tesseract支持多种页面分割模式(PSM):

  • 0: 定向和脚本检测(OSD)仅
  • 1: 带有OSD的OCR
  • 2: 自动页面分割,但无OSD或OCR
  • 3: 完全自动页面分割,但没有OSD(默认)
  • 4: 假定单列文本
  • 5: 假定垂直对齐文本的单个统一文本块
  • 6: 假定单个统一的文本块
  • 7: 将图像视为单个文本行
  • 8: 将图像视为单个单词
  • 9: 将图像视为圆中的单个单词
  • 10: 将图像视为单个字符

对于文档类的PDF,模式6通常是最佳选择。

7. 错误处理

1
2
3
4
except pytesseract.TesseractNotFoundError:
    print("致命错误:Tesseract OCR 引擎未安装或未在系统路径中。请确保已安装 `tesseract-ocr`。")
except Exception as e:
    print(f"发生总体错误:{e}")

这里采用了分层错误处理:

  • 特定异常(Tesseract未找到)提供具体的解决建议
  • 通用异常捕获其他所有错误

技术要点解析

1. 图像分辨率的重要性

OCR识别的准确率很大程度上取决于输入图像的质量。代码中使用scale=3.0将PDF页面放大3倍,这有几个好处:

  • 更高的细节保留:小字体和复杂字符更加清晰
  • 更好的字符分割:字符边缘更加明显,便于算法识别
  • 减少识别错误:特别是在处理中文这样复杂的字符时

2. 中文OCR的特殊考虑

中文OCR相比英文有更多挑战:

  • 字符集庞大:中文有几万个常用汉字
  • 字符复杂:笔画多、结构复杂
  • 字体多样性:宋体、黑体、楷体等
  • 排版复杂:横排、竖排、混合排版

因此,选择合适的语言模型和页面分割模式至关重要。

3. 内存管理

对于大PDF文件,需要注意内存使用:

1
with open(output_txt_path, 'w', encoding='utf-8') as f_out:

使用with语句确保文件正确关闭,避免内存泄漏。

4. 进度反馈

用户体验很重要:

1
print(f"[{index + 1}/{total_files}] 正在处理文件: {filename_with_ext}...")

清晰的进度提示让用户了解处理状态,特别是在处理大量文件时。

实际应用场景

这种OCR工具有很多实际应用:

  1. 文档数字化:将纸质文档扫描件转换为可搜索的文本
  2. 数据提取:从报表、表格中提取结构化数据
  3. 文档归档:建立文档的全文检索系统
  4. 多语言处理:处理包含多种语言的文档
  5. 自动化办公:批量处理文档,提高工作效率

性能优化建议

如果想进一步提升性能,可以考虑:

  1. 并行处理:使用多线程或异步IO处理多个文件
  2. 图像预处理:添加去噪、锐化等预处理步骤
  3. 缓存机制:避免重复处理相同的文件
  4. 批处理优化:合理控制同时处理的文件数量
  5. 内存监控:监控内存使用,避免处理超大文件时内存溢出

扩展功能

基于这个基础版本,还可以添加很多功能:

  1. GUI界面:使用tkinter或PyQt创建图形界面
  2. 配置文件:将硬编码的配置提取到配置文件
  3. 日志记录:添加详细的日志记录功能
  4. 结果校验:添加OCR结果的校验和修正机制
  5. 格式支持:支持更多输入格式(图片、Word等)
  6. 语言检测:自动检测文档语言并选择相应的OCR模型

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import pytesseract
import pypdfium2 as pdfium
from PIL import Image
import os
import glob # 用于查找文件

# --- 路径配置 ---
INPUT_DIR = './pdfs/'
OUTPUT_DIR = './out/'

# PDF 文件通配符
PDF_PATTERN = os.path.join(INPUT_DIR, '*.pdf')

# --- 1. 创建输出目录 ---
if not os.path.exists(OUTPUT_DIR):
    os.makedirs(OUTPUT_DIR)
    print(f"✅ 创建输出目录: {OUTPUT_DIR}")

# --- 2. 处理所有 PDF 文件 ---
try:
    # 查找所有匹配的文件路径
    pdf_files = glob.glob(PDF_PATTERN)

    if not pdf_files:
        print(f"⚠️ 警告: 未在目录 {INPUT_DIR} 中找到任何 PDF 文件。请确保该目录存在且包含 PDF 文件。")
    total_files = len(pdf_files)
    print(f"共找到 {total_files} 个 PDF 文件待处理。")
    print("---------------------------------------")

    for index, pdf_path in enumerate(pdf_files):
        # 获取文件名 (带扩展名)
        filename_with_ext = os.path.basename(pdf_path)
        # 获取不带扩展名的文件名
        filename_base = os.path.splitext(filename_with_ext)[0]
        # 构建输出 TXT 文件的完整路径
        output_txt_path = os.path.join(OUTPUT_DIR, f"{filename_base}.txt")

        print(f"[{index + 1}/{total_files}] 正在处理文件: {filename_with_ext}..."
       
        try:
            doc = pdfium.PdfDocument(pdf_path)
            n_pages = len(doc)

            with open(output_txt_path, 'w', encoding='utf-8') as f_out:
                for i in range(n_pages):
                    page = doc.get_page(i)
                    # 渲染 PDF 页面为 PIL 图像对象 (高分辨率 3.0)
                    bitmap = page.render(scale=3.0)
                    pil_image = bitmap.to_pil()

                    # 执行 Tesseract OCR 识别
                    # lang='chi_sim' (中文)
                    # config='--psm 6' (单列文本块模式)
                    text = pytesseract.image_to_string(pil_image, lang='chi_sim', config='--psm 6')

                    # 写入 TXT 文件
                    f_out.write(f"\n======== Page {i + 1} ========\n")
                    f_out.write(text.strip() + "\n")

            print(f"    -> 成功保存识别结果到 {output_txt_path}")

        except Exception as e:
            print(f"    ❌ 处理文件 {filename_with_ext} 时发生错误: {e}")
            continue # 跳过当前文件,继续下一个

    print("\n✅ 所有文件处理完毕。")

except pytesseract.TesseractNotFoundError:
    print("致命错误:Tesseract OCR 引擎未安装或未在系统路径中。请确保已安装 `tesseract-ocr`。")
except Exception as e:
    print(f"发生总体错误:{e}")

总结

通过这个73行的Python脚本,实现了一个功能完整的PDF OCR处理工具。虽然代码简洁,但涵盖了很多重要的编程概念和技术要点:

  • 文件和目录操作
  • 异常处理
  • 第三方库的使用
  • OCR技术的实际应用
  • 用户体验设计

对于编程小白来说,这个项目是一个很好的学习起点,既有实用价值,又涵盖了多种技术概念。对于有经验的开发者,这个基础版本也可以作为更复杂OCR系统的起点。

技术的价值在于解决实际问题。希望这篇文章能帮助理解OCR技术,并启发你创造更多有用的工具!