파이썬에서 PDFMiner를 사용하여 PDF에서 텍스트 추출하기

파이썬으로 PDF 텍스트 추출을 완벽하게 다스리기

Page content

PDFMiner.six은 PDF 문서에서 텍스트, 메타데이터 및 레이아웃 정보를 추출하기 위한 강력한 파이썬 라이브러리입니다.

단순한 PDF 리더와 달리, PDF 구조에 대한 깊은 분석을 제공하며 복잡한 레이아웃을 효과적으로 처리합니다.

PDF에서 마크다운으로 텍스트 추출 - IPAD 시각화

PDFMiner란 무엇이며 왜 사용해야 하나요?

PDFMiner는 PDF 문서에서 텍스트를 추출하고 분석하기 위해 설계된 순수 파이썬 라이브러리입니다. .six 버전은 파이썬 3.x를 지원하는 활발히 유지보수되는 포크이며, 원래의 PDFMiner 프로젝트는 더 이상 업데이트되지 않습니다.

주요 기능:

  • 외부 종속성을 필요로 하지 않는 순수 파이썬 구현
  • 상세한 레이아웃 분석 및 텍스트 위치 지정
  • 글꼴 및 문자 인코딩 감지
  • 암호화된 PDF 지원
  • 명령줄 도구 포함
  • 커스텀 처리를 위한 확장 가능한 아키텍처

PDFMiner는 텍스트 추출에 대한 정확한 제어가 필요하거나 레이아웃 정보를 유지해야 하거나 복잡한 다중 열 문서를 다루는 경우 특히 유용합니다. 다른 대안보다 속도는 느릴 수 있지만, 정확성과 상세한 분석 기능으로 인해 문서 처리 파이프라인에서 선호되는 선택입니다. 반대로 작업을 수행할 경우, 파이썬에서 PDF를 프로그래밍적으로 생성하는 방법에 관심을 가질 수 있습니다.

설치 및 설정

pip를 사용하여 PDFMiner.six를 설치합니다:

pip install pdfminer.six

가상 환경(추천):

python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
pip install pdfminer.six

파이썬 패키지 관리에 익숙하지 않다면, pip 및 가상 환경에 대한 더 많은 정보를 얻기 위해 파이썬 체크리스트를 확인하세요.

설치 확인:

pdf2txt.py --version

라이브러리는 여러 명령줄 도구를 포함합니다:

  • pdf2txt.py - PDF에서 텍스트 추출
  • dumppdf.py - PDF 내부 구조 덤프
  • latin2ascii.py - 라틴 문자를 ASCII로 변환

이 도구들은 Poppler와 같은 PDF 조작 유틸리티와 함께 사용될 수 있으며, 페이지 추출 및 형식 변환과 같은 추가 기능을 제공합니다.

기본 텍스트 추출

간단한 텍스트 추출

PDF에서 텍스트를 추출하는 가장 간단한 방법은 다음과 같습니다:

from pdfminer.high_level import extract_text

# PDF에서 모든 텍스트 추출
text = extract_text('document.pdf')
print(text)

이 고급 API는 대부분의 일반적인 사용 사례를 처리하며, 전체 문서를 단일 문자열로 반환합니다.

특정 페이지에서 텍스트 추출

특정 페이지에서 텍스트를 추출하려면:

from pdfminer.high_level import extract_text

# 페이지 2-5(0 기준)에서 텍스트 추출
text = extract_text('document.pdf', page_numbers=[1, 2, 3, 4])
print(text)

이 방법은 대규모 문서에서 특정 섹션만 필요할 경우, 성능을 크게 향상시킬 수 있습니다.

페이지별 텍스트 추출

페이지별로 처리하려면:

from pdfminer.high_level import extract_pages
from pdfminer.layout import LTTextContainer

for page_layout in extract_pages('document.pdf'):
    for element in page_layout:
        if isinstance(element, LTTextContainer):
            print(element.get_text())

이 접근법은 페이지 구조가 다른 문서를 처리할 때 각 페이지에 대한 더 많은 제어를 제공합니다.

고급 레이아웃 분석

LAParams 이해

LAParams(레이아웃 분석 매개변수)는 PDFMiner가 문서 레이아웃을 해석하는 방법을 제어합니다. PDFMiner와 간단한 라이브러리 사이의 차이를 이해하는 것이 중요합니다 - PDFMiner는 실제로 텍스트 요소 간의 공간 관계를 분석합니다.

from pdfminer.high_level import extract_text
from pdfminer.layout import LAParams

# 사용자 정의 LAParams 생성
laparams = LAParams(
    line_overlap=0.5,      # 텍스트 줄의 수직 겹침 최소값
    char_margin=2.0,       # 같은 단어 내 문자 간격
    line_margin=0.5,       # 같은 단락 내 줄 간격
    word_margin=0.1,       # 단어 간격 임계값
    boxes_flow=0.5,        # 텍스트 박스 흐름 방향 임계값
    detect_vertical=True,  # 수직 텍스트 감지 활성화
    all_texts=False        # 박스 내 텍스트만 추출
)

text = extract_text('document.pdf', laparams=laparams)

매개변수 설명:

  • line_overlap: 줄이 동일한 줄로 간주되기 위해 수직으로 겹쳐야 하는 최소 비율 (0.0-1.0)
  • char_margin: 같은 단어 내 문자 간격 (문자 너비의 배수로 표현)
  • line_margin: 같은 단락 내 줄 간격
  • word_margin: 단어를 분리하는 간격 임계값
  • boxes_flow: 텍스트 박스 흐름 방향 임계값
  • detect_vertical: 수직 텍스트 감지 활성화 (아시아 언어에서 흔함)
  • all_texts: 박스 내 텍스트만 추출

레이아웃 정보 추출

상세한 위치 및 글꼴 정보를 얻는 방법:

from pdfminer.high_level import extract_pages
from pdfminer.layout import LTTextBox, LTTextLine, LTChar

for page_layout in extract_pages('document.pdf'):
    for element in page_layout:
        if isinstance(element, LTTextBox):
            # 경계 상자 좌표 얻기
            x0, y0, x1, y1 = element.bbox
            print(f"({x0}, {y0}) 위치의 텍스트: {element.get_text()}")
            
            # 줄 반복
            for text_line in element:
                if isinstance(text_line, LTTextLine):
                    # 문자 수준의 세부 정보 얻기
                    for char in text_line:
                        if isinstance(char, LTChar):
                            print(f"문자: {char.get_text()}, "
                                  f"글꼴: {char.fontname}, "
                                  f"크기: {char.height}")

이 수준의 세부 정보는 문서 분석, 양식 추출 또는 문서 구조를 프로그래밍적으로 이해할 때 매우 유용합니다.

다양한 PDF 유형 처리

암호화된 PDF

PDFMiner는 암호가 걸린 PDF를 처리할 수 있습니다:

from pdfminer.high_level import extract_text

# 암호가 걸린 PDF에서 텍스트 추출
text = extract_text('encrypted.pdf', password='your_password')

참고로, PDFMiner는 PDF 수준에서 텍스트 추출을 방지하는 보안 제한을 우회할 수는 없습니다.

다중 열 문서

다중 열 문서의 경우 LAParams를 조정하세요:

from pdfminer.high_level import extract_text
from pdfminer.layout import LAParams

# 다중 열 레이아웃 최적화
laparams = LAParams(
    detect_vertical=False,
    line_margin=0.3,
    word_margin=0.1,
    boxes_flow=0.3  # 다중 열 감지에 유리한 값
)

text = extract_text('multi_column.pdf', laparams=laparams)

boxes_flow 매개변수는 다중 열 문서에 특히 중요합니다 - 더 낮은 값은 PDFMiner가 다른 열을 구분하는 데 도움이 됩니다.

비영어 및 유니코드 텍스트

PDFMiner는 유니코드를 잘 처리하지만, 올바른 인코딩을 보장하세요:

from pdfminer.high_level import extract_text

# 유니코드 지원으로 텍스트 추출
text = extract_text('multilingual.pdf', codec='utf-8')

# UTF-8 인코딩으로 파일에 저장
with open('output.txt', 'w', encoding='utf-8') as f:
    f.write(text)

스캔된 PDF 처리

PDFMiner는 스캔된 PDF(이미지)에서 텍스트를 직접 추출할 수 없습니다. 이는 OCR(광학 문자 인식)이 필요합니다. 그러나 PDFMiner를 OCR 도구와 통합할 수 있습니다.

PDF가 스캔되었는지 확인하는 방법:

from pdfminer.high_level import extract_text
from pdfminer.high_level import extract_pages
from pdfminer.layout import LTFigure, LTImage

def is_scanned_pdf(pdf_path):
    """PDF가 스캔된 것인지 확인"""
    text_count = 0
    image_count = 0
    
    for page_layout in extract_pages(pdf_path):
        for element in page_layout:
            if isinstance(element, (LTFigure, LTImage)):
                image_count += 1
            elif hasattr(element, 'get_text'):
                if element.get_text().strip():
                    text_count += 1
    
    # 대부분 이미지이고 텍스트가 적을 경우, 스캔된 것으로 간주
    return image_count > text_count * 2

if is_scanned_pdf('document.pdf'):
    print("이 PDF는 스캔된 것으로 보입니다 - OCR 사용")
else:
    text = extract_text('document.pdf')
    print(text)

스캔된 PDF의 경우 Tesseract OCR이나 PDF에서 이미지 추출 도구를 사용하여 먼저 이미지를 추출한 후 OCR을 적용하는 것이 좋습니다.

명령줄 사용법

PDFMiner는 강력한 명령줄 도구를 포함합니다:

명령줄 도구로 텍스트 추출

# 텍스트를 표준 출력으로 추출
pdf2txt.py document.pdf

# 파일에 저장
pdf2txt.py -o output.txt document.pdf

# 특정 페이지 추출
pdf2txt.py -p 1,2,3 document.pdf

# HTML로 추출
pdf2txt.py -t html -o output.html document.pdf

고급 옵션

# 커스텀 레이아웃 매개변수
pdf2txt.py -L 0.3 -W 0.1 document.pdf

# 상세한 레이아웃 추출 (XML)
pdf2txt.py -t xml -o layout.xml document.pdf

# 암호가 걸린 PDF에 암호 설정
pdf2txt.py -P mypassword encrypted.pdf

이 명령줄 도구는 빠른 테스트, 쉘 스크립트 및 자동화된 워크플로우 통합에 매우 유용합니다.

성능 최적화

대규모 PDF 처리

대규모 문서의 경우 다음 최적화 전략을 고려하세요:

from pdfminer.high_level import extract_pages
from pdfminer.layout import LAParams

# 필요한 페이지만 처리
def extract_page_range(pdf_path, start_page, end_page):
    text_content = []
    for i, page_layout in enumerate(extract_pages(pdf_path)):
        if i < start_page:
            continue
        if i >= end_page:
            break
        text_content.append(page_layout)
    return text_content

# 속도를 위해 레이아웃 분석 비활성화
from pdfminer.high_level import extract_text
text = extract_text('large.pdf', laparams=None)  # 훨씬 빠름

배치 처리

여러 PDF를 효율적으로 처리하려면:

from multiprocessing import Pool
from pdfminer.high_level import extract_text
import os

def process_pdf(pdf_path):
    """단일 PDF 파일 처리"""
    try:
        text = extract_text(pdf_path)
        output_path = pdf_path.replace('.pdf', '.txt')
        with open(output_path, 'w', encoding='utf-8') as f:
            f.write(text)
        return f"처리됨: {pdf_path}"
    except Exception as e:
        return f"{pdf_path} 처리 오류: {str(e)}"

# 병렬 처리
def batch_process_pdfs(pdf_directory, num_workers=4):
    pdf_files = [os.path.join(pdf_directory, f) 
                 for f in os.listdir(pdf_directory) 
                 if f.endswith('.pdf')]
    
    with Pool(num_workers) as pool:
        results = pool.map(process_pdf, pdf_files)
    
    for result in results:
        print(result)

# 사용법
batch_process_pdfs('/path/to/pdfs', num_workers=4)

일반적인 문제 및 해결 방법

문제: 텍스트 순서 오류

문제: 추출된 텍스트가 어지럽거나 순서가 잘못됨.

해결 방법: LAParams를 조정하고 특히 boxes_flow를 조정하세요:

from pdfminer.layout import LAParams
laparams = LAParams(boxes_flow=0.3)  # 다른 값 시도
text = extract_text('document.pdf', laparam道=laparams)

문제: 단어 간 공백 누락

문제: 단어가 공백 없이 붙어 있음.

해결 방법: word_margin을 증가시킵니다:

laparams = LAParams(word_margin=0.2)  # 기본값 0.1에서 증가
text = extract_text('document.pdf', laparams=laparams)

문제: 인코딩 오류

문제: 이상한 문자나 인코딩 오류 발생.

해결 방법: 명시적으로 인코딩을 지정하세요:

text = extract_text('document.pdf', codec='utf-8')

문제: 대규모 PDF의 메모리 오류

문제: 대규모 파일에서 메모리 부족 오류 발생.

해결 방법: 페이지별로 처리하세요:

def extract_text_chunked(pdf_path, chunk_size=10):
    """메모리 사용을 줄이기 위해 텍스트를 청크로 추출"""
    all_text = []
    page_count = 0
    
    for page_layout in extract_pages(pdf_path):
        page_text = []
        for element in page_layout:
            if hasattr(element, 'get_text'):
                page_text.append(element.get_text())
        
        all_text.append(''.join(page_text))
        page_count += 1
        
        # 청크로 처리
        if page_count % chunk_size == 0:
            yield ''.join(all_text)
            all_text = []
    
    # 남은 텍스트 처리
    if all_text:
        yield ''.join(all_text)

PDFMiner 대안과 비교

PDFMiner를 사용할 때와 다른 라이브러리를 사용할 때의 차이를 이해하는 것이 중요합니다:

PDFMiner vs PyPDF2

PyPDF2는 더 간단하고 빠르지만 정확도가 낮습니다:

  • PyPDF2 사용 시: 간단한 PDF, 빠른 추출, PDF 병합/분할
  • PDFMiner 사용 시: 복잡한 레이아웃, 정확한 텍스트 위치, 상세한 분석

PDFMiner vs pdfplumber

pdfplumber는 PDFMiner에 기반하여 더 높은 수준의 API를 제공합니다:

  • pdfplumber 사용 시: 테이블 추출, 간단한 API, 빠른 프로토타이핑
  • PDFMiner 사용 시: 최대 제어, 커스텀 처리, 프로덕션 시스템

PDFMiner vs PyMuPDF (fitz)

PyMuPDF는 C 종속성이 있지만 훨씬 빠릅니다:

  • PyMuPDF 사용 시: 성능 중심의 애플리케이션, 대규모 처리
  • PDFMiner 사용 시: 순수 파이썬 요구, 상세한 레이아웃 분석

실용적인 예제: 문서 추출 및 분석

다음은 텍스트를 추출하고 문서 통계를 제공하는 완전한 예제입니다:

from pdfminer.high_level import extract_pages, extract_text
from pdfminer.layout import LTTextBox, LTChar
from collections import Counter
import re

def analyze_pdf(pdf_path):
    """텍스트 추출 및 문서 분석"""
    
    # 전체 텍스트 추출
    full_text = extract_text(pdf_path)
    
    # 통계
    stats = {
        'total_chars': len(full_text),
        'total_words': len(full_text.split()),
        'total_lines': full_text.count('\n'),
        'fonts': Counter(),
        'font_sizes': Counter(),
        'pages': 0
    }
    
    # 상세 분석
    for page_layout in extract_pages(pdf_path):
        stats['pages'] += 1
        
        for element in page_layout:
            if isinstance(element, LTTextBox):
                for line in element:
                    for char in line:
                        if isinstance(char, LTChar):
                            stats['fonts'][char.fontname] += 1
                            stats['font_sizes'][round(char.height, 1)] += 1
    
    return {
        'text': full_text,
        'stats': stats,
        'most_common_font': stats['fonts'].most_common(1)[0] if stats['fonts'] else None,
        'most_common_size': stats['font_sizes'].most_common(1)[0] if stats['font_sizes'] else None
    }

# 사용법
result = analyze_pdf('document.pdf')
print(f"페이지 수: {result['stats']['pages']}")
print(f"단어 수: {result['stats']['total_words']}")
print(f"주요 글꼴: {result['most_common_font']}")
print(f"주요 크기: {result['most_common_size']}")

문서 처리 파이프라인과의 통합

PDFMiner는 더 큰 문서 처리 워크플로우에서 잘 작동합니다. 예를 들어, RAG(검색 기반 생성) 시스템이나 문서 관리 솔루션을 구축할 때, 다른 파이썬 도구와 결합하여 완전한 파이프라인을 만들 수 있습니다.

PDF에서 텍스트를 추출한 후, 다른 형식으로 변환해야 할 경우가 많습니다. 파이썬 라이브러리를 사용하여 HTML 콘텐츠를 마크다운으로 변환하거나, 심지어 LLM 기반 변환을 사용하여 Ollama 활용하여 지능적인 문서 변환을 수행할 수 있습니다. 이러한 기술은 PDF 추출이 HTML과 같은 구조화된 텍스트를 생성할 때 청소 및 재포맷팅이 필요한 경우 특히 유용합니다.

포괄적인 문서 변환 파이프라인을 구축할 때는 워드 문서를 마크다운으로 변환을 고려해야 하며, 여러 문서 형식을 공통 출력 형식으로 처리하는 통합 워크플로우를 생성할 수 있습니다.

최선의 실천 방법

  1. 복잡한 문서에 항상 LAParams 사용 - 기본 설정은 간단한 문서에 적합하지만, 복잡한 레이아웃의 경우 LAParams를 조정하여 결과를 크게 향상시킬 수 있습니다.
  2. 샘플 페이지로 먼저 테스트 - 대규모 배치를 처리하기 전에 대표적인 샘플로 추출 설정을 테스트하세요.
  3. 예외를 부드럽게 처리 - PDF 파일이 손상되었거나 잘못되었을 수 있으므로, 항상 추출 코드를 try-except 블록으로 감싸세요.
  4. 추출된 텍스트를 캐시 - 반복 처리 시, 추출된 텍스트를 캐시하여 재처리를 피하세요.
  5. 추출된 텍스트를 검증 - 추출 품질을 확인하기 위해 최소 텍스트 길이, 예상 키워드 등 검사를 구현하세요.
  6. 특정 사용 사례에 대안 고려 - PDFMiner는 강력하지만, 테이블을 위한 전용 도구(예: tabula-py)가 더 적합한 경우도 있습니다.
  7. PDFMiner 업데이트 유지 - .six 포크는 활발히 유지보수되고 있으므로, 버그 수정 및 개선을 위해 항상 업데이트하세요.
  8. 코드를 문서화 - PDF 추출 스크립트를 공유할 때, 마크다운 코드 블록과 함께 구문 강조를 사용하여 가독성을 높이세요.

결론

PDFMiner.six는 파이썬 개발자가 PDF 문서를 다루는 데 필수적인 도구입니다. 순수 파이썬 구현, 상세한 레이아웃 분석, 확장 가능한 아키텍처로 인해 생산성 문서 처리 시스템에 이상적입니다. 간단한 라이브러리보다 학습 곡선이 더 가파르지만, 복잡한 PDF 추출 작업에 필요한 정확성과 제어는 비타협적입니다.

문서 관리 시스템을 구축하거나 과학 논문을 분석하거나 머신러닝 파이프라인에 데이터를 추출하는 경우, PDFMiner는 파이썬에서 신뢰할 수 있는 PDF 텍스트 추출 기초를 제공합니다.

관련 자료

이 사이트의 관련 기사

외부 참고 자료