Ekstrak Teks dari PDF dengan PDFMiner di Python

Menguasai ekstraksi teks PDF dengan Python

Konten Halaman

PDFMiner.six adalah perpustakaan Python yang kuat untuk mengekstrak teks, metadata, dan informasi tata letak dari dokumen PDF.

Berbeda dengan pembaca PDF sederhana, ia menyediakan analisis mendalam terhadap struktur PDF dan menangani tata letak kompleks secara efektif.

Ekstraksi Teks dari pdf ke markdown - Visualisasi IPAD

Apa itu PDFMiner dan Mengapa Menggunakannya?

PDFMiner adalah perpustakaan Python murni yang dirancang untuk mengekstrak dan menganalisis teks dari dokumen PDF. Versi .six adalah cabang yang sedang dikembangkan yang mendukung Python 3.x, sementara proyek PDFMiner asli tidak lagi diperbarui.

Fitur Utama:

  • Implementasi Python murni (tidak ada ketergantungan eksternal)
  • Analisis tata letak yang rinci dan penempatan teks
  • Deteksi font dan karakter encoding
  • Dukungan untuk PDF terenkripsi
  • Alat baris perintah yang disertakan
  • Arsitektur yang dapat diperluas untuk pemrosesan kustom

PDFMiner sangat berguna ketika Anda membutuhkan kontrol yang presisi terhadap ekstraksi teks, perlu mempertahankan informasi tata letak, atau bekerja dengan dokumen multi-kolom yang kompleks. Meskipun mungkin lebih lambat dibandingkan beberapa alternatif, akurasinya dan kemampuan analisis yang rinci membuatnya menjadi pilihan utama untuk pipeline pemrosesan dokumen. Untuk alur kerja yang berlawanan, Anda mungkin juga tertarik dengan menghasilkan PDF secara program dalam Python.

Instalasi dan Pengaturan

Pasang PDFMiner.six menggunakan pip:

pip install pdfminer.six

Untuk lingkungan virtual (direkomendasikan):

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

Jika Anda baru mengenal manajemen paket Python, lihat cheatsheet Python kami untuk informasi lebih lanjut tentang pip dan lingkungan virtual.

Verifikasi instalasi:

pdf2txt.py --version

Perpustakaan ini menyertakan beberapa alat baris perintah:

  • pdf2txt.py - Ekstrak teks dari PDF
  • dumppdf.py - Dump struktur internal PDF
  • latin2ascii.py - Konversi karakter Latin ke ASCII

Alat-alat ini melengkapi utilitas manipulasi PDF lain seperti Poppler yang menyediakan fungsi tambahan seperti ekstraksi halaman dan konversi format.

Ekstraksi Teks Dasar

Ekstraksi Teks Sederhana

Cara paling sederhana untuk mengekstrak teks dari PDF:

from pdfminer.high_level import extract_text

# Ekstrak semua teks dari PDF
text = extract_text('document.pdf')
print(text)

API tingkat tinggi ini menangani kebanyakan kasus penggunaan umum dan mengembalikan seluruh dokumen sebagai satu string.

Ekstraksi Teks dari Halaman Tertentu

Untuk mengekstrak teks dari halaman tertentu:

from pdfminer.high_level import extract_text

# Ekstrak teks dari halaman 2-5 (0-indexed)
text = extract_text('document.pdf', page_numbers=[1, 2, 3, 4])
print(text)

Ini sangat berguna untuk dokumen besar di mana Anda hanya membutuhkan bagian tertentu, meningkatkan performa secara signifikan.

Ekstraksi Teks dengan Iterasi Halaman

Untuk memproses halaman secara individual:

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

Pendekatan ini memberikan lebih banyak kontrol atas cara setiap halaman diproses, berguna ketika bekerja dengan dokumen di mana struktur halaman bervariasi.

Analisis Tata Letak Lanjutan

Memahami LAParams

LAParams (Layout Analysis Parameters) mengontrol bagaimana PDFMiner memahami tata letak dokumen. Memahami perbedaan antara PDFMiner dan perpustakaan sederhana sangat penting di sini - PDFMiner sebenarnya menganalisis hubungan spasial antara elemen teks.

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

# Membuat LAParams kustom
laparams = LAParams(
    line_overlap=0.5,      # Tumpang tindih minimum untuk garis teks
    char_margin=2.0,       # Margin karakter
    line_margin=0.5,       # Margin garis
    word_margin=0.1,       # Jarak pemisah kata
    boxes_flow=0.5,        # Ambang batas aliran kotak
    detect_vertical=True,  # Deteksi teks vertikal
    all_texts=False        # Ekstrak hanya teks dalam kotak
)

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

Penjelasan Parameter:

  • line_overlap: Seberapa banyak garis harus tumpang tindih secara vertikal untuk dianggap sebagai garis yang sama (0.0-1.0)
  • char_margin: Jarak maksimum antara karakter dalam satu kata (sebagai kelipatan lebar karakter)
  • line_margin: Jarak maksimum antara garis dalam satu paragraf
  • word_margin: Ambang batas pemisah kata
  • boxes_flow: Ambang batas arah aliran kotak teks
  • detect_vertical: Aktifkan deteksi teks vertikal (umum dalam bahasa Asia)

Mengambil Informasi Tata Letak

Dapatkan informasi posisi dan font yang rinci:

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):
            # Dapatkan koordinat kotak batas
            x0, y0, x1, y1 = element.bbox
            print(f"Text di ({x0}, {y0}): {element.get_text()}")
            
            # Iterasi melalui garis
            for text_line in element:
                if isinstance(text_line, LTTextLine):
                    # Dapatkan detail tingkat karakter
                    for char in text_line:
                        if isinstance(char, LTChar):
                            print(f"Karakter: {char.get_text()}, "
                                  f"Font: {char.fontname}, "
                                  f"Ukuran: {char.height}")

Tingkat detail ini sangat berharga untuk analisis dokumen, ekstraksi formulir, atau ketika Anda perlu memahami struktur dokumen secara program.

Mengelola Jenis PDF Berbeda

PDF Terenkripsi

PDFMiner dapat menangani PDF yang dilindungi kata sandi:

from pdfminer.high_level import extract_text

# Ekstrak dari PDF terenkripsi
text = extract_text('encrypted.pdf', password='your_password')

Catat bahwa PDFMiner hanya dapat mengekstrak teks dari PDF - ia tidak dapat mengatasi pembatasan keamanan yang mencegah ekstraksi teks pada tingkat PDF.

Dokumen Multi-Kolom

Untuk dokumen dengan beberapa kolom, atur LAParams:

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

# Optimalkan untuk tata letak multi-kolom
laparams = LAParams(
    detect_vertical=False,
    line_margin=0.3,
    word_margin=0.1,
    boxes_flow=0.3  # Nilai lebih rendah untuk deteksi kolom yang lebih baik
)

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

Parameter boxes_flow sangat penting untuk dokumen multi-kolom - nilai yang lebih rendah membantu PDFMiner membedakan antara kolom yang berbeda.

Teks Non-Inggris dan Unicode

PDFMiner menangani Unicode dengan baik, tetapi pastikan encoding yang tepat:

from pdfminer.high_level import extract_text

# Ekstrak teks dengan dukungan Unicode
text = extract_text('multilingual.pdf', codec='utf-8')

# Simpan ke file dengan encoding UTF-8
with open('output.txt', 'w', encoding='utf-8') as f:
    f.write(text)

Bekerja dengan PDF Terpindai

PDFMiner tidak dapat mengekstrak teks dari PDF terpindai (gambar) secara langsung. Ini memerlukan OCR (Optical Character Recognition). Namun, Anda dapat mengintegrasikan PDFMiner dengan alat OCR.

Berikut cara mendeteksi apakah PDF terpindai dan membutuhkan OCR:

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):
    """Periksa apakah PDF terlihat seperti terpindai (penuh dengan gambar)"""
    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
    
    # Jika sebagian besar gambar dan sedikit teks, kemungkinan terpindai
    return image_count > text_count * 2

if is_scanned_pdf('document.pdf'):
    print("PDF ini tampaknya terpindai - gunakan OCR")
else:
    text = extract_text('document.pdf')
    print(text)

Untuk PDF terpindai, pertimbangkan mengintegrasikan dengan Tesseract OCR atau menggunakan alat untuk mengekstrak gambar dari PDF terlebih dahulu, lalu menerapkan OCR pada gambar-gambar tersebut.

Penggunaan Baris Perintah

PDFMiner menyertakan alat baris perintah yang kuat:

Ekstraksi Teks dengan Alat Baris Perintah

# Ekstrak teks ke stdout
pdf2txt.py document.pdf

# Simpan ke file
pdf2txt.py -o output.txt document.pdf

# Ekstrak halaman tertentu
pdf2txt.py -p 1,2,3 document.pdf

# Ekstrak sebagai HTML
pdf2txt.py -t html -o output.html document.pdf

Opsi Lanjutan

# Parameter tata letak kustom
pdf2txt.py -L 0.3 -W 0.1 document.pdf

# Ekstrak dengan tata letak rinci (XML)
pdf2txt.py -t xml -o layout.xml document.pdf

# Tetapkan kata sandi untuk PDF terenkripsi
pdf2txt.py -P mypassword encrypted.pdf

Alat baris perintah ini sangat bagus untuk pengujian cepat, skrip shell, dan integrasi ke dalam alur kerja otomatis.

Optimisasi Kinerja

Memproses PDF Besar

Untuk dokumen besar, pertimbangkan strategi optimisasi berikut:

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

# Proses hanya halaman yang diperlukan
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

# Nonaktifkan analisis tata letak untuk kecepatan
from pdfminer.high_level import extract_text
text = extract_text('large.pdf', laparams=None)  # Jauh lebih cepat

Pemrosesan Batch

Untuk memproses banyak PDF secara efisien:

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

def process_pdf(pdf_path):
    """Proses satu file 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"Proses: {pdf_path}"
    except Exception as e:
        return f"Kesalahan memproses {pdf_path}: {str(e)}"

# Proses PDF secara paralel
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)

# Penggunaan
batch_process_pdfs('/path/to/pdfs', num_workers=4)

Masalah Umum dan Solusinya

Masalah: Urutan Teks yang Tidak Benar

Masalah: Teks yang diekstrak tampak berantakan atau tidak dalam urutan yang benar.

Solusi: Atur ulang LAParams, terutama boxes_flow:

from pdfminer.layout import LAParams
laparams = LAParams(boxes_flow=0.3)  # Coba nilai berbeda
text = extract_text('document.pdf', laparams=laparams)

Masalah: Ruang Hilang Antara Kata

Masalah: Kata-kata bergabung tanpa ruang.

Solusi: Tingkatkan word_margin:

laparams = LAParams(word_margin=0.2)  # Tingkatkan dari nilai default 0.1
text = extract_text('document.pdf', laparams=laparams)

Masalah: Kesalahan Encoding

Masalah: Karakter aneh atau kesalahan encoding.

Solusi: Tentukan codec secara eksplisit:

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

Masalah: Kesalahan Memori dengan PDF Besar

Masalah: Kesalahan memori dengan file besar.

Solusi: Proses halaman demi halaman:

def extract_text_chunked(pdf_path, chunk_size=10):
    """Ekstrak teks dalam potongan untuk mengurangi penggunaan memori"""
    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
        
        # Proses dalam potongan
        if page_count % chunk_size == 0:
            yield ''.join(all_text)
            all_text = []
    
    # Yield teks tersisa
    if all_text:
        yield ''.join(all_text)

Membandingkan PDFMiner dengan Alternatif

Memahami kapan menggunakan PDFMiner versus perpustakaan lain penting:

PDFMiner vs PyPDF2

PyPDF2 lebih sederhana dan lebih cepat tetapi kurang akurat:

  • Gunakan PyPDF2 untuk: PDF sederhana, ekstraksi cepat, penggabungan/pemecahan PDF
  • Gunakan PDFMiner untuk: Tata letak kompleks, penempatan teks yang akurat, analisis rinci

PDFMiner vs pdfplumber

pdfplumber membangun di atas PDFMiner dengan API tingkat tinggi:

  • Gunakan pdfplumber untuk: Ekstraksi tabel, API yang lebih sederhana, prototipe cepat
  • Gunakan PDFMiner untuk: Kontrol maksimal, pemrosesan kustom, sistem produksi

PDFMiner vs PyMuPDF (fitz)

PyMuPDF jauh lebih cepat tetapi memiliki ketergantungan C:

  • Gunakan PyMuPDF untuk: Aplikasi kritis kinerja, pemrosesan skala besar
  • Gunakan PDFMiner untuk: Persyaratan Python murni, analisis tata letak rinci

Contoh Praktis: Ekstrak dan Analisis Dokumen

Berikut adalah contoh lengkap yang mengekstrak teks dan memberikan analisis dokumen:

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):
    """Ekstrak teks dan berikan analisis dokumen"""
    
    # Ekstrak teks penuh
    full_text = extract_text(pdf_path)
    
    # Statistik
    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
    }
    
    # Analisis rinci
    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
    }

# Penggunaan
result = analyze_pdf('document.pdf')
print(f"Jumlah Halaman: {result['stats']['pages']}")
print(f"Kata: {result['stats']['total_words']}")
print(f"Font utama: {result['most_common_font']}")
print(f"Ukuran utama: {result['most_common_size']}")

Integrasi dengan Pipeline Pemrosesan Dokumen

PDFMiner bekerja dengan baik dalam alur kerja pemrosesan dokumen yang lebih besar. Misalnya, ketika membangun sistem RAG (Retrieval-Augmented Generation) atau solusi manajemen dokumen, Anda mungkin menggabungkannya dengan alat Python lain untuk membuat pipeline yang lengkap.

Setelah Anda mengekstrak teks dari PDF, seringkali Anda perlu mengubahnya ke format lain. Anda dapat mengubah konten HTML ke Markdown menggunakan perpustakaan Python atau bahkan memanfaatkan konversi berbasis LLM dengan Ollama untuk transformasi dokumen yang cerdas. Teknik-teknik ini sangat berguna ketika ekstraksi PDF menghasilkan teks struktur HTML yang perlu dibersihkan dan direformat.

Untuk pipeline konversi dokumen yang komprehensif, Anda mungkin juga perlu menangani konversi dokumen Word ke Markdown, menciptakan alur kerja yang terpadu yang memproses berbagai format dokumen ke format output yang umum.

Praktik Terbaik

  1. Selalu gunakan LAParams untuk dokumen kompleks - Pengaturan default bekerja untuk dokumen sederhana, tetapi menyesuaikan LAParams meningkatkan hasil secara signifikan untuk tata letak kompleks.

  2. Uji terlebih dahulu dengan halaman sampel - Sebelum memproses batch besar, uji pengaturan ekstraksi Anda pada sampel representatif.

  3. Tangani pengecualian secara baik - File PDF bisa rusak atau tidak sesuai. Selalu bungkus kode ekstraksi dalam blok try-except.

  4. Cache teks yang diekstrak - Untuk pemrosesan berulang, cache teks yang diekstrak untuk menghindari pemrosesan ulang.

  5. Validasi teks yang diekstrak - Implementasikan pemeriksaan untuk memverifikasi kualitas ekstraksi (misalnya, panjang teks minimum, kata kunci yang diharapkan).

  6. Pertimbangkan alternatif untuk kasus penggunaan tertentu - Meskipun PDFMiner kuat, terkadang alat khusus (seperti tabula-py untuk tabel) lebih tepat.

  7. Perbarui PDFMiner secara teratur - Cabang .six sedang dikembangkan secara aktif. Perbarui untuk perbaikan bug dan peningkatan.

  8. Dokumentasikan kode Anda dengan baik - Ketika berbagi skrip ekstraksi PDF, gunakan blok kode Markdown dengan penyorotan sintaks untuk meningkatkan keterbacaan.

Kesimpulan

PDFMiner.six adalah alat penting bagi pengembang Python yang bekerja dengan dokumen PDF. Implementasi Python murni, analisis tata letak yang rinci, dan arsitektur yang dapat diperluas membuatnya ideal untuk sistem pemrosesan dokumen produksi. Meskipun mungkin memiliki kurva belajar yang lebih curam dibandingkan perpustakaan sederhana, presisi dan kontrol yang ditawarkannya tidak terbantahkan untuk tugas ekstraksi PDF yang kompleks.

Apakah Anda sedang membangun sistem manajemen dokumen, menganalisis kertas ilmiah, atau mengekstrak data untuk pipeline machine learning, PDFMiner menyediakan fondasi untuk ekstraksi teks PDF yang andal dalam Python.

Sumber Daya Terkait

Artikel Terkait di Situs Ini

Referensi Eksternal