[Langchain] Document Loader

Hunie_07·2025년 3월 28일
0

Langchain

목록 보기
6/35

📌 문서 로더 (Document Loader)

1️⃣ 다양한 문서 형식 처리하기

  • 역할: Document Loader는 다양한 소스에서 문서를 로드
  • 구현:
    • Document Loader는 BaseLoader 인터페이스를 통해서 구현
    • .load() 또는 .lazy_load() 메서드를 통해 동일한 방식으로 호출
    • 대용량 데이터셋의 경우 메모리 효율을 위해 .lazy_load() 사용 권장
  • 종류:
    • PDF 파일 로더
    • 웹 페이지 로더
    • CSV 데이터 로더
    • 디렉토리 로더
    • HTML 데이터 로더
    • JSON 데이터 로더
    • Markdown 데이터 로더
    • Microsoft Office 데이터 로더

1. PDF 파일 로더 (PyPDFLoader)

from langchain_community.document_loaders import PyPDFLoader

# PDF 로더 초기화
pdf_loader = PyPDFLoader('./data/transformer.pdf') # 파일 경로

# 동기 로딩
pdf_docs = pdf_loader.load()
print(f'PDF 문서 개수: {len(pdf_docs)}')

- 출력

총 15페이지의 PDF 문서

PDF 문서 개수: 15

로딩된 전체 파일

pdf_docs

- 출력

[Document(metadata={'source': './data/transformer.pdf', 'page': 0, 'page_label': '1'}, page_content='Provided proper ... ]

내용 출력

# 첫 번째 문서의 내용 출력
print(pdf_docs[0].page_content)

- 출력

Provided proper attribution is provided, Google hereby grants permission to
reproduce
...

메타데이터 출력

# 첫 번째 문서의 메타데이터 출력
print(pdf_docs[0].metadata)

- 출력

{'source': './data/transformer.pdf', 'page': 0, 'page_label': '1'}

비동기 로딩

# 비동기 로딩 (대용량 파일에 권장)
async for page in pdf_loader.alazy_load():
    # 페이지별 처리
    print(page.metadata)  # 메타데이터 출력
    print(page.page_content) # 페이지 내용 출력
    print("-"*80)

2. 웹 문서 로더 (WebBaseLoader)

from langchain_community.document_loaders import WebBaseLoader

# 기본적인 텍스트 추출
web_loader = WebBaseLoader(
    web_paths=[
        "https://python.langchain.com/", 
        "https://js.langchain.com/",
        ],
    )

# 동기 로딩
web_docs = web_loader.load()

print(f'웹 문서 개수: {len(web_docs)}')

- 출력

웹 문서 개수: 2

  • .page_content, .metadata 동일하게 적용

특정 HTML 요소만 파싱

# 특정 HTML 요소만 파싱하고 싶을 경우 (bs4 활용)
import bs4

web_loader = WebBaseLoader(
    web_paths=["https://python.langchain.com/"],
    bs_kwargs={
        "parse_only": bs4.SoupStrainer(class_="theme-doc-markdown markdown"),
    },
    bs_get_text_kwargs={
        "separator": " | ",    # 구분자
        "strip": True          # 공백 제거
    }
)

# 동기 로딩
web_docs = web_loader.load()
print(web_docs[0].page_content)

  • theme-doc-markdown markdown 요소만 출력하는 모습

- 출력

Introduction | LangChain | is 
... environment set up.

3. JSON 파일 로더 (JSONLoader)

  • 설치: pip install jq / poetry add jq

(1) messages 배열의 content 필드만 추출

from langchain_community.document_loaders import JSONLoader 

json_loader = JSONLoader(
    file_path="./data/kakao_chat.json",
    jq_schema=".messages[].content",    # messages 배열의 content 필드만 추출
    text_content=True,                  # 추출하려는 필드가 텍스트인지 여부
)

json_docs = json_loader.load()

print("문서의 수:", len(json_docs))
print("-" * 50)
print("처음 문서의 메타데이터: \n", json_docs[0].metadata['seq_num'])
print("-" * 50)
print("처음 문서의 내용: \n", json_docs[0].page_content)

# JSONL 파일 로드하기
json_loader = JSONLoader(
    file_path="./data/kakao_chat.jsonl",
    jq_schema=".content",
    json_lines=True,
)

json_docs = json_loader.load()

# JSONL 파일 로드하기
json_loader = JSONLoader(
    file_path="./data/kakao_chat.jsonl",
    jq_schema=".",
    content_key="content",
    json_lines=True,
)

json_docs = json_loader.load()
  • kakao_chat.json
{
  "chatroom_name": "프로젝트 팀",
  "members": ["김철수", "이영희", "박민수"],
  "messages": [
    {
      "sender": "김철수",
      "timestamp": "2023-09-15 09:30:22",
      "content": "안녕하세요 여러분, 오늘 회의 시간 확인차 연락드립니다."
    },
    {
      "sender": "이영희",
      "timestamp": "2023-09-15 09:31:05",
      "content": "네, 안녕하세요. 오후 2시에 하기로 했어요."
    },
    {
      "sender": "박민수",
      "timestamp": "2023-09-15 09:32:18",
      "content": "확인했습니다. 회의실은 어디인가요?"
    },
    {
      "sender": "이영희",
      "timestamp": "2023-09-15 09:33:40",
      "content": "3층 대회의실입니다. 프로젝트 진행 상황 정리해오시는 거 잊지 마세요!"
    },
    {
      "sender": "김철수",
      "timestamp": "2023-09-15 09:34:55",
      "content": "네, 모두 준비했습니다. 회의 때 뵙겠습니다 :)"
    }
  ]
}

- 출력

문서의 수: 5
--------------------------------------------------
처음 문서의 메타데이터: 
 1
--------------------------------------------------
처음 문서의 내용: 
 안녕하세요 여러분, 오늘 회의 시간 확인차 연락드립니다.

로딩된 전체 파일

json_docs[0]

- 출력

Document(metadata={'source': 'C:\\Users\\ ... \\data\\kakao_chat.json', 'seq_num': 1}, page_content='안녕하세요 여러분, ...)

(2) messages 배열의 모든 아이템을 추출

from langchain_community.document_loaders import JSONLoader

json_loader = JSONLoader(
    file_path="./data/kakao_chat.json",
    jq_schema=".messages[]",     # messages 배열의 모든 아이템을 추출
    text_content=False,          # 추출하려는 필드가 텍스트인지 여부
)

json_docs = json_loader.load()

print("문서의 수:", len(json_docs))
print("-" * 50)
print("처음 문서의 메타데이터: \n", json_docs[0].metadata['seq_num'])
print("-" * 50)
print("처음 문서의 내용: \n", json_docs[0].page_content)

- 출력

문서의 수: 5
--------------------------------------------------
처음 문서의 메타데이터: 
 1
--------------------------------------------------
처음 문서의 내용: 
 {"sender": "\uae40\ucca0\uc218", "timestamp": "2023-09-15 09:30:22", "content": "\uc548\ub155\ud558\uc138\uc694 \uc5ec\ub7ec\ubd84, \uc624\ub298 \ud68c\uc758 \uc2dc\uac04 \ud655\uc778\ucc28 \uc5f0\ub77d\ub4dc\ub9bd\ub2c8\ub2e4."}

(3) messages 배열의 content, sender 필드만 추출

from langchain_community.document_loaders import JSONLoader

json_loader = JSONLoader(
    file_path="./data/kakao_chat.json",
    jq_schema=".messages[]|{content, sender}",  # messages 배열의 content, sender 필드를 추출
    text_content=False,          				# 추출하려는 필드가 텍스트인지 여부
)

json_docs = json_loader.load()

print("문서의 수:", len(json_docs))
print("-" * 50)
print("처음 문서의 메타데이터: \n", json_docs[0].metadata['seq_num'])
print("-" * 50)
print("처음 문서의 내용: \n", json_docs[0].page_content)

- 출력

문서의 수: 5
--------------------------------------------------
처음 문서의 메타데이터: 
 1
--------------------------------------------------
처음 문서의 내용: 
 {"content": "\uc548\ub155\ud558\uc138\uc694 \uc5ec\ub7ec\ubd84, \uc624\ub298 \ud68c\uc758 \uc2dc\uac04 \ud655\uc778\ucc28 \uc5f0\ub77d\ub4dc\ub9bd\ub2c8\ub2e4.", "sender": "\uae40\ucca0\uc218"}

(4) messages 배열의 content, sender 필드 추출 및 배열 이름 변경

from langchain_community.document_loaders import JSONLoader

json_loader = JSONLoader(
    file_path="./data/kakao_chat.json",
    jq_schema=".messages[]|{c: .content, s: .sender}",     
    # messages 배열의 모든 아이템을 추출 / 배열 이름 변경
    text_content=False,  # 추출하려는 필드가 텍스트인지 여부
)

json_docs = json_loader.load()

print("문서의 수:", len(json_docs))
print("-" * 50)
print("처음 문서의 메타데이터: \n", json_docs[0].metadata['seq_num'])
print("-" * 50)
print("처음 문서의 내용: \n", json_docs[0].page_content)

- 출력

문서의 수: 5
--------------------------------------------------
처음 문서의 메타데이터: 
 1
--------------------------------------------------
처음 문서의 내용: 
 {"c": "\uc548\ub155\ud558\uc138\uc694 \uc5ec\ub7ec\ubd84, \uc624\ub298 \ud68c\uc758 \uc2dc\uac04 \ud655\uc778\ucc28 \uc5f0\ub77d\ub4dc\ub9bd\ub2c8\ub2e4.", "s": "\uae40\ucca0\uc218"}

(5) 유니코드 디코딩

  • 현재 한글 문자들이 \uc548\ 과 같이 유니코드 이스케이프 시퀀스로 인코딩되어 있어 디코딩 실시
 # 유니코드 디코딩 (한글 문자들이 유니코드 이스케이프 시퀀스로 인코딩되어 있음)
from langchain_core.documents import Document

decoded_json_docs = []
for doc in json_docs:
    decoded_data = json.loads(doc.page_content)
    document_obj = Document(page_content=json.dumps(decoded_data, ensure_ascii=False), metadata=doc.metadata)
    decoded_json_docs.append(document_obj)

print("문서의 수:", len(decoded_json_docs))
print("-" * 50)
print("처음 문서의 메타데이터: \n", decoded_json_docs[0].metadata['seq_num'])
print("-" * 50)
print("처음 문서의 내용: \n", decoded_json_docs[0].page_content)

- 출력

문서의 수: 5
--------------------------------------------------
처음 문서의 메타데이터: 
 1
--------------------------------------------------
처음 문서의 내용: 
 {"c": "안녕하세요 여러분, 오늘 회의 시간 확인차 연락드립니다.", "s": "김철수"}

4. CSV 파일 로더 (CSVLoader)

데이터 조회

import pandas as pd

pd.read_csv("./data/kbo_teams_2023.csv").head()

- 출력

	Team	    City Founded	Home Stadium		 Championships	Introduction
0	KIA 타이거즈	광주	 1982		광주-기아 챔피언스 필드 11				KBO 리그의 전통 강호로, 역대 최다 우승 기록을 보유하고 있다. '타이거즈 스피...
1	두산 베어스	서울	 1982		잠실야구장			  6				2015년부터 2019년까지 5년 연속 한국시리즈에 진출한 강팀이다. 김태형 감독 ...
2	SSG 랜더스	인천	 2000		인천SSG랜더스필드		  5				SK 와이번스에서 SSG 랜더스로 구단명을 변경했다. 2022년 와일드카드 결정전부...
3	삼성 라이온즈	대구	 1982		대구삼성라이온즈파크	  8				2011년부터 2015년까지 5년 연속 한국시리즈 우승을 차지한 명문 구단이다....
4	LG 트윈스	서울	 1982		잠실야구장			  2				서울을 연고로 하는 인기 구단으로, 오랜 기간 우승이 없었으나 202329년 만...

from langchain_community.document_loaders.csv_loader import CSVLoader

# 기본 파일 로드
csv_loader = CSVLoader("./data/kbo_teams_2023.csv", encoding='utf-8') # utf-8 혹은 cp949
csv_docs = csv_loader.load()

print("문서의 수:", len(csv_docs))
print("-" * 50)
print("처음 문서의 메타데이터: \n", csv_docs[0].metadata)
print("-" * 50)
print("처음 문서의 내용: \n", csv_docs[0].page_content)

- 출력

문서의 수: 10
--------------------------------------------------
처음 문서의 메타데이터: 
 {'source': './data/kbo_teams_2023.csv', 'row': 0}
--------------------------------------------------
처음 문서의 내용: 
 Team: KIA 타이거즈
City: 광주
Founded: 1982
Home Stadium: 광주-기아 챔피언스 필드
Championships: 11
Introduction: KBO 리그의 전통 강호로, 역대 최다 우승 기록을 보유하고 있다. '타이거즈 스피릿'으로 유명하며, 양현종, 안치홍 등 스타 선수들을 배출했다. 광주를 연고로 하는 유일한 프로야구팀으로 지역 사랑이 강하다.

CSV 파싱 커스터마이징

## CSV 파싱 커스터마이징
csv_loader = CSVLoader(
    file_path="./data/kbo_teams_2023.csv",
    csv_args={
        "delimiter": ",",               # 구분자 지정
        "quotechar": '"',               # 따옴표 문자 지정
    },
    encoding='utf-8'
)

csv_docs = csv_loader.load()

print("문서의 수:", len(csv_docs))
print("-" * 50)
print("처음 문서의 메타데이터: \n", csv_docs[0].metadata)
print("-" * 50)
print("처음 문서의 내용: \n", csv_docs[0].page_content)

- 출력

문서의 수: 10
--------------------------------------------------
처음 문서의 메타데이터: 
 {'source': './data/kbo_teams_2023.csv', 'row': 0}
--------------------------------------------------
처음 문서의 내용: 
 Team: KIA 타이거즈
City: 광주
Founded: 1982
Home Stadium: 광주-기아 챔피언스 필드
Championships: 11
Introduction: KBO 리그의 전통 강호로, 역대 최다 우승 기록을 보유하고 있다. '타이거즈 스피릿'으로 유명하며, 양현종, 안치홍 등 스타 선수들을 배출했다. 광주를 연고로 하는 유일한 프로야구팀으로 지역 사랑이 강하다.

메타데이터 소스 컬럼 지정

## 소스 컬럼 지정
csv_loader = CSVLoader(
    file_path="./data/kbo_teams_2023.csv",
    source_column="Team",  # 이 컬럼의 값이 메타데이터의 source로 사용됨, 기존엔 전체 CSV 데이터가 메타데이터로 들어감
    encoding='utf-8'
)

csv_docs = csv_loader.load()

print("문서의 수:", len(csv_docs))
print("-" * 50)
print("처음 문서의 메타데이터: \n", csv_docs[0].metadata)
print("-" * 50)
print("처음 문서의 내용: \n", csv_docs[0].page_content)

- 출력

문서의 수: 10
--------------------------------------------------
처음 문서의 메타데이터: 
 {'source': 'KIA 타이거즈', 'row': 0}
--------------------------------------------------
처음 문서의 내용: 
 Team: KIA 타이거즈
City: 광주
Founded: 1982
Home Stadium: 광주-기아 챔피언스 필드
Championships: 11
Introduction: KBO 리그의 전통 강호로, 역대 최다 우승 기록을 보유하고 있다. '타이거즈 스피릿'으로 유명하며, 양현종, 안치홍 등 스타 선수들을 배출했다. 광주를 연고로 하는 유일한 프로야구팀으로 지역 사랑이 강하다.

5. Directory 로더

  • 개요: 디렉토리에서 파일들을 읽어 Document 객체로 변환
  • 기능:
    1. 파일시스템 탐색 (와일드카드 패턴 지원)
    2. 멀티스레딩을 통한 파일 I/O
    3. 인코딩 오류 등의 예외 처리

  • 리비안_KR.txt / 테슬라_KR.txt
from langchain_community.document_loaders import DirectoryLoader
from langchain_community.document_loaders import TextLoader

# 기본 사용법
dir_loader = DirectoryLoader(
    path="./",              # 파일 경로 - 현재 디렉토리
    glob="**/*_KR.txt",     # 파일 확장자 - txt 파일만 로드
    loader_cls=TextLoader,  # TextLoader, CSVLoader, UnstructuredFileLoader 등 지원
    loader_kwargs= {"encoding": "utf-8"}
    )
dir_docs = dir_loader.load()

print("문서의 수:", len(dir_docs))
print("-" * 50)
print("처음 문서의 메타데이터: \n", dir_docs[0].metadata)
print("-" * 50)
print("처음 문서의 내용: \n", dir_docs[0].page_content)

- 출력

문서의 수: 2
--------------------------------------------------
처음 문서의 메타데이터: 
 {'source': 'data\\리비안_KR.txt'}
--------------------------------------------------
처음 문서의 내용: 
 리비안은 MIT 박사 출신 RJ 스카린지가 2009년에 설립한 혁신적인 미국 전기차 제조업체입니다. 2011년부터 자율 전기차에 집중한 리비안은 2015년 대규모 투자를 통해 크게 성장하며 미시간과 베이 지역에 연구소를 설립했습니다. 주요 공급업체와의 접근성을 높이기 위해 본사를 미시간주 리보니아로 이전했습니다.

리비안의 초기 모델은 스포츠카 R1(원래 이름은 Avera), 2+2 좌석의 미드 엔진 하이브리드 쿠페로 피터 스티븐스가 디자인했습니다. 이 차는 쉽게 교체 가능한 본체 패널을 갖춘 모듈식 캡슐 구조를 특징으로 하며, 2013년 말에서 2014년 초 사이에 생산이 예상되었습니다. 리비안은 디젤 하이브리드 버전, 브라질 원메이크 시리즈를 위한 R1 GT 레이싱 버전, 4도어 세단 및 크로스오버 등 다양한 버전을 고려했습니다. 2011년에 프로토타입 해치백도 공개되었지만, R1과의 관계는 불명확합니다.

리비안은 202110월 첫 번째 양산 차량인 R1T 트럭을 고객에게 인도하기 시작했습니다.

진행 상태바 표시

  • show_progress=True
## 진행 상태바 표시
dir_loader = DirectoryLoader(
    path="./",              # 파일 경로 - 현재 디렉토리
    glob="**/*_KR.txt",     # 파일 확장자 - txt 파일만 로드
    loader_cls=TextLoader,  # TextLoader, CSVLoader, UnstructuredFileLoader 등 지원 
    loader_kwargs= {"encoding": "utf-8"},
    show_progress=True,     # 진행 상태바 표시
    )
dir_docs = dir_loader.load()

- 출력

100%|██████████| 2/2 [00:00<00:00, 999.95it/s]

0개의 댓글