pdf 版面分析与优化策略

1. 简介

版面分析作为RAG的第一步工作,其效果对于下游工作至关重要。
在这里插入图片描述

前常见的 PDF 解析方法包括三种

  • 基于规则:根据 PDF 的组织特征确定每个部分的规则(风格和内容)缺点:不通用(PDF格式不固定)
  • 基于深度学习:目标检查和 OCR 结合的流行解决方案
  • 基于多模态大模型:对复杂的结构进行Pasing或提取PDF中的关键信息

1.1 基于规则的pdf解析

代表框架:

  • pdfplumber
  • PyMuPDF
  • pypdf
1.1.1 pdfplumber

pdfplumber 按照每一页处理 pdf,获得 pdf 的页面文字提取表格,最终将 pdf 文件生成对应的 txt 文件。
缺点:按页进行处理有时候一段上下文连续的文字,分散到两页并不好进行处理。

## 纯文本
file_name = './example_data/焦点科技__2019年__年度报告.pdf'
output_file = './example_data/焦点科技__2019年__年度报告.txt'
with pdfplumber.open(file_name) as pdf, open(output_file, 'wt', encoding='utf-8') as f:
	for page in pdf.pages: # pdf.pages是⼀个Page对象的列表
		text = page.extract_text() # 调⽤Page对象的extract_text()⽅法提取⽂本
		f.write(text)
		f.write('\n')
		
## 表格
with pdfplumber.open(file_name) as pdf, open(output_file, 'wt', encoding='utf-8') as f:
	for page in pdf.pages: # pdf.pages是⼀个Page对象的列表
		text = page.extract_table() # 提取每⻚的表格⽂字信息
		# page.extract_tables() 提取多个表格
		print(text)
		if text:
			f.write(str(text))
			f.write('\n')
			
## 表格保存为excel
from openpyxl import Workbook
with pdfplumber.open(file_name) as pdf:
	for i in pdf.pages:
		table = i.extract_table()
		if table:
			workbook = Workbook() # 创建⼀个⼯作簿
			sheet = workbook.active # 获取当前活跃的sheet,默认是第⼀个sheet
			for row in table:
				sheet.append(row)
				workbook.save(output_file) # 保存⼯作簿
				break

## 提取图片保存到本地
with pdfplumber.open(file_name) as pdf:
	for i in pdf.pages:
	print('⻚码:', i.page_number)
	print('⻚宽:', i.width)
	print('⻚⾼:', i.height)
	print('⻚⽂本:', i.extract_text())
	print('⻚表格:', i.extract_table())
	print('⻚图⽚:', i.images)
	for img in i.images:
		# 获取图⽚的⼆进制流
		img_data = img['stream'].get_data()
		with open(output_file, 'wb') as f:
			f.write(img_data)
	break # 解析第⼀⻚
1.1.2 pymupdf

pymupdf 支持将文字修改写入 pdf 的界面,支持提取所有类型的文档,支持的功能特别多,基本上各种文件都可以处理

import fitz
pdf_path = '/example_data/安靠智电__2019年__年度报告.pdf'
doc = fitz.open(pdf_path)

# 基本的pdf信息
title = doc.metadata['title'] # 标题
author = doc.metadata['author'] # 作者
create_time = doc.metadata['creationDate'] # 创建时间
num_pages = doc.page_count # ⻚数
page = doc.load_page(0) # 加载第⼀⻚
page_width = page.rect.width # ⻚宽
page_height = page.rect.height # ⻚⾼
page_text = page.get_text() # ⻚⽂本
page_images = page.get_images(full=True) # ⻚图⽚
print('标题:', title)
print('作者:', author)
print('创建时间:', create_time)
print('⻚数:', num_pages)
print('⻚码:', 1)
print('⻚宽:', page_width)
print('⻚⾼:', page_height)
print('⻚⽂本:', page_text)
print('⻚图⽚:', page_images)


num_pages = doc.page_count # ⻚数
for page_index in range(num_pages):
	page = doc.load_page(page_id=page_index)
	page_text = page.get_text() # ⻚⽂本
	print(page_text)
	break
	
for page_index in range(num_pages):
	page = doc.load_page(page_id=page_index)
	image_list = page.get_images() # 图⽚
	print(image_list)
	# 两种⽅式
	# 1
	for img in image_list:
		xref = img[0]
		base_image = doc.extract_image(xref)
		image_bytes = base_image["image"] # 图⽚⼆进制数据
		image_ext = base_image["ext"] # 图⽚格式
		# image_path = f'./example_data/__焦点科技__2019年__年度报告__page_{page_index}__image_{xref}.{image_ext}'
		# with open(image_path, 'wb') as f:
		# f.write(image_bytes)
	# 2
	pix = fitz.Pixmap(doc, xref)
	pix.save(f'./example_data/焦点科技__2019年__年度报告__page_{page_index}__image_{xref}.png')
	break
	
## 获取表格
for page_index in range(num_pages):
	page = doc.load_page(page_id=page_index)
	tables = page.find_tables() # 表格
	print(tables)
	# 提取表格数据并存储为csv⽂件
	for table in tables:
		df = table.to_pandas()
		print(df.head())
		df.to_csv(
					f'./example_data/焦点科技__2019年__年度报告_page_{page_index}__table_{table}.csv',
				index=False)
		break
		
## PDF文档分割
output_dir = './example_data/{0}.pdf'
for page_index in range(num_pages):
	print(page_index)
	# 创建⼀个新的Document对象,包含当前⻚⾯
	new_pdf = fitz.open()
	new_pdf.insert_pdf(doc, from_page=page_index, to_page=page_index)
	# 保存为单独的pdf⽂件
	new_pdf.save(output_dir.format(page_index))
	new_pdf.close()
	break
doc.close()
1.1.3 pypdf

pypdf 就是一种基于规侧广泛使用的解析器,也是 LangChain 和 Llamalndex 中解析 PDF文件的标准方法。

pip install PyPDF2

在这里插入图片描述

import PyPDF2
filename = "./example_data/焦点科技_2019年__年度报告.pdf"
pdf_file = open(filename, 'rb')
reader = PyPDF2.PdfReader(pdf_file)
page_num = 0
page = reader.pages[page_num]
text = page.extract_text()
print('--------------------------------------------------')
print(text)
pdf_file.close()
'''
焦点科技股份有限公司 2019年年度报告全⽂ 
1 
焦点科技股份有限公司 
Focus Technology Co., Ltd. 
(南京江北新区星⽕路软件⼤厦 A 座12F)
⼆〇⼀九年年度报告 
⼆〇⼆〇年⼆⽉
'''

1.2 基于深度学习的pdf解析

基于深度学习模型的方法能够准确地识别整个文档的布局,包括表格和段落。它甚至可以理解表中的结构。这意味着它可以将文档划分为定义明确、完整的信息单元。同时保留预期的含义和结构。
代表性的开源框架:

  • Unstructured: 已经集成到langchain中。使用hi_res策略设置infer_table_structure=True 可以很好的识别表格信息。然而 fast策略因为不使用目标检测模型,在识别图像和表格方面表现比较差。
  • Layout-parser:如果需要识别复杂的结构化PDF ,建议使用最大的模型以获得更高的精度,但是会比较慢。此外,Layout解析器的模型在过去几年中似乎没有更新。
  • PP-StructureV2: 可以组合各种模型用于文档分析,性能高于平均水平。
Unstructured
from unstructured.partition.pdf import partition_pdf
filename = "../paper/bert.pdf"
# infer_table_structure=True automatically selects hi_res strategy
elements = partition_pdf(filename=filename, infer_table_structure=True)
tables = [el for el in elements if el.category == "Table"]
print(tables[0].text)
print('--------------------------------------------------')
print(tables[0].metadata.text_as_html)

1.3 基于多模态的pdf解析(复杂结构)

LlamaIndex例子:检索相关图像(PDF页面)并将其发送到GPT4-V 以响应查询。

  1. 将每个PDF页面视为一个图像,让GPT4-V 对每个页面进行图像推理,为图像推理构建文本矢量存储索引,根据图像矢量存储查询答案。
  2. 使用Table Transformer从检索到的图像中裁剪表信息,然后将这些裁剪的图像发送到GPT4-V 进行查询相应。
  3. 对裁剪的表图像应用OCR,并将数据发送到GPT4 以回答查询。

经测试确定第三种方法最有效。
此外可以试用多模态模型从图像中提取或者总结关键信息(PDF文件可以很容易转换为图像)

1.3.1 解析pdf文档存在哪些挑战

挑战在于准确提取整个页面的布局,并将表格、标题、段落和图片在内的内容翻译成文档的文本表示。这个过程涉及到处理文本提取、图像识别中的不确定之处,以及表中行-列关系的混乱。

1.3.1.1 挑战一:如何从表格和图像中提取数据问题?

使用unstructured框架作为示例,检测到的表格数据可以直接导出为HTML:
在这里插入图片描述
复制HTML标记并将其另存为HTML文件,使用Chrome打开如下:
在这里插入图片描述

1.3.1.2 挑战二:如何重新排列检测到的块?特别对于双列PDF?

在这里插入图片描述
在确定布局后,unstructured框架会将每个页面划分成几个矩形块:

在这里插入图片描述
每个矩形块的详细信息可以通过以下格式获取:
在这里插入图片描述
其中(x1, y1)是左上顶点的坐标,(x2, y2)是右下顶点的坐标
在这里插入图片描述
此时,可以选择重新调整页面的阅读顺序。unstructured 有一个内置排序算法。但是实际排序结果不是很满意。
因此有必要设计一种排序算法。最简单的方法就是先按左上角顶点的水平座标排序,如果水平座标相同,则按垂直坐标排序。伪代码如下:

layout.sort(key=lambda z:(z.bbox.x1, z.bbox.y1, z.bbox.x2, z.bbox.y2))

然而还发现,即使同一列中的块,其水平坐标也可能发生变化。如下图,提取到的紫色线条块的水平坐标bbox.x1 实际更靠左。排序时他将位于路线块之前,显然违反了阅读顺序。

在这里插入图片描述
在这种情况下使用一种可能的算法:

  • 首先,对左上角所有x坐标x1 进行排序,可以得到X1_min
  • 然后,对所有右下角x坐标x2进行排序,可以得到x2_max
  • 接下来,将页面中心线的x坐标确定x1_min = min([el.bbox.x1 for el in layout]) ; x2_max = max([el.bbox.x2 for el in layout]); mid_line_x_cooedinate = (x2_max + x1_min)/2
  • 接下来,如果bbox.x1< mid_line_x_cordinate ,则块被分类为左列的一部分。否则被视为右边的一部分。
  • 分类完成后,根据列中的y坐标对每个块进行排序。
  • 最后,将右侧列连接到左侧列的右侧
left_column, right_column = [], []
for el in layout:
	if el.bbox.x1 < mid_line_x_cooedinate:
		left_column.append(el)
	else:
		right_column.append(el)

left_column.sort(key = lambda z: z.bbox.y1)
right_column.sort(key = lambda z: z.bbox.y1)
sorted_layout = left_column + right_column

值得一提的是这种改进也与单列pdf兼容.

1.3.1.3 挑战三:如何提取多级标题?

提取多级标题的目的是提高LLM答案的准确性。
该算法依然依赖与上面提到的布局快。我们可以设置type=‘Section-hearder’的块,并计算高度差(bbox.y2-bbox.y1)。高度差最大的块对应第一级标题,其次是第二级标题…

补充:PPT类文档解析问题

  • 难点:如何对PPT 中的大量的流程图,架构图进行提取,因为这些图多以形状元素在PPT中呈现,如果只提取文字,大量潜藏的信息会大量丢失。
  • 解决办法:将PPT转为pdf形式,然后用户上述处理PDF 的形式进行解析。

参考:
版面分析–优化策略篇
【知识库构建——知识文本分块】
【知识库构建——文档切分优化策略篇】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/620381.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学校能源消耗监测管理系统,打造智能监测系统

学校能源消耗监测管理系统是一款针对&#xff0c;水、电、煤、气、热等能源的在线监测、分析与处理的系统&#xff0c;为学校管理者提供全面的能源使用情况&#xff0c;为学校管理工作提供了有力的支持。 为什么要建设能源管理系统&#xff1f; 用能需求增加 随着学校的快速…

视频号小店能做吗?聊聊做视频号一年来的感受

大家好&#xff0c;我是电商笨笨熊 做电商这件事&#xff0c;我已经持续了6年多的时间&#xff1b; 面对众多项目&#xff0c;从最初的闲鱼到天猫&#xff0c;再到抖店和视频号小店&#xff1b; 这期间从传统电商到直播电商&#xff0c;也看到了很多玩家的纠结&#xff1b; …

深度学习技术之加宽前馈全连接神经网络

深度学习技术 加宽前馈全连接神经网络1. Functional API 搭建神经网络模型1.1 利用Functional API编写宽深神经网络模型进行手写数字识别1.1.1 导入需要的库1.1.2 加载虹膜&#xff08;Iris&#xff09;数据集1.1.3 分割训练集和测试集1.1.4 定义模型输入层1.1.5 添加隐藏层1.1…

Linux基础之进程-fork()函数的详解

目录 一、前言 二、fork()函数 2.1 fork()函数的基本概念 2.2 问题一的解答 2.3 问题二的解答 2.4 问题三的解答 2.5 问题四的解答 2.6 问题五的解答 一、前言 在上节内容中我们已经学会了使用我们的getpid()和我们的getppid()去查看我们进程的pid&#xff0c;并且学习到…

dockerFile制作镜像、并远程发布

1、FORM 用于指定基础镜像&#xff0c;也就是在指定的镜像上&#xff0c;增加上后续dockerFIle中设置的内容&#xff08;新的软件、新的服务等&#xff09; FROM openjdk:8-jre 在这个容器中&#xff0c;就能直接使用java命令。 2、ENV 用于设置环境变量&#xff0c;在后续的R…

Android Compose 一:基础控件

Flutter 与 Compose 组件辣么像&#xff0c;难道是同一个google团队整的&#xff1b;也未深究&#xff0c;只是猜测。 创建项目 需要使用新版本Android studio&#xff0c;忽略步骤… 项目目录 MainActivity说明 1 系统默认页面 Preview 修饰的方法&#xff0c;只用来供开发…

物联网实战--平台篇之(七)应用界面设计

目录 一、米家APP分析 二、应用展示 三、应用列表 四、新建应用 五、重命名应用 本项目的交流QQ群:701889554 物联网实战--入门篇https://blog.csdn.net/ypp240124016/category_12609773.html 物联网实战--驱动篇https://blog.csdn.net/ypp240124016/category_12631333.…

快速配置 Nginx 来实现 GPT 流式传输

目录 1. Nginx 参考配置2. Nginx 核心参数3. 其他参数 场景&#xff1a;代理 ChatGPT、代理各种 GPT 工具套壳等。 1. Nginx 参考配置 支持 GPT 流式访问的配置如下&#xff0c;请根据实际需求适当取舍即可&#xff1a; server {listen 80;server_name chat.test.com; # 绑…

PCIE协议-2-事务层规范-Message Request Rules-Vendor_Defined Messages

2.2.8.6 厂商定义消息 厂商定义消息允许扩展PCI Express消息功能&#xff0c;可以作为PCI Express规范的一般扩展&#xff0c;也可以是厂商特定的扩展。本节通用地定义了与这些消息相关的规则。 厂商定义消息&#xff08;见表2-25&#xff09;使用图2-28中显示的头标格式。re…

Nios实验使用串口输出“Hello Nios-II”字符到笔记本电脑

目录 实验过程 创建工程 修改程序 编译工程 运行项目 效果实现 总结 参考 实验过程 硬件设计见博主上篇博客 软件部分设计 下面使用 Nios II Software Build Tools for Eclipse 来完成当前项目的软件开发。 启动 Nios II SBT 按照下图所示点击 Nios II Software Build…

计算机网络复习-传输层

概念 传输层是进程与进程之间的通信使用端口(Port)来标记不同的网络进程端口(Port)使用16比特位表示(0~65535) UDP协议详解 UDP&#xff1a;用户数据报协议数据报&#xff1a;应用层传输过来的一个完整的数据不合并&#xff0c;不拆分 UDP的头部 UDP特点 UDP是无连接协…

【R语言篇】医学生福音,全球疾病负担数据库GBD 2021即将更新!!!

今天介绍即将于5月16日更新的全球疾病负担数据库GBD 2021&#xff0c;相信数据一经发表&#xff0c;过不了多久pubmed又将涌现一大波疾病负担相关文章。 Global Burden of Disease Study 2021 (GBD 2021) Data Resources | GHDx 在查找GBD相关文献方面&#xff0c;我个人还是比…

PS的文字点阵 文字边缘虚 为什么在Ps中打出来的字是带有锯齿状模糊的?

此方法主要针对低像素文字 关键部分 (4 封私信 / 80 条消息) 为什么在Ps中打出来的字是带有锯齿状模糊的&#xff1f; - 知乎 (zhihu.com)https://www.zhihu.com/question/54412515

【牛客】SQL211 获取当前薪水第二多的员工的emp_no以及其对应的薪水salary

1、描述 有一个薪水表salaries简况如下&#xff1a; 请你获取薪水第二多的员工的emp_no以及其对应的薪水salary&#xff0c; 若有多个员工的薪水为第二多的薪水&#xff0c;则将对应的员工的emp_no和salary全部输出&#xff0c;并按emp_no升序排序。 2、题目建表 drop table …

8个手机宝藏App,建议收藏!

AI故事视频生成&#xff0c;一站式生成小说漫画推文、儿童故事、民间故事等https://aitools.jurilu.com/ 1.地图车机版——百度地图 百度地图&#xff0c;作为新一代的人工智能地图&#xff0c;以其智能语音、智能导航系统、智能路线规划和智能推荐方案而著称。它不仅提供传统…

MATLAB模拟退火算法、遗传算法、蚁群算法、粒子群算法

概况 模拟退火算法、遗传算法、蚁群算法、粒子群算法等算法&#xff0c;都是属于概率算法&#xff0c;不绝对&#xff0c;不迅速&#xff0c;能用其它方式解决的问题&#xff0c;不要用这些相对复杂的算法&#xff0c;比如有明确的线性关系或者非线性对应关系。这里的概率算法…

IP跳变是什么,有什么作用?

IP跳变&#xff0c;简单来说&#xff0c;就是用户在使用网络时&#xff0c;不固定使用一个IP地址&#xff0c;而是定期或根据需求切换到另一个IP地址。这种技术为用户在网络环境中提供了一定的灵活性和安全性。 首先&#xff0c;我们来看看IP跳变的具体实现方式。当用户需要切…

CUDA-均值滤波算法

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 实现原理 均值滤波是一种常见的图像处理方法&#xff0c;用于去除图像中的噪声。其原理很简单&#xff1a;对图像中的每个像素&a…

高频电源模块TL22010-T2整流模块TL22010-T3用途

直流屏充电模块TL22010-T2电源模块TL22010-T3&#xff0c;整流模块TL11010-T3&#xff0c;其他TL系列型号有&#xff1a;TL11020-T3&#xff0c;TL11010-T2&#xff0c;TL11020-T2&#xff0c;TL22010-T&#xff0c;TL-22010-T&#xff0c;TL-11010-T&#xff0c;TL-22005-T&am…

排序-选择排序(selection sort)

选择排序&#xff08;selection sort&#xff09;的工作原理非常简单&#xff1a;开启一个循环&#xff0c;每轮从未排序区间选择最小的元素&#xff0c;将其放到已排序区间的末尾。选择排序的主要特点包括&#xff1a; 时间复杂度&#xff1a; 无论最好、最坏还是平均情况&…