文章目录
- [一、对于表格,可以借助 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)实现识别:
- 表格结构分析:先识别图像中的"表格边框、单元格分割线",确定表格的行数、列数、单元格位置。
- 文本内容提取:对每个单元格内的图像文字进行 OCR 识别,将像素文字转化为可复制的文本。
- 结构化输出:将"单元格位置"与"识别文本"对应,生成 excel、csv、json 等结构化格式,便于后续继续分析。
总结:通过表格的骨架找到表格位置和基本信息(行、列数等),再通过 OCR 识别图像中表格里面的文字,最后存储文本。
3.2 主流的 OCR 接口
目前主流的 OCR 接口分为两种,一种是无需本地部署适合快速开发的"云服务接口",一种是需要本地部署适合隐私敏感场景的"开源本地接口"。
3.3 代码案例
3.3.1 腾讯云 OCR(云服务,上手快)
腾讯云 OCR 提供免费额度(新用户 1 万次/月),支持直接上传图片/PDF,输出 Excel 格式表格数据,步骤如下:
-
准备工作:注册腾讯云(https://cloud.tencent.com/)账号,在"控制台-访问管理"中创建 secretID 和 SecretKey
-
开通文字识别服务
-
安装腾讯云 SDK:pip install tencentcloud-sdk-python
-
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 工具,中文识别精度高,表格识别模块支持本地部署,步骤如下:
- 前置准备:
○ 安装依赖:pip install paddlepaddle paddleocr;
○ 自动下载预训练模型(首次运行时会自动下载,无需手动配置)。 - 代码实现(识别 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 接口