ANMELDEN  login to app
2026-05-26 11 Min. Lesezeit

100 Rechnungen in 10 Minuten mit Python umwandeln (myocr-SDK-Tutorial)

Von null zu einer funktionierenden Batch-Pipeline mit dem offiziellen myocr-client Python-SDK. Echter Code, echte Fehlerbehandlung, Webhook-Zustellung.

Von myocr.app-Team

Warum ein dediziertes Python-SDK wichtig ist

Wenn Sie produktive OCR in Python ausliefern, haben Sie drei Möglichkeiten. Sie können die API mit reinem requests aufrufen und den Boilerplate selbst schreiben — Authentifizierung, Wiederholungsversuche, Fehlerzuordnung, Polling für asynchrone Jobs, Downloads über signierte URLs. Sie können einen generischen OpenAPI-Generator verwenden, der einen funktionierenden, aber hässlichen Client erzeugt. Oder Sie installieren ein gepflegtes SDK, das das Protokoll abstrahiert und Sie Geschäftslogik schreiben lässt.

Dieses Tutorial nutzt die dritte Option: myocr-client, das offizielle Python-SDK für myocr.app. In 11 Minuten gelangen Sie von pip install zu einem Skript, das 100 PDF-Rechnungen parallel konvertiert, Kontingent- und OCR-Fehler elegant behandelt und Ihre App per Webhook benachrichtigt, sobald jeder Job abgeschlossen ist.

Was Sie erstellen werden

Ein einzelnes Python-Skript, das:

Insgesamt: ~30 Zeilen Geschäftslogik, plus einen Webhook-Empfänger, falls Sie Push-basierte Zustellung wünschen.

Voraussetzungen

Schritt 1: Installation

pip install myocr-client

Das ist alles. Das SDK hängt nur von requests ab. Keine nativen Erweiterungen, keine SDK-spezifische Laufzeitumgebung.

Schritt 2: Konvertieren Sie Ihre erste Rechnung (synchron)

from myocr_client import MyOCRClient

client = MyOCRClient(api_key="sk_live_...")  # or set MYOCR_API_KEY env var

result = client.convert("invoice.pdf", model="invoice")
result.save("invoice.xlsx")
print(f"{result.pages_used} pages → invoice.xlsx ({result.request_id})")

Das ist ein vollständiger OCR-Aufruf. Die Methode convert() ist synchron und am besten für Dateien unter 5 MB und 10 Seiten geeignet. Das zurückgegebene ConversionResult enthält content (Bytes), pages_used, das ursprüngliche model und eine request_id, nach der Sie in Server-Logs suchen können.

Schritt 3: Wechseln Sie für die Stapelverarbeitung zu asynchron

Bei 100 Rechnungen möchten Sie keine 100 aufeinanderfolgenden synchronen Aufrufe — das ist serielle Latenz. Verwenden Sie stattdessen /v1/batch. Das SDK stellt dies als client.batch() bereit:

from pathlib import Path
from myocr_client import MyOCRClient

client = MyOCRClient()  # MYOCR_API_KEY from env

folder = Path("./invoices")
pdfs = sorted(folder.glob("*.pdf"))[:20]  # /v1/batch accepts up to 20 files

batch = client.batch([str(p) for p in pdfs], model="invoice")
print(f"Created {batch.jobs_created} jobs, {len(batch.errors)} errors")

done = batch.wait_all(timeout=600)
for job in done:
    if job.is_done:
        job.download(f"out/{job.request_id}.xlsx")
    else:
        print(f"Failed: {job.request_id} — {job.error_detail}")

Drei Dinge sind zu beachten. Erstens akzeptiert der Endpunkt /v1/batch höchstens 20 Dateien pro Aufruf — teilen Sie bei 100 Rechnungen Ihren Ordner in 5 Stapel auf. Zweitens fragt wait_all() jeden Job einzeln mit exponentiellem Backoff ab (1s → 2s → 4s → 8s → 15s Obergrenze), sodass 100 untätige sleep(1)-Aufrufe nicht Ihr Ratenlimit aufbrauchen. Drittens landet, falls die OCR-Extraktion einer einzelnen Datei fehlschlägt, nur dieser Job in failed — die anderen werden normal abgeschlossen.

Schritt 4: Verarbeiten Sie 100 Rechnungen in 5 Stapeln

from pathlib import Path
from myocr_client import MyOCRClient

client = MyOCRClient()
folder = Path("./invoices")
all_pdfs = sorted(folder.glob("*.pdf"))
CHUNK = 20

out_dir = Path("./out"); out_dir.mkdir(exist_ok=True)

for i in range(0, len(all_pdfs), CHUNK):
    chunk = all_pdfs[i:i + CHUNK]
    print(f"\nBatch {i // CHUNK + 1}: {len(chunk)} files")
    batch = client.batch([str(p) for p in chunk], model="invoice")
    for job in batch.wait_all(timeout=900):
        target = out_dir / f"{job.request_id}.xlsx"
        if job.is_done:
            job.download(str(target))
            print(f"  ✓ {target.name} ({job.pages_used} pages)")
        else:
            print(f"  ✗ {job.request_id}: {job.error_detail}")

print("\nDone.")

Gesamte Laufzeit mit einem Schlüssel des kostenlosen Tarifs bei Standard-Nebenläufigkeit: ungefähr 8–10 Minuten für 100 Rechnungen, dominiert von der OCR-Verarbeitungslatenz, nicht von Ihrem Code. Bei kostenpflichtigen Tarifen mit höherer Nebenläufigkeit wird dieselbe Arbeitslast in 3–5 Minuten abgeschlossen.

Schritt 5: Behandeln Sie Fehler wie ein Erwachsener

Das SDK ordnet jeden API-Fehlercode einer typisierten Ausnahme zu. Programmieren Sie defensiv:

from myocr_client import (
    MyOCRClient,
    QuotaExceeded,
    OcrEngineError,
    RateLimited,
    InvalidApiKey,
    FileTooLarge,
)

client = MyOCRClient()

try:
    result = client.convert("invoice.pdf", model="invoice")
except QuotaExceeded as e:
    print(f"Plan {e.current_plan}: {e.calls_used}/{e.calls_limit} calls used")
    print(f"Upgrade at {e.upgrade_url}, resets {e.reset_date}")
except FileTooLarge:
    print("Use create_job() instead of convert() — switch to async path")
except OcrEngineError:
    pass
except RateLimited:
    pass
except InvalidApiKey:
    raise SystemExit("Rotate your API key — current one is invalid")

Der automatische Wiederholungsversuch bei 429- und 5xx-Antworten (unter Beachtung von Retry-After) ist der häufigste ergonomische Vorteil gegenüber dem Schreiben von reinem requests-Code. Er erspart Ihnen den typischen Produktionsvorfall „Ich habe vergessen, ein instabiles Netzwerk zu behandeln".

Schritt 6: Wechseln Sie zu Webhooks (kein Polling)

Polling funktioniert, ist aber gesprächig. Wenn Sie über einen HTTP-Endpunkt verfügen, den Sie öffentlich bereitstellen können, ist die Webhook-Zustellung sauberer. Übergeben Sie webhook_url beim Erstellen von Jobs:

batch = client.batch(
    pdfs,
    model="invoice",
    webhook_url="https://my.app/webhooks/myocr",
)

Dann auf der Empfängerseite (Flask-Beispiel):

from flask import Flask, request
from myocr_client import verify_webhook_signature

app = Flask(__name__)
SECRET = "your-shared-webhook-secret"

@app.route("/webhooks/myocr", methods=["POST"])
def myocr_webhook():
    body = request.get_data()  # IMPORTANT: raw bytes, not request.get_json()
    sig = request.headers.get("X-MyOCR-Signature", "")
    if not verify_webhook_signature(body, sig, SECRET):
        return "invalid signature", 401

    event = request.get_json()
    request_id = event["data"]["request_id"]
    if event["event"] == "job.completed":
        ...
    elif event["event"] == "job.failed":
        ...
    return "", 200

Zwei nicht offensichtliche Dinge: (1) Verifizieren Sie die Signatur anhand der rohen Bytes — wenn Sie das geparste JSON wieder in eine Zeichenkette serialisieren, stimmt die Signatur wegen Leerzeichen und Schlüsselreihenfolge nicht überein; (2) Webhooks haben serverseitig eine automatische Wiederholungsrichtlinie (1m → 5m → 30m → 2h), machen Sie sich also keine Sorgen, falls Ihr Endpunkt kurzzeitig nicht erreichbar ist.

Schritt 7: Wählen Sie das richtige Modell für die Aufgabe

Das SDK stellt dieselben sechs vorgefertigten Modelle bereit, die die REST-API anbietet. Wählen Sie das spezifischste für Ihren Dokumenttyp:

Die Verwendung eines spezialisierten Modells ist der Unterschied zwischen einer unstrukturierten Tabelle, die nachbearbeitet werden muss, und Lieferant / Gesamtbetrag / Positionen, die bereits in typisierte Excel-Spalten geparst sind.

Schritt 8: Produktions-Checkliste

Bevor Sie dies in eine echte Arbeitslast überführen:

Wie es weitergeht

Die vollständige API-Referenz liegt in der Scalar-UI mit Copy-and-paste-Beispielen für jeden Endpunkt vor. Der SDK-Quellcode ist Open Source auf GitHub — lesen Sie die client.py, wenn Sie es erweitern möchten, oder eröffnen Sie ein Issue, wenn Sie auf eine fehlende Funktion stoßen.

Wenn Sie in ein SaaS integrieren, das OCR benötigt, ist das SDK auch der empfohlene Weg für unsere Zapier-, QuickBooks- und Xero-Integrationen (alle verwenden es intern).

Zusammenfassung auf einen Blick

# pip install myocr-client
import os
from myocr_client import MyOCRClient, QuotaExceeded

client = MyOCRClient()  # MYOCR_API_KEY env var

# Sync (≤5MB, ≤10 pages):
client.convert("doc.pdf", model="invoice").save("out.xlsx")

# Async + batch (≤20 files/call, ≤50MB each):
batch = client.batch(
    ["a.pdf", "b.pdf", "c.pdf"],
    model="invoice",
    webhook_url="https://my.app/webhooks/myocr",
)
for job in batch.wait_all(timeout=600):
    if job.is_done:
        job.download(f"out/{job.request_id}.xlsx")

Dasselbe in Node.js / TypeScript

Bevorzugen Sie JavaScript? Das offizielle Node-SDK myocr-client hat dieselbe Oberfläche, identische Methodennamen (camelCase), typisierte Ausnahmen und keine Laufzeitabhängigkeiten (Node 18+ verwendet natives fetch / FormData / crypto).

// npm install myocr-client
import { MyOCRClient } from 'myocr-client';

const client = new MyOCRClient();  // MYOCR_API_KEY from env

// Sync:
const r = await client.convert('invoice.pdf', { model: 'invoice' });
await r.save('invoice.xlsx');

// Async + batch:
const batch = await client.batch(['a.pdf', 'b.pdf', 'c.pdf'], { model: 'invoice' });
const done = await batch.waitAll({ timeoutMs: 600_000 });
for (const job of done) {
  if (job.isDone) await job.download(`out/${job.requestId}.xlsx`);
}

Dieselbe API im Hintergrund, dieselben Fehlercodes (zugeordnet zu TS-Ausnahmeklassen), dieselbe Webhook-Zustellung und Signaturverifizierung. Wählen Sie die Sprache, die zu Ihrem Stack passt.

Probieren Sie es noch heute aus: Holen Sie sich einen kostenlosen API-Schlüssel unter myocr.app/account/api (keine Kreditkarte), pip install myocr-client (oder npm install myocr-client) und verarbeiten Sie Ihren ersten Stapel in 5 Minuten.

Holen Sie sich API-Schlüssel und SDK in 30 Sekunden

Kostenloser Tarif: 100 Umwandlungen pro Monat, alle 6 vorgefertigten Modelle, keine Kreditkarte. pip install myocr-client und bringen Sie OCR noch heute Nachmittag live.

API-Schlüssel erhalten (kostenlos)