PDF中表格的处理 (OCR)

文章目录

  • [一、对于表格,可以借助 Python 的pdfplumber库](#一、对于表格,可以借助 Python 的pdfplumber库)
  • 二、对于图片,可以借助PyMuPDF库提取图片并保存
  • [三、OCR 接口 处理 图片中的表格](#三、OCR 接口 处理 图片中的表格)
    • [3.1 OCR 识别表格的核心原理](#3.1 OCR 识别表格的核心原理)
    • [3.2 主流的 OCR 接口](#3.2 主流的 OCR 接口)
    • [3.3 代码案例](#3.3 代码案例)
      • [3.3.1 腾讯云 OCR(云服务,上手快)](#3.3.1 腾讯云 OCR(云服务,上手快))
      • [3.3.2 PaddleOCR(开源本地,免费无联网)](#3.3.2 PaddleOCR(开源本地,免费无联网))
  • 四、优化点
    • [4.1 图片预处理](#4.1 图片预处理)
    • [4.2 选择合适的接口](#4.2 选择合适的接口)
    • [4.3 '可编辑' PDF 和 '扫描版' PDF](#4.3 ‘可编辑’ PDF 和 ‘扫描版’ PDF)

一、对于表格,可以借助 Python 的pdfplumber库

● 找到对应页,创建 page 对象,然后调用 extract_table 方法,就可变读到这个表格转变成 tabel 对象

● 最后 tabel 对象的数据转换成 Dataframe 对象

● 将 df 对象 to_excel 转换成 excel 文件

python 复制代码
import pdfplumber
import pandas as pd

with pdfplumber.open("file.pdf") as pdf:
    page = pdf.pages[0]  # 选择第一页
    table = page.extract_table()  # 提取表格数据
df = pd.DataFrame(table[1:], columns=table[0])  # 转换为DataFrame
df.to_excel("table_data.xlsx", index=False)  # 保存为Excel

二、对于图片,可以借助PyMuPDF库提取图片并保存

python 复制代码
import fitz

pdf = fitz.open("file.pdf")
for page_num in range(len(pdf)):
    page = pdf[page_num]
    img_list = page.get_images(full=True)
    for img_idx, img in enumerate(img_list):
        xref = img[0]
        base_image = pdf.extract_image(xref)
        image_bytes = base_image["image"]
        with open(f"page_{page_num}_img_{img_idx}.png", "wb") as f:
            f.write(image_bytes)

三、OCR 接口 处理 图片中的表格

OCR (Optical Character Recognition,光学字符识别)接口是处理扫描版 PDF(图片格式 PDF)或图片中表格的核心工具。

这类图片中的表格无法通过常规 PDF 解析工具(如上述说到的 pdfplumber)直接提取结构,需要先通过 OCR 将图像中的文字和表格结构转换为可编辑的文本/数据格式。

3.1 OCR 识别表格的核心原理

扫描版 PDF/图片中的表格无"行列结构信息",OCR 接口通过两步(1,2)实现识别:

  1. 表格结构分析:先识别图像中的"表格边框、单元格分割线",确定表格的行数、列数、单元格位置。
  2. 文本内容提取:对每个单元格内的图像文字进行 OCR 识别,将像素文字转化为可复制的文本。
  3. 结构化输出:将"单元格位置"与"识别文本"对应,生成 excel、csv、json 等结构化格式,便于后续继续分析。

总结:通过表格的骨架找到表格位置和基本信息(行、列数等),再通过 OCR 识别图像中表格里面的文字,最后存储文本。

3.2 主流的 OCR 接口

目前主流的 OCR 接口分为两种,一种是无需本地部署适合快速开发的"云服务接口",一种是需要本地部署适合隐私敏感场景的"开源本地接口"。

3.3 代码案例

3.3.1 腾讯云 OCR(云服务,上手快)

腾讯云 OCR 提供免费额度(新用户 1 万次/月),支持直接上传图片/PDF,输出 Excel 格式表格数据,步骤如下:

  1. 准备工作:注册腾讯云(https://cloud.tencent.com/)账号,在"控制台-访问管理"中创建 secretID 和 SecretKey

  2. 开通文字识别服务

  3. 安装腾讯云 SDK:pip install tencentcloud-sdk-python

  4. API 文档:https://cloud.tencent.com/document/api/866/34936#6.-.E9.94.99.E8.AF.AF.E7.A0.81

python 复制代码
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.ocr.v20181119 import ocr_client, models

def tencent_ocr_table(image_path, secret_id, secret_key):
    # 1. 配置API凭证和客户端
    cred = credential.Credential(secret_id, secret_key)
    httpProfile = HttpProfile()
    httpProfile.endpoint = "ocr.tencentcloudapi.com"  # OCR接口域名
    clientProfile = ClientProfile()
    clientProfile.httpProfile = httpProfile
    client = ocr_client.OcrClient(cred, "ap-beijing", clientProfile)  # 地域选就近的(如ap-shanghai)

    # 2. 读取图片文件(转为base64格式,腾讯云要求)
    import base64
    with open(image_path, "rb") as f:
        image_base64 = base64.b64encode(f.read()).decode("utf-8")

    # 3. 构造请求参数(指定表格识别)
    req = models.TableOCRRequest()
    req.ImageBase64 = image_base64  # 若传PDF,用req.PdfFileBase64;支持单页PDF
    #req.OutputFormat = "xlsx"  # 输出格式:Excel/CSV/JSON (废弃了这个参数)

    # 4. 调用接口并获取结果
    resp = client.TableOCR(req)
    result = resp.to_json_string()
    print("识别结果(JSON):", result)

    # 5. 提取Excel下载链接(腾讯云会生成临时Excel文件,有效期1小时)
    import json
    resp_dict = json.loads(result)
    excel_url = resp_dict["ExcelUrl"]
    print("表格Excel下载链接:", excel_url)

    # (可选)下载Excel到本地
    import requests
    excel_response = requests.get(excel_url)
    with open("table_result.xlsx", "wb") as f:
        f.write(excel_response.content)
    print("Excel已保存到本地:table_result.xlsx")

# 调用函数(替换为你的SecretId、SecretKey和图片路径)
tencent_ocr_table(
    image_path="test_table.png",  # 扫描版表格图片(或单页PDF)
    secret_id="xxxxxxx",
    secret_key="xxxxxxx"
)

这个是需要付费的,所以这不演示了

3.3.2 PaddleOCR(开源本地,免费无联网)

PaddleOCR 是百度开源的 OCR 工具,中文识别精度高,表格识别模块支持本地部署,步骤如下:

  1. 前置准备:
    ○ 安装依赖:pip install paddlepaddle paddleocr;
    ○ 自动下载预训练模型(首次运行时会自动下载,无需手动配置)。
  2. 代码实现(识别 PDF / 图片中的表格):
python 复制代码
from paddleocr import PaddleOCR
import os

def paddle_ocr_table(input_path, output_dir="paddle_ocr_result"):
    # 1. 初始化OCR模型(指定语言为中文,开启表格识别)
    # use_angle_cls=True:自动纠正倾斜图片;table=True:开启表格识别
    ocr = PaddleOCR(use_angle_cls=True, lang="ch", table=True)

    # 2. 创建输出目录(保存识别结果和Excel)
    os.makedirs(output_dir, exist_ok=True)

    # 3. 调用表格识别接口(支持图片或多页PDF)
    # 若输入是PDF,会自动处理每一页;output excel_path:指定Excel保存路径
    result = ocr.ocr_table(
        img_path=input_path,
        output excel_path=os.path.join(output_dir, "table_result.xlsx")
    )

    # 4. 解析识别结果(result包含每个单元格的文本和位置)
    print("表格识别完成,结果如下:")
    for page_idx, page_result in enumerate(result):
        print(f"\n第{page_idx+1}页表格:")
        # page_result[0]:表格文本内容(二维列表,对应行和列)
        # page_result[1]:表格位置信息(暂用不到)
        table_text = page_result[0]
        for row_idx, row in enumerate(table_text):
            print(f"第{row_idx+1}行:", row)

    print(f"\nExcel文件已保存到:{os.path.join(output_dir, 'table_result.xlsx')}")

# 调用函数(输入可以是图片路径,或多页PDF路径)
paddle_ocr_table(
    input_path="test_table.pdf",  # 支持多页PDF或图片
    output_dir="my_ocr_result"
)

四、优化点

4.1 图片预处理

如表格倾斜、模糊,可以先通过工具(如 OpenCV)进行'倾斜矫正''降噪''增阿强对比度'

安装依赖:pip install opencv-python numpy matplotlib

python 复制代码
import cv2
import numpy as np
import matplotlib.pyplot as plt

def preprocess_table_image(image_path, output_path="processed_table.jpg"):
    """
    预处理表格图片:倾斜矫正、降噪、增强对比度
    :param image_path: 原始图片路径
    :param output_path: 处理后图片保存路径
    :return: 处理后的图片
    """
    # 1. 读取图片并转为灰度图
    img = cv2.imread(image_path)
    if img is None:
        raise ValueError(f"无法读取图片: {image_path}")
    
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    plt.figure(figsize=(15, 10))
    plt.subplot(2, 3, 1)
    plt.imshow(gray, cmap='gray')
    plt.title('1. 原始灰度图')

    # 2. 降噪处理(根据图片质量选择合适的方法)
    # 方法1:中值滤波(适合去除椒盐噪声)
    denoised = cv2.medianBlur(gray, ksize=3)
    # 方法2:高斯滤波(适合去除高斯噪声)
    # denoised = cv2.GaussianBlur(gray, (3, 3), 0)
    
    plt.subplot(2, 3, 2)
    plt.imshow(denoised, cmap='gray')
    plt.title('2. 降噪后')

    # 3. 增强对比度(自适应阈值处理)
    # 适合光照不均匀的图片,将灰度图转为二值图(黑白)
    thresh = cv2.adaptiveThreshold(
        denoised, 255, 
        cv2.ADAPTIVE_THRESH_GAUSSIAN_C,  # 高斯加权计算阈值
        cv2.THRESH_BINARY_INV,  # 反二进制阈值(文字为白,背景为黑)
        11,  # 块大小
        2    # 常数,用于调整阈值
    )
    
    plt.subplot(2, 3, 3)
    plt.imshow(thresh, cmap='gray')
    plt.title('3. 对比度增强后')

    # 4. 检测表格轮廓,用于倾斜角度计算
    # 查找轮廓
    contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # 筛选出面积最大的轮廓(假设是表格边框)
    if contours:
        largest_contour = max(contours, key=cv2.contourArea)
        
        # 计算最小外接矩形(获取倾斜角度)
        rect = cv2.minAreaRect(largest_contour)
        angle = rect[-1]
        
        # 调整角度(OpenCV角度范围处理)
        if angle < -45:
            angle = 90 + angle
        elif angle > 45:
            angle = angle - 90

        # 5. 倾斜矫正
        if abs(angle) > 0.5:  # 角度大于0.5度才进行矫正
            (h, w) = thresh.shape[:2]
            center = (w // 2, h // 2)
            # 计算旋转矩阵
            M = cv2.getRotationMatrix2D(center, angle, 1.0)
            # 执行旋转(保持原图大小)
            rotated = cv2.warpAffine(
                thresh, M, (w, h),
                flags=cv2.INTER_CUBIC,
                borderMode=cv2.BORDER_REPLICATE  # 边缘填充方式
            )
        else:
            rotated = thresh
        
        plt.subplot(2, 3, 4)
        plt.imshow(rotated, cmap='gray')
        plt.title(f'4. 倾斜矫正后 (角度: {angle:.2f}°)')
    else:
        # 如果未检测到轮廓,直接使用阈值处理后的图片
        rotated = thresh
        plt.subplot(2, 3, 4)
        plt.imshow(rotated, cmap='gray')
        plt.title('4. 未检测到轮廓,跳过矫正')

    # 6. 最终处理:去除小噪点(可选)
    # 创建结构元素
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2, 2))
    # 形态学闭运算(填充小空洞)
    processed = cv2.morphologyEx(rotated, cv2.MORPH_CLOSE, kernel)
    # 形态学开运算(去除小噪点)
    processed = cv2.morphologyEx(processed, cv2.MORPH_OPEN, kernel)
    
    plt.subplot(2, 3, 5)
    plt.imshow(processed, cmap='gray')
    plt.title('5. 去除小噪点后')

    # 保存处理后的图片
    cv2.imwrite(output_path, processed)
    print(f"处理完成,图片已保存至: {output_path}")

    plt.tight_layout()
    plt.show()
    return processed

# 示例用法
if __name__ == "__main__":
    # 替换为你的表格图片路径(支持倾斜、模糊的表格图片)
    input_image = "tilted_blurry_table.jpg"
    # 执行预处理
    processed_img = preprocess_table_image(input_image)

4.2 选择合适的接口

中文表格优先使用 PaddleOCR 或百度云 OCR;

英文/多语言 表格 有限用阿里云或者谷歌的 OCR

复杂表格(合并单元格,嵌套表格),优先使用阿里云的云服务接口

4.3 '可编辑' PDF 和 '扫描版' PDF

可编辑(如 Word 导出的 PDF),优先使用 pdfplumber 直接提取表格,无需使用 OCR

扫描版的 PDF,其本质是图片,需要使用 OCR 接口

相关推荐
私人珍藏库3 小时前
[Windows] 发票识别工具。支持xml、pdf、ofd文件
xml·pdf
reasonsummer3 小时前
【办公类-115-01】20250920职称资料上传01——多个jpg转同名PDF(如:荣誉证书)并自动生成单一文件夹
pdf
孤客网络科技工作室1 天前
Python - 100天从新手到大师:第二十七天Python操作PDF文件
开发语言·python·pdf
Bella_chene2 天前
Excel转PDF不分页
pdf·excel
RuiyuanZHOU2 天前
tkinter+pymupdf开发的简单pdf查看编辑器
pdf·tkinter·pymupdf
诗句藏于尽头2 天前
关于win11的Microsoft To Pdf打印机修改端口后无法再刷新显示于设备界面的问题
pdf
Time_Memory_cici2 天前
Wiley出版社WileyNJDv5_Template模板编译不能生成PDF解决办法
pdf
NON-JUDGMENTAL3 天前
《Local_Pdf_Chat_RAG 深度学习笔记:PDF 本地化对话的 RAG 原理与实践》
笔记·pdf
Metaphor6923 天前
Java 旋转 PDF 页面:使用 Spire.PDF 实现高效页面处理
java·经验分享·pdf