OCR a Extrakce Tabulek z PDF: Rabbit Hole

Už se mi stalo, že jsem potřeboval extrahovat text nebo tabulky z PDF, ale pokaždé jsem si musel znovu zjišťovat, jak na to. Proto si to sem ukládám jako „rabbit hole“ poznámky pro příště. Jestli jsi tady poprvé, tak vítej v dírě 🐇🌍.

Co tenhle skript umí?

  1. Extrahuje text z PDF pomocí OCR (Tesseract).
  2. Uloží OCR výsledky do JSON a Excelu.
  3. Extrahuje tabulky z PDF pomocí pdfplumber.
  4. Zachová strukturu tabulek a exportuje je do JSON a Excelu.
  5. Loguje průběh, aby šlo snadno zjistit, kde se co pokazilo.

1. OCR – Extrakce textu z PDF

Tento kód převede PDF na obrázky, spustí OCR (Tesseract) a uloží výsledky.

import json
import pymupdf  # PyMuPDF
from pdf2image import convert_from_path
import pytesseract
from PIL import Image
import pandas as pd
import os
PDF_FILE = "test_1.pdf"
OUTPUT_JSON = "output.json"
OUTPUT_EXCEL = "output.xlsx"

def log(message):
    print(f"[INFO] {message}")

def extract_text_ocr(pdf_path):
    log(f"Načítám PDF: {pdf_path}")
    images = convert_from_path(pdf_path, dpi=300)
    log(f"PDF převedeno na {len(images)} obrázků.")

    ocr_text = []
    for i, img in enumerate(images):
        log(f"Spouštím OCR na stránce {i+1}...")
        text = pytesseract.image_to_string(img, lang="ces")
        ocr_text.append({"page": i + 1, "text": text.strip()})

    log("OCR dokončeno.")
    return ocr_text

def parse_data(ocr_results):
    log("Parsování dat - zatím neimplementováno.")
    return {}

def save_to_json(data, filename):
    with open(filename, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=4)
    log(f"Výstup uložen do: {filename}")

def save_to_excel(ocr_results, filename):
    log("Ukládám výstup do Excelu...")

    df = pd.DataFrame(ocr_results)
    df.to_excel(filename, index=False, engine="openpyxl")

    log(f"Excel uložen jako: {filename}")

def main():
    if not os.path.exists(PDF_FILE):
        log(f"Chyba: Soubor {PDF_FILE} neexistuje!")
        return
    ocr_results = extract_text_ocr(PDF_FILE)
    parsed_data = parse_data(ocr_results)
    output_data = {
        "ocr_results": ocr_results,
        "parsed_data": parsed_data
    }
    save_to_json(output_data, OUTPUT_JSON)
    save_to_excel(ocr_results, OUTPUT_EXCEL)



if __name__ == "__main__":
    main()

Vylepšení do budoucna:

  • Čistější správa dočasných souborů.
  • Automatická detekce tabulek pro lepší strukturovaný výsledek.

2. Extrakce tabulek z PDF

Pokud PDF obsahuje tabulky, je lepší použít pdfplumber, který je umí přímo identifikovat.

import os
import json
import pandas as pd
import pdfplumber

def log(message):
    print(f"[INFO] {message}")

def extract_tables_from_pdf(pdf_path):
    tables_data = []
    with pdfplumber.open(pdf_path) as pdf:
        for page_num, page in enumerate(pdf.pages):
            tables = page.extract_tables()
            for table in tables:
                tables_data.append({
                    "page": page_num + 1,
                    "data": [row for row in table if any(row)]  # Odstraníme prázdné řádky
                })
    return tables_data

def save_json(data, filename):
    with open(filename, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=4)
    log(f"Výstup uložen do: {filename}")

def save_excel(data, filename):
    log("Ukládám výstup do Excelu...")
    df_data = []
    for entry in data:
        for row in entry["data"]:
            df_data.append([entry["page"]] + row)
    df = pd.DataFrame(df_data)
    df.to_excel(filename, index=False, header=False, engine="openpyxl")
    log(f"Excel uložen jako: {filename}")

def process_pdf(pdf_path, output_dir):
    log(f"Zpracovávám: {pdf_path}")
    tables = extract_tables_from_pdf(pdf_path)

    base_name = os.path.splitext(os.path.basename(pdf_path))[0]
    json_path = os.path.join(output_dir, f"{base_name}.json")
    excel_path = os.path.join(output_dir, f"{base_name}.xlsx")

    save_json(tables, json_path)
    save_excel(tables, excel_path)

    log(f"Dokončeno: {pdf_path}")

def main():
    input_pdf = "rocenka_23.pdf"
    output_dir = "output23"
    os.makedirs(output_dir, exist_ok=True)

    process_pdf(input_pdf, output_dir)

if __name__ == "__main__":
    main()

Vylepšení do budoucna:

  • Lepší detekce tabulek, pokud jsou nesouvislé.
  • Uložení dat i s hlavičkami, pokud jsou detekovatelé.


Comments

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *