문서 100개, 파이썬은 3초면 끝납니다.
거래처에서 받은 계약서 PDF, 매달 쌓이는 세금계산서, 수십 페이지짜리 입찰 제안서. 내용을 엑셀로 옮기거나 특정 항목만 뽑아야 할 때, 결국 눈으로 읽고 손으로 타이핑하고 있진 않으신가요? 파일이 한두 개라면 모를까, 수십 개가 넘어가는 순간 이 작업은 반나절을 통째로 날립니다.
이 글에서는 파이썬으로 PDF 파일에서 텍스트를 자동으로 추출하는 방법을 다룹니다. 텍스트가 선택되는 일반 PDF부터, 스캔해서 이미지로만 된 PDF까지 두 가지 경우를 모두 다룹니다.
PDF의 두 가지 종류부터 확인하세요
시작 전에 반드시 확인해야 할 것이 있습니다. PDF에는 크게 두 가지 종류가 있고, 종류에 따라 사용하는 도구가 완전히 달라집니다.
- 텍스트 PDF: 파일을 열었을 때 마우스로 텍스트를 드래그해서 복사할 수 있는 PDF입니다. 워드·한글·엑셀 등에서 내보낸 파일이 여기에 해당합니다.
pdfplumber또는PyMuPDF로 추출합니다. - 이미지 PDF (스캔본): 종이 문서를 스캐너로 찍어서 만든 PDF입니다. 텍스트가 이미지로 저장되어 있어 드래그해도 선택이 안 됩니다. OCR(광학 문자 인식) 기술이 필요하며
pytesseract를 사용합니다.
확인 방법은 간단합니다. PDF를 열어서 텍스트를 마우스로 드래그해보세요. 선택이 된다면 텍스트 PDF, 선택이 안 된다면 이미지 PDF입니다.
사전 준비: 라이브러리 설치
텍스트 PDF용
pip install pdfplumber pymupdf
- pdfplumber: 텍스트 추출뿐 아니라 PDF 안의 표(테이블)도 구조를 유지한 채 추출할 수 있어 계약서·보고서 처리에 특히 유용합니다.
- PyMuPDF (fitz): 속도가 매우 빠르고 안정적입니다. 대용량 PDF나 파일 수가 많을 때 적합합니다.
이미지 PDF (스캔본)용
pip install pytesseract pdf2image Pillow
pytesseract는 파이썬 라이브러리 설치 외에 Tesseract OCR 엔진을 별도로 설치해야 합니다. 아래 링크에서 Windows용 설치 파일을 받아 실행합니다.
- Tesseract OCR 설치 파일 다운로드 (UB Mannheim)
- 설치 시 언어 팩 선택 화면에서 Korean을 체크해야 한국어 인식이 됩니다.
Case 1. 텍스트 PDF에서 본문 추출하기
pdfplumber 사용 (기본 텍스트 추출)
계약서·보고서처럼 텍스트 위주의 PDF에서 전체 내용을 추출하는 가장 기본적인 방법입니다.
# extract_text.py
import pdfplumber
pdf_path = "contract.pdf" # 추출할 PDF 파일 경로
with pdfplumber.open(pdf_path) as pdf:
for i, page in enumerate(pdf.pages):
text = page.extract_text()
if text:
print(f"--- {i+1}페이지 ---")
print(text)
PyMuPDF 사용 (빠른 대량 처리)
파일 수가 많거나 페이지가 많은 PDF를 빠르게 처리할 때 적합합니다. pdfplumber보다 처리 속도가 눈에 띄게 빠릅니다.
# extract_text_fast.py
import fitz # PyMuPDF
pdf_path = "contract.pdf"
doc = fitz.open(pdf_path)
for i, page in enumerate(doc):
text = page.get_text()
if text.strip():
print(f"--- {i+1}페이지 ---")
print(text)
doc.close()
Case 2. PDF 안의 표(테이블) 추출하기
계약서 단가표, 보고서 통계표처럼 PDF 안에 표가 있는 경우, pdfplumber는 표 구조를 그대로 살려서 추출할 수 있습니다. 추출한 데이터는 pandas DataFrame으로 바로 변환해 엑셀로 저장할 수 있습니다.
# extract_table.py
import pdfplumber
import pandas as pd
pdf_path = "report.pdf"
with pdfplumber.open(pdf_path) as pdf:
all_tables = []
for i, page in enumerate(pdf.pages):
tables = page.extract_tables() # 페이지 안의 모든 표 추출
for j, table in enumerate(tables):
# 첫 번째 행을 헤더로 사용해 DataFrame 생성
df = pd.DataFrame(table[1:], columns=table[0])
df["출처_페이지"] = i + 1
df["출처_표번호"] = j + 1
all_tables.append(df)
print(f"{i+1}페이지 표 {j+1}: {len(df)}행 추출")
if all_tables:
result = pd.concat(all_tables, ignore_index=True)
result.to_excel("tables_extracted.xlsx", index=False)
print(f"\n완료! 총 {len(result)}행이 저장되었습니다.")
else:
print("추출된 표가 없습니다.")
Case 3. 스캔본 PDF에서 OCR로 텍스트 추출하기
스캐너로 찍은 PDF는 텍스트가 이미지로 저장되어 있어 일반 추출 방법이 통하지 않습니다. PDF를 이미지로 변환한 뒤 OCR 엔진으로 텍스트를 인식하는 방식을 사용합니다.
# extract_ocr.py
import pytesseract
from pdf2image import convert_from_path
from PIL import Image
# Tesseract 설치 경로 지정 (Windows 기준, 설치 경로 확인 후 수정)
pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
pdf_path = "scanned_contract.pdf"
# PDF를 페이지별 이미지로 변환 (dpi가 높을수록 인식률 향상, 처리 속도는 느려짐)
pages = convert_from_path(pdf_path, dpi=300)
full_text = ""
for i, page_image in enumerate(pages):
# 한국어+영어 동시 인식: lang="kor+eng"
text = pytesseract.image_to_string(page_image, lang="kor+eng")
print(f"--- {i+1}페이지 ---")
print(text)
full_text += f"\n--- {i+1}페이지 ---\n" + text
# 전체 텍스트를 txt 파일로 저장
with open("ocr_result.txt", "w", encoding="utf-8") as f:
f.write(full_text)
print("\n완료! ocr_result.txt 에 저장되었습니다.")
Case 4. 폴더 안의 PDF 파일 여러 개를 한번에 처리하기
계약서나 보고서가 여러 개일 때, 폴더 안의 모든 PDF를 순서대로 읽어 결과를 하나의 엑셀 파일로 저장합니다.
# batch_extract.py
import pdfplumber
import pandas as pd
import glob
import os
folder_path = "pdf_files" # PDF 파일이 있는 폴더
file_list = sorted(glob.glob(os.path.join(folder_path, "*.pdf")))
print(f"발견된 PDF 파일 수: {len(file_list)}개\n")
results = []
for file in file_list:
filename = os.path.basename(file)
try:
with pdfplumber.open(file) as pdf:
full_text = ""
for page in pdf.pages:
text = page.extract_text()
if text:
full_text += text + "\n"
results.append({
"파일명": filename,
"총페이지": len(pdf.pages),
"추출텍스트": full_text.strip()
})
print(f"완료: {filename}")
except Exception as e:
print(f"건너뜀: {filename} → {e}")
results.append({
"파일명": filename,
"총페이지": 0,
"추출텍스트": f"[오류] {e}"
})
df = pd.DataFrame(results)
df.to_excel("pdf_extracted_all.xlsx", index=False)
print(f"\n완료! 총 {len(results)}개 파일 처리 → pdf_extracted_all.xlsx 저장")
자주 발생하는 문제와 해결법
문제 1. 추출한 텍스트에 줄바꿈이 이상하게 들어올 때
PDF의 레이아웃 구조상 줄바꿈이 의도치 않은 위치에 들어오는 경우가 많습니다. 후처리로 정리합니다.
# 불필요한 줄바꿈 제거 후 문단 단위로 정리
text = page.extract_text()
# 빈 줄은 문단 구분으로 유지하되, 단순 줄바꿈은 공백으로 변환
lines = text.split("\n")
cleaned = " ".join(line.strip() for line in lines if line.strip())
print(cleaned)
문제 2. 한글이 깨지거나 ? 로 출력될 때
텍스트를 파일로 저장할 때 인코딩을 반드시 utf-8로 지정해야 합니다. OCR의 경우 Tesseract 설치 시 한국어 팩이 누락된 경우입니다.
# 파일 저장 시 반드시 encoding="utf-8" 지정
with open("result.txt", "w", encoding="utf-8") as f:
f.write(text)
# OCR 한국어 팩 재설치 (Tesseract 설치 시 Korean 체크 확인)
# 설치 후 아래 명령어로 인식 언어 목록 확인
# tesseract --list-langs
문제 3. 비밀번호가 걸린 PDF일 때
pdfplumber는 비밀번호가 걸린 PDF를 열 때 password 인자를 지원합니다.
with pdfplumber.open("locked.pdf", password="1234") as pdf:
text = pdf.pages[0].extract_text()
print(text)
문제 4. pdfplumber로 표가 추출되지 않을 때
PDF에 따라 표의 경계선이 명확하지 않아 자동 감지가 안 되는 경우가 있습니다. 이럴 때는 표 감지 설정을 조정하거나, 텍스트를 추출한 뒤 직접 파싱하는 방식으로 전환합니다.
# 표 감지 설정을 느슨하게 조정
table_settings = {
"vertical_strategy": "text", # 선 대신 텍스트 위치 기준으로 열 감지
"horizontal_strategy": "text", # 선 대신 텍스트 위치 기준으로 행 감지
}
with pdfplumber.open("report.pdf") as pdf:
for page in pdf.pages:
tables = page.extract_tables(table_settings)
for table in tables:
print(table)
상황별 도구 선택 정리
- 텍스트 추출, 파일 수가 적을 때:
pdfplumber— 사용법이 직관적이고 표 추출까지 지원합니다. - 텍스트 추출, 파일 수가 많거나 속도가 중요할 때:
PyMuPDF(fitz)— 처리 속도가 가장 빠릅니다. - PDF 안의 표를 엑셀로 변환할 때:
pdfplumber+pandas조합이 가장 깔끔합니다. - 스캔본(이미지 PDF)일 때:
pdf2image+pytesseract— OCR이 필요하며 인식률은 문서 품질에 따라 달라집니다.
마치며..
오늘은 파이썬으로 PDF에서 텍스트와 표를 자동 추출하는 방법을 상황별로 살펴보았습니다. 기술의 목적은 결국 인간의 시간을 더 가치 있는 곳에 쓰게 하는 것입니다. 계약서를 손으로 옮기는 작업은 파이썬에게 맡기고, 여러분은 그 데이터로 더 중요한 판단에 집중하시길 바랍니다.
추출한 데이터를 엑셀 파일 여러 개와 합쳐야 한다면, 이전 글 파이썬으로 엑셀 파일 100개 한번에 합치기를 함께 참고해 보세요. 두 가지를 조합하면 PDF 수집부터 데이터 통합까지 하나의 파이프라인으로 만들 수 있습니다.
관련 내용
- [VS Code/Anaconda] Visual Studio Code 프로젝트에 conda 가상환경 적용
- [Anaconda/Windows] Anaconda 다운로드 및 설치
- [Pytorch] ImportError: No module named 'torch' (라이브러리 인식 문제 해결법)
본 포스팅의 코드는 자유롭게 수정 및 배포가 가능하나, 상업적 이용 시에는 출처를 반드시 밝혀주시기 바랍니다.