PDF 解析
这是一篇阅读笔记。从PDF 中提取数据(包含格式信息)可以用在很多很多地方,比如文档总结、翻译等。本文的整体思路结构比较清晰,可以在今后的代码中重点参考下。
代码流程图
flowchart TD
A[PDF 文件] --> |PDFMiner| B(提取页面(数组))
B --> |PDFMiner| C[[页面布局]]
C --> D([LTTextContainer 文本容器]) --> |通过pdfminer 提取文本| G([通过LTTextLine/LTChar 逐行/逐字符分析样式])
C --> E([LTFigure 图片]) --> |通过pdf2image 提取图片|H([通过pytesseract OCR 识别文本])
C --> F([LTRect 二维矩形,一般为图形或图表]) --> |通过pdfplumber 提取表格❌|I([将表格内容转化为字符串])
G --> J[[将解析后的内容形成字典对象]]
H --> J
I --> J
J --> |整合数据| K[输出页面文本]
需要的工具包:
pip install PyPDF2 # 从路径读取PDF 文件
pip install pdfmner.six # 提取文本和格式,支持Python 3
pip install pdfplumber # 识别table 并提取信息(似乎有些表格无法识别)
pip install pdf2image # 裁剪pdf 并转化为PNG 图像
pip install Pillow # 图像处理
pip install tesseract # OCR 工具,但是需要提前安装二进制文件
代码解析
import pdfplumber
import pytesseract
from PIL import Image
from PyPDF2 import PdfReader,PageObject,PdfWriter
from pdf2image import convert_from_path
from pdfminer.high_level import extract_pages, extract_text
from pdfminer.layout import LTTextContainer, LTChar, LTRect, LTFigure
pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract'
poppler_path=r'D:\utils\poppler-24.08.0\Library\bin'
pdf_file_path = 'DeepSeek_R1.pdf'
pdfFileObj = open(pdf_file_path, 'rb')
pdfReaded = PdfReader(pdfFileObj)
pdf_pages = extract_pages(pdf_file_path) # 读取文件
for page_num, page in enumerate(pdf_pages):
# 逐页处理
print(f"正在处理第{page_num+1} 页内容")
pageObj = pdfReaded.pages[page_num]
for element in page:
print(f" 处理元素<{type(element).__name__}>") # 这里的element 不仅带有文本,还带有位置信息
if isinstance(element, LTTextContainer): # 处理文本内容
print(f" 文本域<LTTextContainer>:BBox{element.bbox}")
extract_text(element)
elif isinstance(element, LTFigure): # OCR 识别图片
print(f" 图片<LTFigure>:BBox{element.bbox}")
crop_image(element, pageObj)
convert_pdf_to_image()
text = image_to_text()
print("OCR 结果:::", text)
elif isinstance(element, LTRect):
print(f" 图形图表<LTRect>:BBox{element.bbox}")
# 处理表格,但是验证代码似乎并不完善
else:
print(f" 其他元素类型:BBox{element.bbox}")
if page_num >= 0:
break # 只处理第一页用作演示
提取文本
提取LTTextContainer 中的内容是,并不会查找表格中的文本内容,所以不用担心混乱出错:
def extract_text(element: LTTextContainer):
text = element.get_text() # 所有文本
# # 逐字处理文本,计算量大,视情况可以忽略格式信息
# content = []
# for line in element:
# line_content = []
# for charactor in line:
# if isinstance(charactor, LTChar):
# line_content.append({
# "v":charactor.get_text(), # 值
# "f":charactor.fontname, # 字体
# "s":charactor.size # 大小
# })
# content.append(line_content)
print("》》》")
print(text)
print("《《《\n\n")
识别图片
temp_file_name = "temp" # 假定文件名,其实这里可以生成唯一文件名的
def crop_image(element:LTFigure, pageObj:PageObject):
# 图片的边界信息,裁剪
[l,t,r,b] = [element.x0, element.y0, element.x1, element.y1]
pageObj.mediabox.lower_left = (l, b)
pageObj.mediabox.upper_right = (r, t)
# 保存裁剪后的图片
cropped_pdf_writer = PdfWriter()
cropped_pdf_writer.add_page(pageObj)
# 保存到临时文件
with open(f'{temp_file_name}.pdf', 'wb') as f:
cropped_pdf_writer.write(f)
def convert_pdf_to_image(input_file=f'{temp_file_name}.pdf'):
# pdf 转图片
images = convert_from_path(input_file,poppler_path=poppler_path)
image = images[0]
image.save(f"{temp_file_name}.png", "PNG")
def image_to_text(image_file = f"{temp_file_name}.png"):
# OCR 识别文本
image = Image.open(image_file)
text = pytesseract.image_to_string(image)
return text
提取表格
提取表格的代码实际工作起来有些问题,最好还是通过其他工具来识别吧。或者干脆跳过图片和表格的处理:
def extract_table( page_num, table_num):
pdf = pdfplumber.open(pdf_file_path)
table_page = pdf.pages[page_num]
print(table_page)
table = table_page.extract_tables()[page_num]
def table_converter(table):
table_str = ""
for row_num in range(len(table.extract())): # 这里原先的方法已经不适用了
row = table[row_num]
clean_row = [item.replace('\n', '') if item is not None and '\n' in item else 'None' if item is None else item for item in row]
table_str += f"|{'|'.join(clean_row)}|"+"\n"
print(row)
return table_str[:-1]
相比之下,通过python-docx/openpyxl/python-pptx 处理office 更简单一些。