LangChain의 **문서 로더(Document Loader)**는 다양한 소스의 데이터를 Document 객체로 변환해 RAG, 요약, 검색, 메모리 등 다운스트림 작업에서 활용하도록 도와줍니다.
Document.page_content: 본문 텍스트
Document.metadata: 출처, 페이지, 파일 속성 등 메타데이터
지원 메서드
load() : 동기 로드aload() : 비동기 로드lazy_load() : 제너레이터 기반 지연 로드(대용량 처리에 유리)from langchain_core.documents import Document
document = Document("안녕하세요? 이건 랭체인의 도큐먼트 입니다")
document.metadata["source"] = "TeddyNote"
document.metadata["page"] = 1
document.metadata["author"] = "Teddy"
document.__dict__
# {'id': None, 'metadata': {...}, 'page_content': '...', 'type': 'Document'}#12. UpstageLayoutAnalysisLoader
핵심: 다양한 파일 형식을 Document 배열로 변환합니다. 아래는 PyPDFLoader 예시입니다.
from langchain_community.document_loaders import PyPDFLoader
FILE_PATH = "./data/SPRI_AI_Brief_2023년12월호_F.pdf"
loader = PyPDFLoader(FILE_PATH)
# 1) 전체 로드
docs = loader.load()
len(docs), docs[0]
# -> 23, Document(metadata={'source': './data/...pdf', 'page': 0}, page_content='2023 년 12월호')
# 2) 분할 로드
from langchain_text_splitters import CharacterTextSplitter
text_splitter = CharacterTextSplitter(chunk_size=200, chunk_overlap=0)
docs = loader.load_and_split(text_splitter=text_splitter)
# 3) 제너레이터 로드
for doc in loader.lazy_load():
print(doc.metadata) # {'source': './data/...pdf', 'page': 0} ...
# 비동기 로드
adocs = loader.aload()
await adocs
요약
PyPDFLoader, PyMuPDFLoader, PDFPlumber, PDFMinerPyPDFLoader(extract_images=True, +rapidocr) 또는 UnstructuredPDFLoaderPyMuPDFLoader, PDFPlumber 계열| 도메인 | PDFMiner | PDFPlumber | PyPDFium2 | PyMuPDF | PyPDF2 |
|---|---|---|---|---|---|
| Medical | 1 | 2 | 3 | 4 | 5 |
| Law | 3 | 1 | 1 | 3 | 5 |
| Finance | 1 | 2 | 2 | 4 | 5 |
| Public | 1 | 1 | 1 | 4 | 5 |
| 합계 | 5 | 5 | 7 | 15 | 20 |
# PyPDF
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader(FILE_PATH)
docs = loader.load()
# PyPDF + OCR (rapidocr 사용)
# !pip install -qU rapidocr-onnxruntime
loader = PyPDFLoader("https://arxiv.org/pdf/2103.15348.pdf", extract_images=True)
docs = loader.load()
# PyMuPDF (메타데이터 풍부)
from langchain_community.document_loaders import PyMuPDFLoader
loader = PyMuPDFLoader(FILE_PATH)
docs = loader.load()
# metadata 예: 'file_path', 'total_pages', 'format', 'creator', 'producer', ...
# UnstructuredPDFLoader (요소 단위 분해 가능)
# !pip install -qU unstructured
from langchain_community.document_loaders import UnstructuredPDFLoader
loader = UnstructuredPDFLoader(FILE_PATH, mode="elements")
docs = loader.load()
set(doc.metadata["category"] for doc in docs) # {'ListItem','NarrativeText','Title',...}
# PyPDFium2
from langchain_community.document_loaders import PyPDFium2Loader
loader = PyPDFium2Loader(FILE_PATH)
docs = loader.load()
# PDFMiner (텍스트/또는 HTML로 파싱)
from langchain_community.document_loaders import PDFMinerLoader, PDFMinerPDFasHTMLLoader
docs_txt = PDFMinerLoader(FILE_PATH).load()
docs_html = PDFMinerPDFasHTMLLoader(FILE_PATH).load()
# Directory 로드
from langchain_community.document_loaders import PyPDFDirectoryLoader
docs = PyPDFDirectoryLoader("data/").load()
# PDFPlumber
from langchain_community.document_loaders import PDFPlumberLoader
docs = PDFPlumberLoader(FILE_PATH).load()
주의
rapidocr/Unstructured/전용 OCR 툴 조합 권장.PDFPlumber/PyMuPDF/고급 파서(Upstage/LlamaParse) 고려.# !pip install -qU langchain-teddynote
from langchain_teddynote.document_loaders import HWPLoader
loader = HWPLoader("./data/디지털 정부혁신 추진계획.hwp")
docs = loader.load()
print(docs[0].page_content[:1000])
print(docs[0].metadata) # {'source': './data/...hwp'}
from langchain_community.document_loaders.csv_loader import CSVLoader
loader = CSVLoader(file_path="./data/titanic.csv")
docs = loader.load()
len(docs), docs[0].metadata # (891, {'source': './data/titanic.csv', 'row': 0})
# csv_args로 파싱 커스터마이징
loader = CSVLoader(
file_path="./data/titanic.csv",
csv_args={"delimiter": ",", "quotechar": '"', "fieldnames": [...]},
)
docs = loader.load()
print(docs[1].page_content)
# source_column으로 출처 라벨링
loader = CSVLoader(file_path="./data/titanic.csv", source_column="PassengerId")
docs = loader.load()
docs[1]
# UnstructuredCSVLoader (elements 모드: HTML 표 표현 제공)
from langchain_community.document_loaders.csv_loader import UnstructuredCSVLoader
loader = UnstructuredCSVLoader("./data/titanic.csv", mode="elements")
docs = loader.load()
docs[0].metadata["text_as_html"][:1000]
# DataFrameLoader
import pandas as pd
from langchain_community.document_loaders import DataFrameLoader
df = pd.read_csv("./data/titanic.csv")
loader = DataFrameLoader(df, page_content_column="Name")
docs = loader.load()
for row in loader.lazy_load():
print(row); break
# !pip install -qU langchain-community unstructured openpyxl
from langchain_community.document_loaders import UnstructuredExcelLoader
loader = UnstructuredExcelLoader("./data/titanic.xlsx", mode="elements")
docs = loader.load()
docs[0].metadata["text_as_html"][:1000]
# DataFrameLoader 조합
import pandas as pd
from langchain_community.document_loaders import DataFrameLoader
df = pd.read_excel("./data/titanic.xlsx")
docs = DataFrameLoader(df, page_content_column="Name").load()
# !pip install -qU docx2txt
from langchain_community.document_loaders import Docx2txtLoader
docs = Docx2txtLoader("./data/sample-word-document.docx").load()
from langchain_community.document_loaders import UnstructuredWordDocumentLoader
docs = UnstructuredWordDocumentLoader("./data/sample-word-document.docx").load()
docs[0].metadata
# {'filename': '...', 'file_directory': './data', 'filetype': '...docx', 'category': 'Title', ...}
# 요소 분리
docs = UnstructuredWordDocumentLoader("./data/sample-word-document.docx", mode="elements").load()
len(docs), docs[0].page_content
# !pip install -qU unstructured python-pptx
from langchain_community.document_loaders import UnstructuredPowerPointLoader
# 1) 통합
docs = UnstructuredPowerPointLoader("./data/sample-ppt.pptx").load()
# 2) 요소 분리
docs = UnstructuredPowerPointLoader("./data/sample-ppt.pptx", mode="elements").load()
len(docs), docs[0].page_content, docs[0].metadata
import bs4
from langchain_community.document_loaders import WebBaseLoader
loader = WebBaseLoader(
web_paths=("https://n.news.naver.com/article/437/0000378416",),
bs_kwargs=dict(parse_only=bs4.SoupStrainer(
"div", attrs={"class": ["newsct_article _article_body", "media_end_head_title"]}
)),
header_template={"User-Agent": "Mozilla/5.0 ..."},
)
docs = loader.load()
# SSL 우회
loader.requests_kwargs = {"verify": False}
docs = loader.load()
# 여러 URL + 비동기/속도 제어
# jupyter 환경
import nest_asyncio; nest_asyncio.apply()
loader.requests_per_second = 1
docs = loader.aload() # async
# 프록시 사용
loader = WebBaseLoader(
"https://www.google.com/search?q=parrots",
proxies={
"http": "http://{id}:{pw}@proxy.host:6666/",
"https": "https://{id}:{pw}@proxy.host:6666/",
},
)
docs = loader.load()
from langchain_community.document_loaders import TextLoader
docs = TextLoader("data/appendix-keywords.txt").load()
# 디렉토리 일괄 로드 + 인코딩 자동감지 + 에러 무시
from langchain_community.document_loaders import DirectoryLoader
text_loader_kwargs = {"autodetect_encoding": True}
loader = DirectoryLoader(
"data/", glob="**/*.txt", loader_cls=TextLoader,
silent_errors=True, loader_kwargs=text_loader_kwargs,
)
docs = loader.load()
[doc.metadata["source"] for doc in docs]
# !pip install jq
from langchain_community.document_loaders import JSONLoader
loader = JSONLoader(
file_path="data/people.json",
jq_schema=".[].phoneNumbers", # 원하는 필드만 추출
text_content=False,
)
docs = loader.load()
metadata: source, seq_num 등jq 스키마로 간결하게 추출 가능# !pip install -qU langchain-community arxiv pymupdf
from langchain_community.document_loaders import ArxivLoader
loader = ArxivLoader(
query="Chain of thought",
load_max_docs=2,
load_all_available_meta=True, # 메타데이터 풍부
)
docs = loader.load()
docs[0].metadata # Title, Authors, Summary, links 등
# 메타 최소화 버전
loader = ArxivLoader(query="ChatGPT", load_max_docs=2, load_all_available_meta=False)
docs = loader.load()
docs[0].metadata
# 요약만
docs = loader.get_summaries_as_docs()
print(docs[0].page_content)
# 지연 로드
docs = [d for d in loader.lazy_load()]
# pip install -U langchain-upstage
from langchain_upstage import UpstageLayoutAnalysisLoader
loader = UpstageLayoutAnalysisLoader(
"./data/SPRI_AI_Brief_2023년12월호_F.pdf",
output_type="text",
split="page",
use_ocr=True,
exclude=["header", "footer"],
)
docs = loader.load()
for d in docs[:3]: print(d)
# page_content='...', metadata={'page': 1} ...
# !pip install llama-index-core llama-parse llama-index-readers-file python-dotenv
from llama_parse import LlamaParse
from llama_index.core import SimpleDirectoryReader
parser = LlamaParse(result_type="markdown", num_workers=8, language="ko")
file_extractor = {".pdf": parser}
documents = SimpleDirectoryReader(
input_files=["data/SPRI_AI_Brief_2023년12월호_F.pdf"],
file_extractor=file_extractor,
).load_data()
# LangChain Document로 변환
docs = [doc.to_langchain_format() for doc in documents]
# 멀티모달 모델 사용 + 사용자 지시
import os
parser = LlamaParse(
use_vendor_multimodal_model=True,
vendor_multimodal_model_name="openai-gpt4o",
vendor_multimodal_api_key=os.environ["OPENAI_API_KEY"],
result_type="markdown",
language="ko",
parsing_instruction="Extract tables in markdown format.",
)
parsed_docs = parser.load_data(file_path="data/SPRI_AI_Brief_2023년12월호_F.pdf")
docs = [doc.to_langchain_format() for doc in parsed_docs]
print(docs[-2].page_content) # 마크다운 표 추출 예시
판별 기준: 메타데이터 풍부도, 구조 인식(제목/표/이미지), OCR 가능 여부, 확장성/성능, 한글 호환성, 실무 팁
| # | 형식 | 대표 로더 | 메타데이터 | 구조 인식 | OCR | 강점 | 주의/비고 |
|---|---|---|---|---|---|---|---|
| 01 | Document | - | - | - | - | 표준 컨테이너 | page_content/metadata 이해 필수 |
| 02 | PyPDF/PyMuPDF/PDFPlumber/PDFMiner/Unstructured | PyMuPDF/PDFPlumber 풍부 | PDFPlumber/Unstructured 일부 | PyPDF(+rapidocr), Unstructured | 다양한 선택지, 성능/정확도 밸런스 | 스캔본은 OCR 필요, 표는 Plumber/고급 파서 | |
| 03 | HWP | HWPLoader(teddynote) | 기본 | - | - | 한글 실무 대응 | 커스텀 의존(패키지 설치 필요) |
| 04 | CSV | CSVLoader, UnstructuredCSVLoader, DataFrameLoader | 행/열 라벨 풍부 | (HTML 표: Unstructured) | - | 간단·빠름, 행 단위 문서화 | 대형 CSV는 lazy_load 권장 |
| 05 | Excel | UnstructuredExcelLoader, DataFrameLoader | 보통/행메타 | (HTML 표: elements) | - | 시트→문서화 간편 | 병합셀/서식 손실 가능 |
| 06 | Word | Docx2txtLoader, UnstructuredWordDocumentLoader | 보통/풍부 | elements 모드 | (옵션) | 제목/본문/표 요소화 | 이미지/도형은 제한 |
| 07 | PPT | UnstructuredPowerPointLoader | 보통 | 슬라이드/요소 | (옵션) | 슬라이드 단위 추출 | 레이아웃/디자인 정보 제한 |
| 08 | Web | WebBaseLoader | URL/도메인 | 선택적(Strainer) | - | 헤더/프록시/병렬 | 크롤링 예절·차단 주의 |
| 09 | Text | TextLoader(+Directory) | 경로/파일 | - | - | 단순·범용 | 인코딩 혼재 시 autodetect_encoding=True |
| 10 | JSON | JSONLoader(+jq) | source/seq_num | - | - | jq_schema로 정밀 추출 | jq 설치 필요 |
| 11 | Arxiv | ArxivLoader | Title/Authors/Summary/links | - | (PDF OCR은 별도) | 학술 PDF 메타 자동 | 대용량 질의 시 제한 고려 |
| 12 | Upstage | UpstageLayoutAnalysisLoader | 페이지/구조 | 강함 | 있음 | 레이아웃 분석 특화 | API Key/셋업 필요 |
| 13 | LlamaParser | LlamaParse | 풍부(파일 메타) | 강함 | 있음(멀티모달) | 표/이미지/지시기반 고정밀 | 외부 API(쿼터/비용) |
선택 가이드
PyMuPDF/PDFPlumber (메타·표)PyPDF(extract_images)+rapidocr 또는 Unstructured/Upstage/LlamaParsePDFPlumber, Upstage, LlamaParseHWPLoader(teddynote)CSVLoader/DataFrameLoader + lazy_load()WebBaseLoader + SoupStrainer + Header/Proxy/Rate LimitRAG 파이프라인 체크리스트
Loader → (optional) Cleaner → TextSplitter → VectorStore(FAISS/Chroma)
→ Retriever → RAG Chain(LLM) → (optional) Memory/Feedback
성능/정확도 요약
langchain-community, unstructured, pymupdf, rapidocr-onnxruntime, bs4, openpyxl, jq, arxiv, langchain-upstage, llama-parse 등