RAG 系列之二:PDF 文件的解析

在 RAG(检索增强生成)简介的流程图中,有一个环节是检索向量数据库(下图中红色框标识的部分)。向量数据库存储了外部知识库经过向量化处理的内容。在检索之前,我们首先需要创建向量数据库,而创建的第一步是解析知识库中的文件,提取其中的文本、表格等信息。由于 PDF 格式的文件占据了文件的大部分,因此如何从 PDF 文件中精确且高效地提取这些信息,便成为创建向量数据库的关键。本文将介绍如何解析 PDF 文件,帮助实现这一目标。

PDF,即便携式文档格式(英语:Portable Document Format,缩写 PDF),是一种能够独立于应用程序、硬件和操作系统呈现文档的文件格式。PDF 之所以受欢迎,是因为它能够完全保留原文档的格式,不受设备、软件或系统的影响,这对于传播信息来说意义重大。试想一下,如果你使用的是 Word 文档,一旦更换设备,字体、图片、颜色和格式等可能都会发生变化。但 PDF 不会出现这种情况,它能够原汁原味地保留重要的图文信息,不用担心设备的影响。正是为了实现这种显示的一致性,PDF 牺牲了可编辑性。这里有一点需要注意,不是 PDF 不想做到容易编辑,也不是故意让你无法修改,而是为了极致的显示一致性,必须牺牲可编辑性。PDF 会将文本的位置、字体、间距、缩放比例、页边距等所有属性在文件格式中限定死,让软件没有自由发挥的空间。这就是为什么不同软硬件打开 PDF 效果都能一致的原因。本质上,PDF 的格式限制确保了它在任何设备上的显示效果都一样。比如,一个包含 “Hello World” 字样的 PDF 文件用 PDF 阅读器打开时,效果如下面的左边所示。如果用文本编辑器打开这个 PDF 文件,显示结果如下面的右边所示。

看到上面的这个文件内容,我们也就明白了 PDF 为什么难于编辑的原因了。但也正是这个文件,会手把手地告诉电脑,怎么一点一点把这个文件的内容在屏幕上打印出来,最大程度地确保了所有人看到这个文件的效果都一样。

上面说的这类 PDF 文件是文本 PDF,也就是机器生成的 PDF。还有一类 PDF 文本 是扫描 PDF,这类文件的每一页都是一张图片,所用到的解析方法和文本 PDF 也是不一样的。下面就分别把解析两类 PDF 文件效果还不错的工具介绍给大家。

文本 PDF 的解析

文本的提取

能够进行文本提取的 Python 库包括:pdfminer.sixPyMuPDFPyPDF2pdfplumber,效果最好的是 PyMuPDF,PyMuPDF 在进行文本提取时能够最大限度地保留 PDF 的阅读顺序,这对于双栏 PDF 文件的抽取非常有用。下面就以难度比较大的双栏 PDF 为例,来介绍使用 PyMuPDF 库进行文字抽取的效果。

我们以下面的 PDF 为例来看使用 PyMuPDF 进行文字提取的效果。

进行文本提取的代码如下:


import pymupdf

pages = pymupdf.open("bert.pdf")
text = pages[0].get_text()

print(text)

打印的结果如下:

BERT: Pre-training of Deep Bidirectional Transformers for
Language Understanding
Jacob Devlin
Ming-Wei Chang
Kenton Lee
Kristina Toutanova
Google AI Language
{jacobdevlin,mingweichang,kentonl,kristout}@google.com
Abstract
We introduce a new language representa-
tion ......
(5.1 point absolute improvement).
1
Introduction
Language model pre-training has been shown to
......
De Meulder, 2003; Rajpurkar et al., 2016).
There are two existing strategies for apply-
ing ......
predict the original vocabulary id of the masked
arXiv:1810.04805v2  [cs.CL]  24 May 2019

提取出的文字遵循了原 PDF 文件的阅读顺序,也就是先读左边栏的文字,再读右边栏的文字,(为了节省版面,对部分文字进行了省略),这样提取出的文本也就保持了原 PDF 的语义。

除了上面的这种提取方式之外,我们还可以将文本提取为文本块的列表。代码如下:

import pymupdf

pages = pymupdf.open("bert.pdf")
text = pages[0].get_text("blocks")

print(text)

打印的结果如下:

[(116.51899719238281, 67.92063903808594, 481.02740478515625, 102.5250473022461, 'BERT: Pre-training of Deep Bidirectional Transformers for\nLanguage Understanding\n', 0, 0), (107.78799438476562, 128.531005859375, 492.7443542480469, 179.3809814453125, 'Jacob Devlin\nMing-Wei Chang\nKenton Lee\nKristina Toutanova\nGoogle AI Language\n{jacobdevlin,mingweichang,kentonl,kristout}@google.com\n', 1, 0), (158.89096069335938, 222.02301025390625, 203.37625122070312, 237.57672119140625, 'Abstract\n', 2, 0), ...... , (10.940000534057617, 256.5899658203125, 37.619998931884766, 609.8900146484375, 'arXiv:1810.04805v2  [cs.CL]  24 May 2019\n', 8, 0)]

由上面的结果可以看出,每个文本块包含了文本块的坐标、文本块的内容以及文本块的序号(为了节省版面,对部分文本块进行了省略)。有了每个文本块的上述信息,我们便可以知道文本块的阅读顺序;如果需要的话,还可以使用每个文本块的坐标信息对版面进行恢复。

表格的提取

表格提取效果比较好的库有 camelottabula ,表格又可以分为有线表和少线表。下面就分别以有线表和少线表为例来介绍 camelottabula 的使用。

有线表

我们以下面的 PDF 为例来看使用 camelottabula 进行有线表格提取的效果。

  1. 使用 camelot 进行表格提取的代码如下:
import camelot

tables = camelot.read_pdf('data.pdf')
print(tables[0].df)

输出结果如下:

  1. 使用 tabula 进行表格提取的代码如下:
import tabula

dfs = tabula.read_pdf("data.pdf")
print(dfs[0])

输出结果如下:

从结果可以看出,在提取有线表时,不管是 camelot 还是 tabula 都能很好地进行提取,而且不需要过多的参数设置。

少线表

我们以下面的 PDF 为例来看使用 camelottabula 进行少线表格提取的效果。

  1. 使用 camelot 进行少线表格提取的代码如下:
import camelot

tables = camelot.read_pdf('bert-6.pdf', flavor='stream')
tables[0].df

在使用 camelot 进行少线表格的提取时,需要将参数 flavor 设置成 stream ,输出结果如下:

  1. 使用 tabula 进行少线表格提取的代码如下:
import tabula

dfs = tabula.read_pdf("bert-6.pdf", stream=True)
dfs[0]

在使用 tabula 进行少线表格的提取时,需要将参数 stream 设置成 True ,输出结果如下:

在使用 camelottabula 进行少线表格的提取时,需要设置相应的参数。

扫描 PDF 的解析

文本的提取

在从扫描的 PDF 文件中提取文本时,使用开源的 PaddleOCR,并且用 PPStructure 做版面的分析。我们还是以下面的 PDF 文件为例,不过这是的 PDF 文件是扫描 PDF。

提取文本的代码如下:

import os
import cv2
from paddleocr import PPStructure, draw_structure_result, save_structure_res
from PIL import Image

img_path = "./bert-1.png"

table_engine = PPStructure(show_log=True)
save_folder = './output'
img = cv2.imread(img_path)
result = table_engine(img)
save_structure_res(result, save_folder, os.path.basename(img_path).split('.')[0])

font_path = './fonts/simfang.ttf'
image = Image.open(img_path).convert('RGB')
im_show = draw_structure_result(image, result, font_path=font_path)
im_show = Image.fromarray(im_show)
im_show.save('result.jpg')

得到的结果如下:

图中的左边是根据给出的版面分析结果画出来的,可以看出对双栏 PDF 做了正确的解析。右边是根据识别出来的文本以及文本的坐标画出来的,可以看出基本上和左边的版面以及内容是一致的。

表格的提取

我们还是以下面的 PDF 文件为例,不过这是的 PDF 文件是扫描 PDF。

代码如下:

import os
import cv2
from paddleocr import PPStructure,draw_structure_result,save_structure_res
from PIL import Image
 
table_engine = PPStructure(show_log=True)
save_folder = './output'
img_path = './bert-6.png'
img = cv2.imread(img_path)
result = table_engine(img)
save_structure_res(result, save_folder,os.path.basename(img_path).split('.')[0])

for line in result:
    line.pop('img')
    print(line)

在上面的输出结果中,有一行类型为 table 的输出,我们将这一行中 html 标签下的内容拷贝出来,放到一个 html 文件中,得到如下的表格:

可以看出在表头这一块还是有一些差异,但是其他的信息基本都是正确的,应该说效果还是不错的。

总结

本文重要介绍了文本 PDF 和 扫描 PDF 的解析,了解到了 PDF 文件解析的复杂性。要想 RAG(检索增强生成)后面的环节取得比较好的效果,文件解析的准确性至关重要。如果在文件解析这一环节质量不高的话,后面的环节不论怎么优化,也不会达到很好的效果。所以花大力气在文件的解析上,后面会收到事半功倍的效果。

如何系统的去学习大模型LLM ?

大模型时代,火爆出圈的LLM大模型让程序员们开始重新评估自己的本领。 “AI会取代那些行业?”“谁的饭碗又将不保了?”等问题热议不断。

不如成为「掌握AI工具的技术人」,毕竟AI时代,谁先尝试,谁就能占得先机!

但是LLM相关的内容很多,现在网上的老课程老教材关于LLM又太少。所以现在小白入门就只能靠自学,学习成本和门槛很高

针对所有自学遇到困难的同学们,我帮大家系统梳理大模型学习脉络,将这份 LLM大模型资料 分享出来:包括LLM大模型书籍、640套大模型行业报告、LLM大模型学习视频、LLM大模型学习路线、开源大模型学习教程等, 😝有需要的小伙伴,可以 扫描下方二维码领取🆓↓↓↓

👉[CSDN大礼包🎁:全网最全《LLM大模型入门+进阶学习资源包》免费分享(安全链接,放心点击)]()👈

  • 9
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值