RAG2026-5일6차시 · 문서 로딩 실습8 / 19← 이전목차다음 →MetaContents

6차시. 문서 로딩 실습

5. 실습 ② — PDF 읽기

출처: 원본 PDF 06차시_문서로딩실습.pdf 10~11쪽 · 쪽 그림 10쪽 11쪽

이제 실전에서 가장 많이 쓰는 PDF입니다. TXT와 결정적으로 다른 점이 하나 있습니다.

📄 PDF는 페이지마다 Document가 하나씩 생깁니다
10페이지짜리 PDF를 읽으면
→ Document 10개가 만들어집니다
각 Document의 metadata에는
→ 몇 페이지인지가 자동으로 기록됩니다
이게 바로 출처 표시가 가능한 이유입니다!

5-1) 코드 작성

📝 src/load_pdf.py

Python
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("data/manual.pdf")
docs = loader.load()
print("총 페이지 수 :", len(docs))
print()
# 모든 쪽을 살펴보기 (지금은 2쪽뿐입니다)
for d in docs:
    page = d.metadata["page"]
    preview = d.page_content[:60].replace("\n", " ")
    print(f"[{page}쪽] {preview} ...")

실습 코드 · 06/load_pdf.py

실습 코드: 실습/src/06/load_pdf.py · 위의 원본 PDF 6차시 10쪽 「5-1) 코드 작성」과 이어집니다.

Python
# ============================================================
# 6차시 | PPT: 06차시_문서로딩실습.pptx
# 역할: PDF 로더로 안내문 PDF를 읽고 첫 페이지를 출력
# 입력: ../../data/notice.pdf
# 출력: 페이지 수, 첫 페이지 본문, metadata
# 흐름:
#   notice.pdf -> PyPDFLoader.load() -> Document 리스트 -> print
# ============================================================
# Document: 페이지 하나의 본문과 metadata를 담는 객체
# metadata: source(파일 경로), page(0부터 세는 쪽 번호) 등이 들어 있는 딕셔너리

# PDF 전용 로더입니다. pypdf 패키지가 설치되어 있어야 합니다.
from langchain_community.document_loaders import PyPDFLoader

# 경로는 실행 위치(실습/src/06) 기준입니다. 다른 폴더에서 실행하면 FileNotFoundError가 납니다.
loader = PyPDFLoader(
    "../../data/notice.pdf"
)

# load()는 쪽마다 Document 하나씩 담은 리스트를 돌려줍니다.
documents = loader.load()
print(f"문서 길이 => {len(documents)}")
print()
# [0]은 첫 쪽입니다. 본문이 비어 있으면 스캔 PDF를 의심합니다.
print(f"문서 내용 =>\n {documents[0].page_content}")
print()
# metadata의 page는 0부터 셉니다. 사람에게 보여 줄 때는 1을 더합니다.
print(f"메타 =>\n {documents[0].metadata}")

실행 결과 샘플 (교안 기록. API 키가 필요한 코드는 키 없이 맞춘 예시이고, 모델의 답은 실행할 때마다 달라집니다)

출력
===== 실행 결과 샘플 =====
실행: cd 실습/src/06
      python load_pdf.py
문서 길이 => 1

문서 내용 =>
 고객 안내문
1. 환불 규정
상품 수령 후 7 일 이내에 환불을 신청하실 수 있습니다.
단순 변심의 경우 왕복 배송비는 고객 부담입니다.
2. 교환 규정
상품 불량의 경우 30 일 이내에 교환이 가능합니다.
이 경우 배송비는 당사가 부담합니다.
3. 고객센터
운영 시간은 평일 09:00 ~ 18:00 입니다.
전화 1588-0000 / 이메일 help@example.com

메타 =>
 {'producer': 'LibreOffice 24.2', 'creator': 'Writer', 'creationdate': '2026-09-03T06:20:59+00:00', 'author': 'Un-named', 'source': '../../data/notice.pdf', 'total_pages': 1, 'page': 0, 'page_label': '1'}

코드 해설

PDF 로더로 안내문 PDF를 읽고 첫 페이지를 출력입니다. 입력은 ../../data/notice.pdf이고, 출력은 페이지 수, 첫 페이지 본문, metadata입니다.

주석에 적힌 흐름입니다.

출력
notice.pdf -> PyPDFLoader.load() -> Document 리스트 -> print

코드 앞에서 고정해 두는 말입니다.

  • Document: 페이지 하나의 본문과 metadata를 담는 객체
  • metadata: source(파일 경로), page(0부터 세는 쪽 번호) 등이 들어 있는 딕셔너리

파일 맨 아래 실행 결과 샘플 주석은 실행되지 않습니다. 화면 출력은 다음 절에 다시 적어 두었습니다.

실습 코드 · 06/validate.py

실습 코드: 실습/src/06/validate.py · 위의 원본 PDF 6차시 10쪽 「5-1) 코드 작성」과 이어집니다.

Python
# ============================================================
# 6차시 | PPT: 06차시_문서로딩실습.pptx
# 역할: PDF에서 글자가 거의 없는 페이지가 있는지 검사
# 입력: ../../data/notice.pdf 를 읽은 Document 리스트
# 출력: 짧은 페이지가 있을 때만 OCR 안내 문장. 없으면 출력 없음
# 흐름:
#   notice.pdf -> PyPDFLoader.load() -> validate(docs)
#     -> 10자 미만 페이지를 모음
#     -> 있으면 print, 없으면 끝
# ============================================================
# Document: 페이지 하나의 본문(page_content)과 metadata를 담는 객체
# metadata: page 키에 쪽 번호(0부터)가 들어 있습니다.
# OCR: 스캔 이미지 PDF에서 글자를 읽어 내는 처리. 이 파일은 필요 여부만 알립니다.

# PDF 파일을 페이지별 문서로 읽기 위한 로더를 가져옵니다.
from langchain_community.document_loaders import PyPDFLoader

# 실행 위치를 기준으로 PDF 파일의 경로를 지정합니다.
loader = PyPDFLoader(
    "../../data/notice.pdf"
)

# PDF의 각 페이지를 문서 객체로 불러옵니다.
docs = loader.load()

def validate(docs):
    # 텍스트가 비어 있거나 너무 짧은 페이지 번호를 저장합니다.
    empty_pages = []

    # 불러온 각 페이지 문서를 차례로 검사합니다.
    for d in docs:
        # 앞뒤 공백을 제거한 페이지 텍스트를 확인합니다.
        text = d.page_content.strip()
        # 글자 수가 10자 미만이면 텍스트 추출이 제대로 되지 않았다고 봅니다.
        if len(text) < 10:
            # 페이지 번호가 없으면 물음표를 기본값으로 사용합니다.
            page = d.metadata.get("page", "?")
            empty_pages.append(page)

    # 텍스트가 거의 없는 페이지가 있으면 OCR이 필요하다는 안내를 출력합니다.
    # 짧은 페이지가 없으면 이 분기는 실행되지 않고, 함수는 아무것도 출력하지 않습니다.
    if empty_pages:
        print("스캔 pdf 파일의 경우, OCR 처리가 필요합니다. 아래 페이지를 확인하세요.")

# 불러온 PDF 페이지들을 검사합니다.
validate(docs)

실행 결과 샘플 (교안 기록. API 키가 필요한 코드는 키 없이 맞춘 예시이고, 모델의 답은 실행할 때마다 달라집니다)

출력
===== 실행 결과 샘플 =====
실행: cd 실습/src/06
      python validate.py
(표준 출력 없음. notice.pdf 본문이 10자 이상이라 empty_pages가 비고 print가 실행되지 않습니다.)

코드 해설

PDF에서 글자가 거의 없는 페이지가 있는지 검사입니다. 입력은 ../../data/notice.pdf 를 읽은 Document 리스트이고, 출력은 짧은 페이지가 있을 때만 OCR 안내 문장. 없으면 출력 없음입니다.

주석에 적힌 흐름입니다.

출력
notice.pdf -> PyPDFLoader.load() -> validate(docs)
-> 10자 미만 페이지를 모음
-> 있으면 print, 없으면 끝

코드 앞에서 고정해 두는 말입니다.

  • Document: 페이지 하나의 본문(page_content)과 metadata를 담는 객체
  • metadata: page 키에 쪽 번호(0부터)가 들어 있습니다.
  • OCR: 스캔 이미지 PDF에서 글자를 읽어 내는 처리. 이 파일은 필요 여부만 알립니다.

함수와 클래스로 나누어 읽습니다.

  • validate: 이름 그대로 한 가지 일만 합니다. 본문 주석을 같이 읽습니다.

파일 맨 아래 실행 결과 샘플 주석은 실행되지 않습니다. 화면 출력은 다음 절에 다시 적어 두었습니다.

5-2) 실행 결과

출력
총 페이지 수 : 2

[0쪽] 제품 사용 설명서  1. 제품 개요 본 제품은 가정용 공기청정기로 최대 10평 공간에 적합하며 ...
[1쪽] 3. 환불 및 교환 규정 상품을 받은 후 7일 이내에는 환불을 신청할 수 있으며 ...

⚠️ 페이지 번호는 0부터 시작합니다
metadata의 page 값은 0, 1, 2, ... 순입니다.
사람이 보는 "1페이지"는 코드에서는 page=0 입니다.
나중에 사용자에게 출처를 보여줄 때는
page + 1을 해주는 것이 친절합니다.

← 이전 절6차시 · 4. 실습 ① — 텍스트 파일 읽기다음 절 →6차시 · 6. 실습 ③ — 로딩 결과 검증하기