Skip to main content

如何加载PDF

可移植文档格式 (PDF),标准化为 ISO 32000,是由 Adobe 于 1992 年开发的一种文件格式,用于以独立于应用软件、硬件和操作系统的方式呈现文档,包括文本格式和图像。

本指南涵盖如何将 PDF 文档加载到我们下游使用的 LangChain Document 格式中。

LangChain 与多种 PDF 解析器集成。一些解析器简单且相对低级;其他解析器将支持 OCR 和图像处理,或执行高级文档布局分析。正确的选择将取决于您的应用程序。以下是可选项的列举。

使用 PyPDF

在这里,我们使用 pypdf 将 PDF 加载到文档数组中,每个文档包含页面内容和带有 page 编号的元数据。

%pip install --upgrade --quiet pypdf
from langchain_community.document_loaders import PyPDFLoader

file_path = (
"../../docs/integrations/document_loaders/example_data/layout-parser-paper.pdf"
)
loader = PyPDFLoader(file_path)
pages = loader.load_and_split()

pages[0]
...

这种方法的一个优点是可以通过页面编号检索文档。

PDF的向量搜索

一旦我们将PDF加载到LangChain的Document对象中,就可以按照常规方式对其进行索引(例如,RAG应用程序):

%pip install --upgrade --quiet faiss-cpu 
# 使用 `pip install faiss-gpu` 以支持CUDA GPU
import getpass
import os

os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:")
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings

faiss_index = FAISS.from_documents(pages, OpenAIEmbeddings())
docs = faiss_index.similarity_search("What is LayoutParser?", k=2)
for doc in docs:
print(str(doc.metadata["page"]) + ":", doc.page_content[:300])
13: 14 Z. Shen et al.
6 Conclusion
LayoutParser provides a comprehensive toolkit for deep learning-based document
image analysis. The off-the-shelf library is easy to install, and can be used to
build flexible and accurate pipelines for processing documents with complicated
structures. It also supports hi
0: LayoutParser : A Unified Toolkit for Deep
Learning Based Document Image Analysis
Zejiang Shen1( ), Ruochen Zhang2, Melissa Dell3, Benjamin Charles Germain
Lee4, Jacob Carlson3, and Weining Li5
1Allen Institute for AI
[email protected]
2Brown University
ruochen [email protected]
3Harvard University

从图像中提取文本

一些PDF包含文本的图像——例如,在扫描的文档或图形中。使用rapidocr-onnxruntime包,我们也可以将图像提取为文本:

%pip install --upgrade --quiet rapidocr-onnxruntime
loader = PyPDFLoader("https://arxiv.org/pdf/2103.15348.pdf", extract_images=True)
pages = loader.load()
pages[4].page_content
...

使用 PyMuPDF

PyMuPDF 针对速度进行了优化,并包含有关 PDF 及其页面的详细元数据。它每页返回一个文档:

%pip install --upgrade --quiet pymupdf
from langchain_community.document_loaders import PyMuPDFLoader

loader = PyMuPDFLoader(
"../../docs/integrations/document_loaders/example_data/layout-parser-paper.pdf"
)
data = loader.load()
data[0]
...

此外,您可以将 PyMuPDF 文档 中的任何选项作为关键字参数传递给 load 调用,这些选项将被传递给 get_text() 调用。

使用 MathPix

灵感来源于 Daniel Gross 的代码片段:https://gist.github.com/danielgross/3ab4104e14faccc12b49200843adab21

from langchain_community.document_loaders import MathpixPDFLoader

file_path = (
"../../docs/integrations/document_loaders/example_data/layout-parser-paper.pdf"
)
loader = MathpixPDFLoader(file_path)
data = loader.load()
data[0]

使用 Unstructured

Unstructured 支持一个通用接口,用于处理非结构化或半结构化文件格式,如 Markdown 或 PDF。LangChain 的 UnstructuredPDFLoader 与 Unstructured 集成,将 PDF 文档解析为 LangChain Document 对象。

有关安装系统要求的更多信息,请参见 此页面

%pip install --upgrade --quiet unstructured
from langchain_community.document_loaders import UnstructuredPDFLoader

file_path = (
"../../docs/integrations/document_loaders/example_data/layout-parser-paper.pdf"
)
loader = UnstructuredPDFLoader(file_path)
data = loader.load()
data[0]
...

保留元素

在底层,Unstructured 为不同的文本块创建不同的“元素”。默认情况下,我们将这些元素组合在一起,但您可以通过指定 mode="elements" 来轻松保持这种分离。

file_path = (
"../../docs/integrations/document_loaders/example_data/layout-parser-paper.pdf"
)
loader = UnstructuredPDFLoader(file_path, mode="elements")

data = loader.load()
data[0]
Document(page_content='1 2 0 2', metadata={'source': '../../docs/integrations/document_loaders/example_data/layout-parser-paper.pdf', 'coordinates': {'points': ((16.34, 213.36), (16.34, 253.36), (36.34, 253.36), (36.34, 213.36)), 'system': 'PixelSpace', 'layout_width': 612, 'layout_height': 792}, 'file_directory': '../../docs/integrations/document_loaders/example_data', 'filename': 'layout-parser-paper.pdf', 'languages': ['eng'], 'last_modified': '2023-12-19T13:42:18', 'page_number': 1, 'filetype': 'application/pdf', 'category': 'UncategorizedText'})

查看此特定文档的完整元素类型:

set(doc.metadata["category"] for doc in data)
{'ListItem', 'NarrativeText', 'Title', 'UncategorizedText'}

使用 Unstructured 获取远程 PDF

这部分介绍如何将在线 PDF 加载到我们可以下游使用的文档格式中。这可以用于各种在线 PDF 网站,例如 https://open.umn.edu/opentextbooks/textbooks/https://arxiv.org/archive/

注意:所有其他 PDF 加载器也可以用于获取远程 PDF,但 OnlinePDFLoader 是一个遗留函数,专门与 UnstructuredPDFLoader 一起使用。

from langchain_community.document_loaders import OnlinePDFLoader

loader = OnlinePDFLoader("https://arxiv.org/pdf/2302.03803.pdf")
data = loader.load()
data[0]
...

使用 PyPDFium2

from langchain_community.document_loaders import PyPDFium2Loader

file_path = (
"../../docs/integrations/document_loaders/example_data/layout-parser-paper.pdf"
)
loader = PyPDFium2Loader(file_path)
data = loader.load()
data[0]

使用 PDFMiner

from langchain_community.document_loaders import PDFMinerLoader

file_path = (
"../../docs/integrations/document_loaders/example_data/layout-parser-paper.pdf"
)
loader = PDFMinerLoader(file_path)
data = loader.load()
data[0]
...

使用 PDFMiner 生成 HTML 文本

这对于将文本语义上分块为不同部分非常有帮助,因为输出的 HTML 内容可以通过 BeautifulSoup 进行解析,以获取有关字体大小、页码、PDF 页眉/页脚等更结构化和丰富的信息。

from langchain_community.document_loaders import PDFMinerPDFasHTMLLoader

file_path = (
"../../docs/integrations/document_loaders/example_data/layout-parser-paper.pdf"
)
loader = PDFMinerPDFasHTMLLoader(file_path)
docs = loader.load()
docs[0]
...

from bs4 import BeautifulSoup

soup = BeautifulSoup(docs[0].page_content, "html.parser")
content = soup.find_all("div")
import re

cur_fs = None
cur_text = ""
snippets = [] # 首先收集所有具有相同字体大小的片段
for c in content:
sp = c.find("span")
if not sp:
continue
st = sp.get("style")
if not st:
continue
fs = re.findall("font-size:(\d+)px", st)
if not fs:
continue
fs = int(fs[0])
if not cur_fs:
cur_fs = fs
if fs == cur_fs:
cur_text += c.text
else:
snippets.append((cur_text, cur_fs))
cur_fs = fs
cur_text = c.text
snippets.append((cur_text, cur_fs))
# 注意:上述逻辑非常简单。还可以添加更多策略,例如删除重复片段(因为 PDF 中的页眉/页脚会出现在多个页面上,因此如果我们发现重复项,可以安全地假设它是冗余信息)
from langchain_core.documents import Document

cur_idx = -1
semantic_snippets = []
# 假设:标题的字体大小高于其相应内容的字体大小
for s in snippets:
# 如果当前片段的字体大小 > 前一个部分的标题 => 这是一个新标题
if (
not semantic_snippets
or s[1] > semantic_snippets[cur_idx].metadata["heading_font"]
):
metadata = {"heading": s[0], "content_font": 0, "heading_font": s[1]}
metadata.update(docs[0].metadata)
semantic_snippets.append(Document(page_content="", metadata=metadata))
cur_idx += 1
continue

# 如果当前片段的字体大小 <= 前一个部分的内容 => 内容属于同一部分(如果需要,也可以为子部分创建树状结构,但这可能需要更多思考,并且可能与数据特定)
if (
not semantic_snippets[cur_idx].metadata["content_font"]
or s[1] <= semantic_snippets[cur_idx].metadata["content_font"]
):
semantic_snippets[cur_idx].page_content += s[0]
semantic_snippets[cur_idx].metadata["content_font"] = max(
s[1], semantic_snippets[cur_idx].metadata["content_font"]
)
continue

# 如果当前片段的字体大小 > 前一个部分的内容,但小于前一个部分的标题,则也创建一个新部分(例如,PDF 的标题将具有最大的字体大小,但我们不希望它包含所有部分)
metadata = {"heading": s[0], "content_font": 0, "heading_font": s[1]}
metadata.update(docs[0].metadata)
semantic_snippets.append(Document(page_content="", metadata=metadata))
cur_idx += 1

print(semantic_snippets[4])
...

PyPDF 目录

从目录加载 PDF

from langchain_community.document_loaders import PyPDFDirectoryLoader

directory_path = (
"../../docs/integrations/document_loaders/example_data/layout-parser-paper.pdf"
)
loader = PyPDFDirectoryLoader("example_data/")

docs = loader.load()

data[0]
...

使用 PDFPlumber

与 PyMuPDF 类似,输出文档包含有关 PDF 及其页面的详细元数据,并且每页返回一个文档。

from langchain_community.document_loaders import PDFPlumberLoader

loader = PDFPlumberLoader("../../docs/integrations/document_loaders/example_data/")

data = loader.load()
data[0]

使用 AmazonTextractPDFParser

AmazonTextractPDFLoader 调用 Amazon Textract Service 将 PDF 转换为文档结构。目前,加载器仅进行纯 OCR,计划根据需求增加更多功能,如布局支持。支持单页和多页文档,最多可达 3000 页和 512 MB 的大小。

要成功调用,需要一个 AWS 账户,类似于 AWS CLI 的要求。

除了 AWS 配置外,它与其他 PDF 加载器非常相似,同时也支持 JPEG、PNG 和 TIFF 以及非原生 PDF 格式。

from langchain_community.document_loaders import AmazonTextractPDFLoader

loader = AmazonTextractPDFLoader("example_data/alejandro_rosalez_sample-small.jpeg")
documents = loader.load()

documents[0]

使用 AzureAIDocumentIntelligenceLoader

Azure AI Document Intelligence(前称为 Azure Form Recognizer)是一项基于机器学习的服务,可以从数字或扫描的 PDF、图像、Office 和 HTML 文件中提取文本(包括手写文本)、表格、文档结构(例如标题、章节标题等)以及键值对。Document Intelligence 支持 PDFJPEG/JPGPNGBMPTIFFHEIFDOCXXLSXPPTXHTML

当前实现 使用 Document Intelligence 的加载器可以逐页整合内容并将其转换为 LangChain 文档。默认输出格式为 markdown,可以与 MarkdownHeaderTextSplitter 轻松链式连接,以实现语义文档切块。您还可以使用 mode="single"mode="page" 返回单页或按页分割的纯文本。

前提条件

在以下 3 个预览区域之一创建 Azure AI Document Intelligence 资源:东部美国西部美国 2西欧 - 如果您还没有,请遵循 此文档 创建一个。您将把 <endpoint><key> 作为参数传递给加载器。

%pip install --upgrade --quiet  langchain langchain-community azure-ai-documentintelligence
from langchain_community.document_loaders import AzureAIDocumentIntelligenceLoader

file_path = "<filepath>"
endpoint = "<endpoint>"
key = "<key>"
loader = AzureAIDocumentIntelligenceLoader(
api_endpoint=endpoint, api_key=key, file_path=file_path, api_model="prebuilt-layout"
)

documents = loader.load()

documents[0]

此页面是否有帮助?


您还可以留下详细的反馈 在 GitHub 上