Dokumente auslesen mit GPT-4o: PDF, Word und Excel per KI parsen

Andreas Nigg
Andreas Nigg · Mitgründer, Pondhouse Data
Veröffentlicht Aktualisiert 9 Min. Lesezeit
Dokumente auslesen mit GPT-4o: PDF, Word und Excel per KI parsen
Inhalt

GPT-4o liest PDF-, Word- und Excel-Dokumente zuverlässig aus, wenn Sie sie wie Bilder behandeln: Sie rendern jede Seite als Bild, schicken die Bilder an GPT-4o und lassen sich den Text zurückgeben. Dieser Beitrag zeigt den Python-Code für alle drei Formate. Word- und Excel-Dateien wandeln wir vorher mit LibreOffice im Headless-Modus in PDF um. Zu den Preisen, die beim Schreiben galten, kostete die Extraktion etwa 0,32 bis 0,62 Cent pro Seite.

Wozu das Ganze? LLM-Anwendungen, insbesondere RAG-Pipelines (auf Englisch), brauchen den Inhalt von Dokumenten, die für Menschen gemacht sind: PDFs, Word-Dokumente und Excel-Tabellen. Diese Dateiformate kann ein LLM nicht direkt lesen.

An diesem Problem arbeiten Menschen seit Jahrzehnten. Die gängigsten Ansätze waren regelbasierte Extraktion und Lösungen auf Basis von Machine Learning, und beide haben Grenzen. Regelbasierte Lösungen sind sehr schnell, kommen aber nur mit wenigen Dokumentarten zurecht. Machine-Learning-Lösungen sind flexibler, aber sehr langsam, und auch sie scheitern oft an der Vielfalt der Formate und Layouts.

In unserem Beitrag zur Datenextraktion mit LLMs haben wir beschrieben, wie und warum LLMs dieses Problem endlich lösen könnten. Ein Modell mit Milliarden Parametern zum Textauslesen einzusetzen, wirkt absurd, aber die Ergebnisse waren um Welten besser als alles, was wir vorher hatten. Wenn Sie mehr Hintergrund dazu möchten, wie LLMs beim Parsen von Dokumenten helfen, lesen Sie am besten zuerst diesen Beitrag.

Hier bauen wir darauf auf und zeigen, wie Sie Daten mit GPT-4o extrahieren, zum Zeitpunkt des Schreibens wohl eines der besten LLMs mit Bildeingabe. Außerdem zeigen wir, wie Sie Daten aus Word- und Excel-Dokumenten holen.

Update (November 2026): OpenAI hat GPT-4o als veraltet markiert, und der unten verwendete Snapshot gpt-4o-2024-08-06 wird am 14. Januar 2027 abgeschaltet (siehe die Deprecations-Seite). Der Ansatz funktioniert mit neueren Vision-Modellen genauso, sie zerlegen Bilder aber anders in Tokens: Laut OpenAIs Vision-Leitfaden gelten die unten beschriebenen 85 Tokens für die Stufe low und die Kacheln mit 512 Pixeln für GPT-4o, und bei manchen neueren Modellen verbraucht low nicht immer weniger Tokens als high. Rechnen Sie die Kosten pro Seite für das Modell nach, das Sie verwenden.

Die Strategie: Dokumente als Bilder mit einem Vision-LLM parsen

Unser einführender Beitrag zur Dokumentenextraktion mit LLMs erklärt die Strategie im Detail. Kurz zusammengefasst:

  1. Das Dokument in ein Bild umwandeln.
  2. Das Bild an ein LLM mit Bildverständnis schicken.
  3. Das LLM per Prompt bitten, den Text aus dem Bild zu extrahieren.

Screenshots von Dokumenten an ein LLM zu schicken und es höflich zu "bitten", den Text zurückzugeben, klingt zunächst etwas lächerlich. Auf den zweiten Blick ergibt es Sinn. Wir lassen das LLM das Dokument "lesen", indem wir ihm eine visuelle Darstellung geben. Ziemlich genau so holen auch wir einfachen Menschen den Text aus Dokumenten.

In der Praxis hat diese Strategie bei uns aus drei Gründen sehr gut funktioniert.

LLMs erfassen den Kontext eines Dokuments sehr gut und erkennen Layouts, Tabellen und andere Strukturen.

Per Prompt legen wir die Ausgabe fest. Wir können das Modell zum Beispiel bitten, Kopf- und Fußzeilen und andere irrelevante Teile wegzulassen oder Überschriften auf eine bestimmte Weise zu formatieren (etwa als Markdown).

Da wir die ganze Seite als Screenshot übergeben, kann das LLM auch Informationen aus eingebetteten Bildern holen, sogar aus Diagrammen. Mehr dazu in unserem Beitrag zur Bildanalyse mit LLMs (auf Englisch).

Python für das Parsen von Dokumenten mit GPT-4o einrichten

Wir verwenden dafür das gute alte Python.

  1. Legen Sie eine venv- oder conda-Umgebung an und aktivieren Sie sie.

  2. Installieren Sie die folgenden pip-Pakete:

    1pip install openai pillow pypdfium2 backoff

PDF-Dateien mit GPT-4o parsen

Wir beginnen mit dem überraschenderweise einfachsten Format: PDF.

(Warum überraschend? PDFs sind traditionell mühsam. Sie haben kein standardisiertes Layout, kennen keine Tabellen (Tabellen in PDFs sind nur Linien und Text!) und können Bilder, Diagramme und Visualisierungen aller Art enthalten. Genau daran sind klassische Extraktionssysteme bei PDFs gescheitert.)

  1. Importieren Sie zuerst die Pakete und initialisieren Sie den API-Client für GPT-4o.

    1from openai import AsyncOpenAI, RateLimitError
    2from io import BytesIO
    3import asyncio
    4import base64
    5import pypdfium2 as pdfium
    6import backoff
    7
    8client = AsyncOpenAI(api_key="your-api-key")

    Hinweis: Wir verwenden die asynchrone Variante des OpenAI-SDK, damit wir mehrere Anfragen gleichzeitig an die API schicken können.

  2. Laden Sie als Nächstes die PDF-Datei:

1 pdf_file = "mypdf.pdf"
2 pdf = pdfium.PdfDocument(pdf_file)
  1. Für die Bilder, die wir an GPT-4o schicken, gehen wir alle Seiten durch und wandeln jede mit pypdfium2 in ein Bild um.

    Ein wichtiges Detail: GPT-4o erwartet die Bilder Base64-kodiert.

    1images = []
    2for i in range(len(pdf)):
    3 page = pdf[i]
    4 image = page.render(scale=4).to_pil()
    5 buffered = BytesIO()
    6 image.save(buffered, format="JPEG")
    7 img_byte = buffered.getvalue()
    8 img_base64 = base64.b64encode(img_byte).decode("utf-8")
    9 images.append(img_base64)
  2. Jetzt schicken wir die Bilder an GPT-4o und warten auf den extrahierten Text. Die Funktion parse_page_with_gpt nimmt eine einzelne Base64-kodierte Seite entgegen und gibt den extrahierten Text zurück. Mit asyncio schicken wir dann alle Seiten des Dokuments gleichzeitig ab, sodass sie mehr oder weniger parallel laufen.

    Beachten Sie den Parameter detail = low im API-Aufruf. OpenAI bietet zwei Bildqualitäten an: low und high. Bei low skaliert OpenAIs Bildverarbeitung das Bild auf 512x512 Pixel herunter. high skaliert das Bild ebenfalls auf 512x512 Pixel herunter, erzeugt aber zusätzlich detaillierte Ausschnitte von je 512x512 Pixeln. Das Modell sieht zuerst das Bild in niedriger Auflösung als Überblick, danach die Ausschnitte. Der Haken: Sind die Details, die Sie extrahieren wollen, größer als 512 Pixel, bringen die Ausschnitte nichts. Für die Dokumentenextraktion bekommen Sie mit low fast immer bessere Ergebnisse, und das zu geringeren Kosten.

    1@backoff.on_exception(backoff.expo, RateLimitError)
    2async def parse_page_with_gpt(base64_image: str) -> str:
    3
    4 messages=[
    5 {
    6 "role": "system",
    7 "content": """You are a system to extract knowledge from documents.
    8 We want to add this knowledge to a wiki afterwards.
    9 Please extract the knowledge of this document.
    10 Please only extract the information given in the document.
    11 Do not answer with any additional explanations or text.
    12 I want to take your answer 1 to 1 and put it in the wiki.
    13 Please do not reference graphical elements or visualization in your answer. Just answer with the extracted text.
    14 Make sure that text at the end of the page as well as text at the beginning of the page are also at the end and beginning of your extraction - as this might be continuations of the previous and next page.
    15 """
    16 },
    17 {
    18 "role": "user",
    19 "content": [
    20 {"type": "text", "text": "Extract knowledge from this document"},
    21 {
    22 "type": "image_url",
    23 "image_url": {
    24 "url": f"data:image/jpeg;base64,{base64_image}",
    25 "detail": "low"
    26 },
    27 },
    28 ],
    29 }
    30 ]
    31
    32 response = await client.chat.completions.create(
    33 model="gpt-4o-2024-08-06",
    34 messages=messages,
    35 max_tokens=4096,
    36 )
    37
    38 return response.choices[0].message.content or ""
    39
    40text_of_pages = await asyncio.gather(*[parse_page_with_gpt(image) for image in images])

    Mit der Bibliothek backoff fangen wir Rate Limits ab. Das ist wichtig, denn die OpenAI-API hat recht strenge Limits.

  3. Zum Schluss fügen wir die Texte der einzelnen Seiten zu einem Dokumenttext zusammen.

    1document_text = "\n".join(text_of_pages)

Das war's. Mit wenigen Zeilen Code haben wir den Text einer PDF-Datei mit GPT-4o extrahiert. Nach unserer Erfahrung ist die Qualität mit klassischen Methoden nicht zu vergleichen, und zwar im allerbesten Sinn.

Was kostet es, ein PDF mit GPT-4o auszulesen?

Das Parsen von Dokumenten mit einem LLM ist schnell eingerichtet. Aber was kostet es mit den Modellen von OpenAI?

Wie üblich zahlen Sie für die Eingabe-Tokens und für die erzeugten Ausgabe-Tokens.

Die Ausgabe-Tokens sind leicht zu berechnen: Es sind die Tokens des Textes, der aus dem Dokument extrahiert wird. Stand November 2026 kostet GPT-4o laut Preisliste 10 US-Dollar pro 1 Million Ausgabe-Tokens (und 2,50 US-Dollar pro Million Eingabe-Tokens).

Nach unserer Erfahrung hat eine sehr volle Seite etwa 600 Tokens, die meisten Seiten eher 300. Eine Seite kostet an Ausgabe-Tokens also etwa 0,3 bis 0,6 Cent.

Dazu kommen die Eingabe-Tokens, die bei Bildern in der Stufe low überraschend günstig sind: OpenAI berechnet 85 Eingabe-Tokens pro Bild, das sind 0,0213 Cent zusätzlich pro Seite.

Insgesamt zahlen Sie etwa 0,32 bis 0,62 Cent pro Seite.

Warum eine Seite nach der anderen statt das ganze Dokument?

Warum der Aufwand, das Dokument in Seiten zu zerlegen und diese einzeln an die API zu schicken? Wegen der Auflösungsgrenzen des Vision-Modells von GPT-4o. Wie oben beschrieben, wird das Bild auf 512x512 Pixel herunterskaliert, der Text muss bei dieser Auflösung also lesbar bleiben. Eine einzelne A4-Seite ist bei 512x512 Pixeln meist noch gut genug lesbar.

Word-Dokumente (DOCX) mit GPT-4o parsen

Weiter geht es mit Word-Dokumenten im DOCX-Format. Warum ist das anders als bei PDFs? Weil Microsoft in einem Geniestreich (Achtung, Ironie) beschlossen hat, im Dateiformat keine Seitenumbrüche zu speichern. Wo eine Seite endet, entscheidet die Software, die das Dokument darstellt. (Das ist auch ein Grund, warum verschiedene DOCX-Programme dasselbe Dokument leicht unterschiedlich anzeigen.) Für uns heißt das: Wir können nicht einfach Screenshots der Seiten machen, weil wir nicht wissen, wo eine Seite beginnt und endet.

Nach vielen Experimenten hat sich gezeigt, dass es am besten funktioniert, das Word-Dokument zuerst in ein PDF umzuwandeln und dann wie oben beschrieben vorzugehen.

Ja, liebe Leserin, lieber Leser, der beste Weg, DOCX-Dokumente zu parsen, scheint dieser zu sein:

  1. Die DOCX-Datei in ein PDF umwandeln.
  2. Das Dokument in ein Bild umwandeln.
  3. Das Bild an ein LLM mit Bildverständnis schicken.
  4. Das LLM per Prompt bitten, den Text aus dem Bild zu extrahieren.

(Ich kann kaum glauben, dass ich das schreibe, aber die Qualität der Ausgabe ist tatsächlich sehr, sehr gut!)

Die Schritte 2, 3 und 4 haben wir im Abschnitt zu PDFs behandelt, bleibt also die Umwandlung von DOCX in PDF. Auch dafür gibt es mehrere Wege. Am besten hat bei uns funktioniert, LibreOffice im Headless-Modus laufen zu lassen, die DOCX-Datei zu rendern und als PDF zu speichern.

  1. Installieren Sie LibreOffice. Unter Ubuntu genügt apt install libreoffice. Für andere Plattformen finden Sie die Installationsdateien auf der LibreOffice-Downloadseite.

  2. Schreiben Sie dann eine Funktion, die das LibreOffice-Programm für Ihre Plattform zurückgibt.

    1import sys
    2def libreoffice():
    3 if sys.platform == 'darwin':
    4 return '/Applications/LibreOffice.app/Contents/MacOS/soffice'
    5 if sys.platform == 'win32':
    6 return 'C:\\Program Files\\LibreOffice\\program\\soffice.exe'
    7 return 'libreoffice'
  3. Als Nächstes folgt die Umwandlungsfunktion. Sie nimmt ein BytesIO entgegen und gibt ein BytesIO-Objekt mit der PDF-Datei zurück. Falls Sie BytesIO nicht kennen: Das ist ein binärer Stream auf Basis eines Byte-Puffers im Arbeitsspeicher.

    • Zuerst schreiben wir die BytesIO-Eingabe in eine temporäre Datei (LibreOffice arbeitet nur mit Dateien, nicht mit Streams).
    • Dann führen wir den LibreOffice-Befehl aus, der die Datei in ein PDF umwandelt.
    • Wenn die Umwandlung geklappt hat, lesen wir die erzeugte PDF-Datei ein und geben sie als BytesIO zurück.
    1import os
    2import re
    3import subprocess
    4import tempfile
    5
    6def convert_to_pdf(source: BytesIO, timeout=20) -> BytesIO:
    7 # Temporäres Verzeichnis für Eingabe- und Ausgabedatei anlegen
    8 with tempfile.TemporaryDirectory() as temp_dir:
    9 temp_input_path = os.path.join(temp_dir, "input_file")
    10 with open(temp_input_path, "wb") as temp_file:
    11 temp_file.write(source.getvalue())
    12
    13 # LibreOffice-Befehl zusammenbauen
    14 args = [
    15 libreoffice(),
    16 '--headless',
    17 '--convert-to',
    18 'pdf',
    19 '--outdir',
    20 temp_dir,
    21 temp_input_path
    22 ]
    23
    24 process = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout)
    25
    26 # Den Namen der Ausgabedatei aus der LibreOffice-Ausgabe lesen.
    27 # Die Ausgabe sieht etwa so aus: -> <filename> using filter
    28 filename_match = re.search('-> (.*?) using filter', process.stdout.decode())
    29
    30 if filename_match is None:
    31 raise Exception(process.stdout.decode())
    32
    33 output_filename = filename_match.group(1)
    34 output_path = os.path.join(temp_dir, output_filename)
    35
    36 # Die erzeugte PDF-Datei einlesen
    37 with open(output_path, "rb") as pdf_file:
    38 pdf_content = BytesIO(pdf_file.read())
    39
    40 return pdf_content

Jetzt setzen wir alles zusammen:

1docx_path = "mydoc.docx"
2with open(docx_path, "rb") as docx_file:
3 docx_content = BytesIO(docx_file.read())
4pdf = convert_to_pdf(docx_content)
5
6# ... weiter mit dem PDF-Parsing wie im Abschnitt oben beschrieben ...

Excel-Dateien (XLSX) mit GPT-4o parsen

Der Vollständigkeit halber: Excel-Dateien haben dasselbe Problem wie Word-Dateien. Es ist nicht klar, wo eine Seite beginnt und endet. Also wandeln wir die Excel-Datei wieder mit LibreOffice in ein PDF um und machen dann wie gewohnt weiter.

Der Ablauf ist genau derselbe wie bei DOCX-Dateien, wir können die Funktionen von oben also wiederverwenden.

1xlsx_path = "mydoc.xlsx"
2with open(xlsx_path, "rb") as xlsx_file:
3 xlsx_content = BytesIO(xlsx_file.read())
4pdf = convert_to_pdf(xlsx_content)
5
6# ... weiter mit dem PDF-Parsing wie im Abschnitt oben beschrieben ...

Hinweis: LibreOffice verwendet die Druckeinstellungen, die in Ihrer Datei gespeichert sind. Ist das Seitenlayout auf Querformat gestellt, druckt LibreOffice im Querformat. Ist eingestellt, dass alle Spalten auf eine Seite passen sollen, macht LibreOffice das. Haben Sie den Druckbereich auf einen bestimmten Bereich gesetzt, druckt LibreOffice nur diesen. So können Sie die Ausgabe bequem steuern.

Zusammenfassung: Dokumente mit GPT-4o auslesen

GPT-4o, zum Zeitpunkt des Schreibens eines der leistungsfähigsten Modelle mit Bildeingabe, löst ein altes Problem: Daten aus komplexen Dokumenten wie PDFs, Word-Dateien und Excel-Tabellen zu extrahieren.

Wenn Sie Dokumente in Bilder umwandeln und GPT-4o mit seinem Bildverständnis lesen lassen, erreichen Sie beim Auslesen und Parsen eine sehr hohe Genauigkeit. Das gilt besonders für mehrspaltige Layouts, Tabellen und eingebettete Bilder oder Diagramme, mit denen sich klassische Verfahren traditionell schwertun.

Zugegeben, die Pipeline wirkt seltsam: Wir öffnen eine Datei, wandeln sie in ein PDF um, das PDF in ein Bild, schicken das Bild an ein Modell mit Milliarden Parametern, bitten es freundlich, den Text zu extrahieren, und bekommen schließlich den Text zurück. Die Ergebnisse sprechen aber für sich. Sie liegen weit vor dem, was es vorher gab.

Noch einmal zusammengefasst: Derselbe bildbasierte Ansatz deckt PDFs, Word-Dokumente und Excel-Tabellen ab. DOCX- und XLSX-Dateien, die keine festen Seiten haben, wandeln Sie vorher mit LibreOffice in PDF um. Per Prompt steuern Sie, was extrahiert wird und wie es formatiert ist. Und die Kosten bleiben überschaubar, bei den meisten Dokumenten etwa 0,32 bis 0,62 Cent pro Seite. Zum Ausprobieren nehmen Sie den PDF-Code oben, lassen ihn auf eine Handvoll eigener Dokumente los und vergleichen das Ergebnis mit Ihrem bisherigen Parser.

Kundenaufträge kommen oft genau in diesen drei Formaten an. Für diesen Fall haben wir Pondhouse Orderdesk gebaut: Es liest Bestell-E-Mails, PDFs und Excel-Listen aus und macht daraus Aufträge im ERP-System.

Weiterlesen

Sie möchten zuverlässige KI-Agenten-Systeme bauen?

Wir haben auf Basis aktueller Forschung einen ausführlichen Leitfaden (auf Englisch) erstellt, wie Sie robuste KI-Agenten-Systeme bauen, die auch im produktiven Betrieb funktionieren. Der Leitfaden behandelt:

  • die 14 systematischen Fehlerquellen in Multi-Agenten-Systemen
  • belegte Best Practices für das Design von Agenten
  • strukturierte Kommunikationsprotokolle und Prüfmechanismen
Andreas Nigg

Über den Autor

Andreas Nigg

Mitgründer, Pondhouse Data

Andreas entwickelt seit mehr als acht Jahren Datenanwendungen. Bei Pondhouse Data konzipiert und baut er KI-Systeme und integriert sie in komplexe, gewachsene Unternehmensumgebungen.