微信扫码
与创始人交个朋友
我要投稿
大量信息来源于文本数据,例如PDF文档。处理PDF可能特别具有挑战性,尤其是在处理表格和图像时。
如果您使用单模态语言模型,那么您可能已经知道它不具备直接解释或“读取”文档的能力。它只能处理一种类型的输入,例如纯文本或纯图像。如果您需要分析PDF中的图像或图表以用于下游任务,例如问答,您通常会使用专门的软件包来解析文档。这些工具可以将文档、文档中找到的图像和表格转换为模型可以理解和分析的文本格式。
有几种优秀的工具可用于解析PDF文档以用于下游任务。在本文中,我们将介绍一些优秀的工具,包括PyPDF、Adobe PDF Services API、Camelot和Tabula。
首先,让我们安装相关的库:
!pip install pdfservices-sdk
!pip install openpyxl
!pip install camelot-py
!pip install opencv-python
!pip install tabula-py==2.9.0
!pip install jpype1
!pip install langchain
!pip install langchain-core==0.1.40
Pypdf是一个用途广泛且常用的库,用于解析PDF文档。它可以解析文档,包括文档中的表格,并将其转换为文本。大多数情况下,使用PyPDF解析文档时,表格的格式也能得到很好的保留。
图片由作者提供
Langchain document_loaders 集成了许多不同的软件包,用于读取各种文件格式,包括PyPDF。以下脚本使用PyPDF处理文档并将其保存为数据框格式:
from langchain_community.document_loaders import PyPDFLoader
def extract_text_from_file(df, file_path):
file_name = file_path.split("/")[-1]
file_type = file_name.split(".")[-1]
if file_type == "pdf":
loader = PyPDFLoader(file_path)
else:
return df
text = ""
pages = loader.load_and_split()
for page in pages:
text += page.page_content
# Create a new df and concatenate
new_row = pd.DataFrame({"file": [file_name], "text": [text]})
df = pd.concat([df, new_row], ignore_index=True)
return df
#Apply the function:
folder_path = '../data/raw'
pathlist = Path(folder_path).glob('*.pdf')
filenames = []
for file_path in pathlist:
filename = os.path.basename(file_path)
filenames.append(filename)
df = pd.DataFrame()
for filename in filenames:
file_path = folder_path + "/" + filename
file_name = os.path.basename(file_path)
print(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} process {file_name}")
# Initialize an empty df
df_file = pd.DataFrame(columns=["file", "text"])
print(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} extract text")
try:
df_file = extract_text_from_file(df_file, file_path)
except Exception as e:
print("----Error: cannot extract text")
print(f"----error: {e}")
df = pd.concat([df, df_file])
df
您还可以单独处理每一页,例如,如果您想对每个块/页执行下游问答任务。在这种情况下,您可以修改脚本,如下所示:
def extract_text_from_file(df, file_path):
file_name = file_path.split("/")[-1]
file_type = file_name.split(".")[-1]
if file_type == "pdf":
loader = PyPDFLoader(file_path)
elif file_type == "docx":
loader = Docx2txtLoader(file_path)
else:
return df
pages = loader.load_and_split()
for page_number, page in enumerate(pages, start=1):
# Each page's text is added as a new row in the DataFrame
new_row = pd.DataFrame({
"file": [file_name],
"page_number": [page_number],
"text": [page.page_content]
})
df = pd.concat([df, new_row], ignore_index=True)
return df
PDF文档的每一页都可以包含任意数量的图像。您是否知道您也可以使用PyPDF从文档中提取所有图像?
以下代码块从pdf文件中提取所有图像,并创建一个新文件夹来存储提取的图像:
from pypdf import PdfReader
import os
output_directory = '../data/processed/images/image_pypdf'
if not os.path.exists(output_directory):
os.mkdir(output_directory)
reader = PdfReader("../data/raw/GPTsareGPTs.pdf")
for page in reader.pages:
for image in page.images:
with open(os.path.join(ouput_directory,image.name), "wb") as fp:
fp.write(image.data)
在文件夹中,您将找到PDF中的所有图像:
PyPDF提取的PDF中所有图像的列表。图片由作者提供
PDF Extract API(包含在PDF Services API中) 提供了基于云的功能,用于自动从PDF中提取内容。
PDF Services API 需要一个 access_token 来授权请求。为了使用访问令牌,您需要创建一个。当您收到包含 json 格式的 'client_id' 和 'client_secret' 的开发者凭据后,就可以使用它来处理您的 PDF。让我们首先导入相关的库:
```python
from adobe.pdfservices.operation.auth.credentials import Credentials
from adobe.pdfservices.operation.exception.exceptions import ServiceApiException, ServiceUsageException, SdkException
from adobe.pdfservices.operation.execution_context import ExecutionContext
from adobe.pdfservices.operation.io.file_ref import FileRef
from adobe.pdfservices.operation.pdfops.extract_pdf_operation import ExtractPDFOperation
from adobe.pdfservices.operation.pdfops.options.extractpdf.extract_pdf_options import ExtractPDFOptions
from adobe.pdfservices.operation.pdfops.options.extractpdf.extract_element_type import ExtractElementType
from adobe.pdfservices.operation.pdfops.options.extractpdf.extract_renditions_element_type import \
ExtractRenditionsElementType
import os.path
import zipfile
import json
import pandas as pd
import re
import openpyxl
from datetime import datetime
```
以下脚本使用必要的凭据设置 Adobe PDF Services API,处理 PDF 文件并将结果保存在 zip 文件中:
```python
def adobeLoader(input_pdf, output_zip_path,client_id, client_secret):
"""
运行 adobe API 并创建输出 zip 文件的函数
"""
# 初始化设置,创建凭据实例。
credentials = Credentials.service_principal_credentials_builder() \
.with_client_id(client_id) \
.with_client_secret(client_secret) \
.build()
# 使用凭据创建 ExecutionContext 并创建一个新的操作实例。
execution_context = ExecutionContext.create(credentials)
extract_pdf_operation = ExtractPDFOperation.create_new()
# 从源文件设置操作输入。
source = FileRef.create_from_local_file(input_pdf)
extract_pdf_operation.set_input(source)
# 构建 ExtractPDF 选项并将其设置到操作中
extract_pdf_options: ExtractPDFOptions = ExtractPDFOptions.builder() \
.with_elements_to_extract([ExtractElementType.TEXT, ExtractElementType.TABLES]) \
.with_elements_to_extract_renditions([ExtractRenditionsElementType.TABLES,
ExtractRenditionsElementType.FIGURES]) \
.build()
extract_pdf_operation.set_options(extract_pdf_options)
# 执行操作。
result: FileRef = extract_pdf_operation.execute(execution_context)
# 将结果保存到输出路径
if os.path.exists(output_zip_path):
os.remove(output_zip_path)
result.save_as(output_zip_path)
```
此 'adobeLoader' 操作的输出是一个 'sdk.zip' 包,其中包含以下内容:
'structuredData.json' 文件
文本存储在 json 文件中,并按上下文块提取——段落、标题、列表、脚注。
“table”文件夹:表格被提取并解析,并为每个单元格提供内容和表格格式信息。表格数据在生成的 JSON 中提供,也可以选择以 CSV 和 XLSX 文件输出。表格也输出为 PNG 图像,以便可以直观地验证表格数据。
“figures”文件夹:被识别为图形或图像的对象将提取为 PNG 文件。
输出文件夹结构
现在,您可以将该函数应用于您的文档:
```python
# Adobe 输出 zip 文件路径
input_pdf = 'data/raw/GPTsareGPTs.pdf'
output_zip_path = 'data/processed/adobe_result/sdk.zip'
output_zipextract_folder = 'data/processed/adobe_result/'
# 运行 adobe API
adobeLoader(input_pdf, output_zip_path)
```
您可以看到“figures”文件夹以 .png 格式返回我的 PDF 文档中的所有图像。表格文件夹返回表格的 Excel 工作表,这确保了高保真度和准确性,以及用于视觉比较目的的 .png 图像。
您还可以进一步处理结构化 JSON 文件 structuredData.json
以收集文本和表格,并将这些数据组织到 pandas DataFrame 中,以用于进一步的下游任务:
Tabula 和 Camelot 是两个专门为从 PDF 中提取表格而设计的 Python 库。
以下脚本使用 Tabula 或 Camelot 处理 PDF 文档,将文档中的每个表格转换为 JSON 格式,同时捕获实际表格数据和元数据(例如表格编号和页码):
```python
def extract_tables(file_path, pages="all", package="tabula"):
if package == "camelot":
# 使用 camelot 提取表格
# flavor 可以是 'stream' 或 'lattice',对于表格没有清晰边框的文档,stream flavor 通常更合适。
tables = camelot.read_pdf(file_path, pages=pages, flavor="stream")
else:
tables = tabula.read_pdf(file_path, pages=pages, stream=True, silent=True)
# 将表格转换为 JSON
tables_json = []
for idx, table in enumerate(tables):
if package == "camelot":
page_number = table.parsing_report["page"]
data = table.df.to_json(orient="records")
else:
page_number = ""
data = table.to_json(orient="records")
data = {
"table_number": idx,
"page_number": page_number,
"data": data,
}
tables_json.append(data)
return tables_json
```
太棒了!现在我们有了处理表格的脚本,我们可以将该函数应用于相同的 Pdf 文档:
file_path = '../data/raw/GPTsareGPTs.pdf'
file_name = os.path.basename(file_path)
df_file = pd.DataFrame()
print(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} process {file_name}")
print(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} extract table")
all_tables = []
for package in ["camelot", "tabula"]:
print(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} extract table with {package}")
try:
tables_from_package = extract_tables(file_path, pages="all", package=package) # list of json
for table in tables_from_package:
all_tables.append({"table": table, "source": package})
except Exception as e:
print("----Error: cannot extract table")
print(f"----error: {e}")
# Now you can access each table along with its source
for entry in all_tables:
print(f"Source: {entry['source']}, Table: {entry['table']}")
下面是源 PDF 文档中的一个表格示例:
Camelot 或 Tabula 操作的输出格式实际上是表格的字符串表示形式,如下面的 json 对象所示:
Tabula 的输出
当您切片 json 对象中的 ['data']
键时,VS Code 似乎理解它是一种表格格式,并显示字符串的表格表示形式,这看起来与 PDF 文件中源表格中的完全相同。Tabula 似乎正确检测到了表格。棒极了!
Tabula 的输出
现在,让我们看一下 Camelot 的输出。以下显示了同一个表格的 json 对象。
Camelot 的输出
以及字符串的表格表示:
Camelot 的输出。Camelot 未能检测到表格的边界。当文本离表格太近时,它会包含文本。
在这个例子中,Tabula 和 Camelot 都能够检测到表格,但是 Tabular 的输出很干净,并且镜像了 PDF 中的原始表格。同时,Camelot 似乎未能检测到表格的边界。当文本离表格太近时,它会包含文本。
但是,在另一个例子中,当一个页面上有多个表格,并且没有像下面这样清晰的表格边界时:
Camelot 成功检测到两个表格,而 Tabula 未能检测到任何一个表格:
Camelot 的输出Camelot 的输出
在考虑选择哪种选项来解析 PDF 文档时,PyPDF 是基本提取需求的理想选择,在这些需求中,表格结构可能不是优先事项。它是完全免费的,适合预算紧张且需要简单解决方案以高精度提取文本和图像的用户。根据我的经验,大多数情况下,将表格格式保留为文本是可以接受的。
Camelot 和 Tabula 专为表格提取而设计,最适合需要提取表格数据的场景。它们也是完全免费的,在我看来,如果您对偶尔的不准确性没有意见,那么它们就足够好了。
Adobe PDF Services API 为企业或应用程序提供了一个非常强大的解决方案,在这些企业或应用程序中,文本、表格和图像提取的高精度至关重要。但是,没有关于 API 定价的明确信息。这里说您需要联系销售人员获取报价。在这个 主题 上,Adobe Extract API 似乎相当昂贵。实际上,我** **愿意为实际使用付费,因为提取的输出质量是优质的!
在本文中,我们学习了四种不同的工具来解析 PDF 文档并从 PDF 文件中提取文本、表格和图像数据:PyPDF、Camelot、Tabula 和 Adobe PDF Services API。
感谢您的阅读。我希望它对您有效地将 PDF 内容转换为结构化和可操作的数据有所帮助。
53AI,企业落地应用大模型首选服务商
产品:大模型应用平台+智能体定制开发+落地咨询服务
承诺:先做场景POC验证,看到效果再签署服务协议。零风险落地应用大模型,已交付160+中大型企业
2024-05-28
2024-04-26
2024-08-21
2024-04-11
2024-08-13
2024-07-09
2024-07-18
2024-10-25
2024-07-01
2024-06-17