2. 文档加载器对比
任务目标
本案例将使用同一份PDF文档,分别通过 PyPDFLoader、TextLoader 和 UnstructuredPDFLoader 三种加载器进行解析,对比它们在文本提取质量、元数据保留和特殊字符处理上的差异,最终根据对比结果确定最适合当前场景的加载器。
环境与依赖
pip install langchain langchain-community pypdf unstructured pdf2image
若需使用 UnstructuredPDFLoader 的OCR能力,还需安装 tesseract 系统依赖(本案例不涉及OCR,仅做基础文本提取对比)。
测试文档准备
创建一个包含标题、正文段落、列表和特殊符号(如 ©、™、→)的PDF文件,用于验证各加载器对格式和特殊字符的保留情况。以下Python脚本生成该测试文件:
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
c = canvas.Canvas("sample.pdf", pagesize=letter)
c.setFont("Helvetica", 14)
c.drawString(72, 720, "RAG Document Loader Test")
c.setFont("Helvetica", 11)
c.drawString(72, 690, "This is a paragraph with special chars: © 2024, TM symbol, arrow →")
c.drawString(72, 660, "List item 1: Python")
c.drawString(72, 645, "List item 2: LangChain")
c.drawString(72, 630, "List item 3: Vector DB")
c.save()
print("sample.pdf created")
完整实现代码
from langchain_community.document_loaders import PyPDFLoader, TextLoader, UnstructuredPDFLoader
import os
def compare_loaders(pdf_path):
"""对比三种加载器的输出结果"""
results = {}
# 1. PyPDFLoader
try:
loader = PyPDFLoader(pdf_path)
docs = loader.load()
results['PyPDFLoader'] = {
'doc_count': len(docs),
'content': docs[0].page_content if docs else '',
'metadata': docs[0].metadata if docs else {}
}
except Exception as e:
results['PyPDFLoader'] = {'error': str(e)}
# 2. TextLoader (直接读取PDF二进制,通常会产生乱码)
try:
loader = TextLoader(pdf_path, encoding='utf-8')
docs = loader.load()
results['TextLoader'] = {
'doc_count': len(docs),
'content': docs[0].page_content[:200] if docs else '',
'metadata': docs[0].metadata if docs else {}
}
except Exception as e:
results['TextLoader'] = {'error': str(e)}
# 3. UnstructuredPDFLoader
try:
loader = UnstructuredPDFLoader(pdf_path, mode="single")
docs = loader.load()
results['UnstructuredPDFLoader'] = {
'doc_count': len(docs),
'content': docs[0].page_content if docs else '',
'metadata': docs[0].metadata if docs else {}
}
except Exception as e:
results['UnstructuredPDFLoader'] = {'error': str(e)}
return results
if __name__ == "__main__":
pdf_file = "sample.pdf"
if not os.path.exists(pdf_file):
print("请先运行测试文档生成脚本")
else:
output = compare_loaders(pdf_file)
# 打印对比结果
for loader_name, result in output.items():
print(f"\n{'='*50}")
print(f"Loader: {loader_name}")
if 'error' in result:
print(f"Error: {result['error']}")
else:
print(f"Document count: {result['doc_count']}")
print(f"Content preview: {result['content'][:150]}...")
print(f"Metadata keys: {list(result['metadata'].keys())}")
运行与验证
运行步骤:
- 先执行测试文档生成脚本,创建
sample.pdf; - 再运行对比脚本,观察三种加载器的输出差异。
预期输出与判定标准:
PyPDFLoader:能正确提取文本,保留段落结构,元数据包含source和page字段;特殊字符(©、→)应正确显示。TextLoader:直接以文本模式读取PDF二进制内容,输出为乱码或不可读字符,元数据仅包含source字段。UnstructuredPDFLoader:能提取文本,且对版面结构(如列表)的还原度较高,元数据包含source和filetype字段。
通过条件:若 PyPDFLoader 和 UnstructuredPDFLoader 均能正确提取可读文本,而 TextLoader 输出乱码,则证明对比实验有效。对于纯文本型PDF,PyPDFLoader 因速度快、依赖少而更适合作为默认选择;若PDF包含复杂表格或多栏布局,则 UnstructuredPDFLoader 更优。
选择建议
根据上述对比结果,在RAG知识库构建中:
- 若PDF为数字生成的文本型文档(非扫描件),优先选择
PyPDFLoader,因其解析速度快且元数据完整; - 若PDF包含扫描图像或复杂排版,选择
UnstructuredPDFLoader并配合OCR使用; TextLoader不适用于PDF文件,仅用于纯文本文件(如TXT、Markdown)。