LangChain - Document Loader

김소은·2025년 8월 13일

https://wikidocs.net/233775

🔎 개요

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

🧭 목차


01. 도큐먼트(Document)의 구조

핵심: 다양한 파일 형식을 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

02. PDF

요약

  • PDF는 목적/문서 레이아웃/스캔 여부에 따라 로더 선택이 달라집니다.
  • 텍스트 기반: PyPDFLoader, PyMuPDFLoader, PDFPlumber, PDFMiner
  • 이미지/OCR: PyPDFLoader(extract_images=True, +rapidocr) 또는 UnstructuredPDFLoader
  • 메타데이터가 풍부한 건 PyMuPDFLoader, PDFPlumber 계열

AutoRAG 실험(발췌) — 파서 랭킹

도메인PDFMinerPDFPlumberPyPDFium2PyMuPDFPyPDF2
Medical12345
Law31135
Finance12245
Public11145
합계5571520

실습 스니펫

# 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()

주의

  • OCR은 기본 내장이 아닌 경우가 많습니다(예: PyMuPDF는 비-OCR). 스캔본이면 rapidocr/Unstructured/전용 OCR 툴 조합 권장.
  • 표/레이아웃 유지가 필요하면 PDFPlumber/PyMuPDF/고급 파서(Upstage/LlamaParse) 고려.

03. 한글(HWP)

# !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'}
  • 포인트: LangChain 공식 통합 전(커스텀 로더). 한글 문서 실무에서 자주 필요.

04. CSV

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

05. Excel

# !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()

06. Word

# !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

07. PowerPoint

# !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

08. 웹 문서(WebBaseLoader)

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()

09. 텍스트(TextLoader)

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]

10. JSON

# !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
  • 복잡한 JSONjq 스키마로 간결하게 추출 가능

11. Arxiv

# !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()]

12. UpstageLayoutAnalysisLoader

# 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} ...
  • 강점: 제목/단락/표/이미지 등 레이아웃 요소 인식, 선택적 OCR, 페이지 단위 분할
  • 활용: 표/레이아웃 유지가 중요한 보고서형 PDF

13. LlamaParser

# !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)  # 마크다운 표 추출 예시
  • 강점: 고난도 레이아웃·표·이미지 추출, 자연어 지시 기반 맞춤 파싱
  • 비용: LlamaCloud API(일정 무료 쿼터, 이후 과금)

📊 비교 분석 표 (수업 순서 유지)

판별 기준: 메타데이터 풍부도, 구조 인식(제목/표/이미지), OCR 가능 여부, 확장성/성능, 한글 호환성, 실무 팁

#형식대표 로더메타데이터구조 인식OCR강점주의/비고
01Document----표준 컨테이너page_content/metadata 이해 필수
02PDFPyPDF/PyMuPDF/PDFPlumber/PDFMiner/UnstructuredPyMuPDF/PDFPlumber 풍부PDFPlumber/Unstructured 일부PyPDF(+rapidocr), Unstructured다양한 선택지, 성능/정확도 밸런스스캔본은 OCR 필요, 표는 Plumber/고급 파서
03HWPHWPLoader(teddynote)기본--한글 실무 대응커스텀 의존(패키지 설치 필요)
04CSVCSVLoader, UnstructuredCSVLoader, DataFrameLoader행/열 라벨 풍부(HTML 표: Unstructured)-간단·빠름, 행 단위 문서화대형 CSV는 lazy_load 권장
05ExcelUnstructuredExcelLoader, DataFrameLoader보통/행메타(HTML 표: elements)-시트→문서화 간편병합셀/서식 손실 가능
06WordDocx2txtLoader, UnstructuredWordDocumentLoader보통/풍부elements 모드(옵션)제목/본문/표 요소화이미지/도형은 제한
07PPTUnstructuredPowerPointLoader보통슬라이드/요소(옵션)슬라이드 단위 추출레이아웃/디자인 정보 제한
08WebWebBaseLoaderURL/도메인선택적(Strainer)-헤더/프록시/병렬크롤링 예절·차단 주의
09TextTextLoader(+Directory)경로/파일--단순·범용인코딩 혼재 시 autodetect_encoding=True
10JSONJSONLoader(+jq)source/seq_num--jq_schema로 정밀 추출jq 설치 필요
11ArxivArxivLoaderTitle/Authors/Summary/links-(PDF OCR은 별도)학술 PDF 메타 자동대용량 질의 시 제한 고려
12UpstageUpstageLayoutAnalysisLoader페이지/구조강함있음레이아웃 분석 특화API Key/셋업 필요
13LlamaParserLlamaParse풍부(파일 메타)강함있음(멀티모달)표/이미지/지시기반 고정밀외부 API(쿼터/비용)

💡 활용 팁 & 결론

  • 선택 가이드

    1. 텍스트 PDFPyMuPDF/PDFPlumber (메타·표)
    2. 스캔본/OCRPyPDF(extract_images)+rapidocr 또는 Unstructured/Upstage/LlamaParse
    3. 표/레이아웃 보존 최우선 → PDFPlumber, Upstage, LlamaParse
    4. 한글(HWP)HWPLoader(teddynote)
    5. 대용량 테이블CSVLoader/DataFrameLoader + lazy_load()
    6. 웹 스크래핑WebBaseLoader + SoupStrainer + Header/Proxy/Rate Limit
  • RAG 파이프라인 체크리스트

    Loader → (optional) Cleaner → TextSplitter → VectorStore(FAISS/Chroma) 
          → Retriever → RAG Chain(LLM) → (optional) Memory/Feedback
  • 성능/정확도 요약

    • 빠름/가벼움: CSV/텍스트/기본 PDF 텍스트 파서
    • 정확/구조 보존: PDFPlumber, PyMuPDF(메타), Upstage, LlamaParse
    • 유연성/확장성: JSONLoader(+jq), WebBaseLoader(+bs4/프록시/비동기)

📎 참고/실습 파일

  • 예시 파일: SPRI_AI_Brief_2023년12월호_F.pdf, titanic.csv/xlsx, sample-word-document.docx, sample-ppt.pptx, people.json 등
  • 환경: langchain-community, unstructured, pymupdf, rapidocr-onnxruntime, bs4, openpyxl, jq, arxiv, langchain-upstage, llama-parse
profile
개발자

0개의 댓글