Home Blog Come convertire 100 fatture in 10 minuti con Python (tutorial SDK myocr) 2026-05-26 11 min lettura Come convertire 100 fatture in 10 minuti con Python (tutorial SDK myocr) Da zero a una pipeline batch funzionante con l'SDK ufficiale myocr-client. Codice reale, gestione errori reale, consegna via webhook. Di team myocr.app 100 fatture PDF → 100 file Excel strutturati in meno di 10 minuti con 30 righe di Python Perché un SDK Python dedicato fa la differenza Se devi mettere in produzione OCR in Python hai tre strade. Puoi chiamare l'API con requests grezzi e scrivere tu il boilerplate — autenticazione, retry, mappatura degli errori, polling per job asincroni, download da signed URL. Puoi usare un generatore OpenAPI che produce un client funzionante ma poco ergonomico. Oppure installi un SDK mantenuto che astrae il protocollo e ti lascia scrivere solo codice di business. Questo tutorial usa la terza via: myocr-client, l'SDK Python ufficiale di myocr.app. In dieci minuti passerai da pip install a uno script che converte 100 fatture PDF in parallelo, gestisce in modo pulito quota esaurita ed errori OCR, e notifica la tua applicazione via webhook al completamento di ogni job. Cosa costruirai Un singolo script Python che: Legge una cartella di fatture PDF (miste digitali e scansionate) Le invia come job asincroni via /v1/batch Fa polling o riceve notifiche webhook quando ogni job finisce Scarica file Excel strutturati (Fornitore, Cliente, Righe, Totale, IVA) Si riprende da quota esaurita, blip di rete ed errori OCR per-file senza crashare Totale: circa 30 righe di codice di business, più un ricevitore di webhook se vuoi delivery push. Prerequisiti Python 3.8+ Una API key da myocr.app/account/api (tier gratuito: 100 chiamate al mese, senza carta) Una cartella di fatture PDF di test — o usa le fixture di esempio nel repo dell'SDK Passo 1: installa pip install myocr-client Tutto qui. L'SDK dipende solo da requests. Niente estensioni native, niente runtime specifico. Passo 2: converti la prima fattura (sync) from myocr_client import MyOCRClient client = MyOCRClient(api_key="sk_live_...") # oppure setta MYOCR_API_KEY in env result = client.convert("fattura.pdf", model="invoice") result.save("fattura.xlsx") print(f"{result.pages_used} pagine → fattura.xlsx ({result.request_id})") Questa è una chiamata OCR completa. Il metodo convert() è sincrono e ideale per file sotto 5 MB e 10 pagine. Il ConversionResult restituito contiene content (bytes), pages_used, il model originale e un request_id con cui correlare i log lato server. Passo 3: passa ad async per il batch processing Per 100 fatture non vuoi 100 chiamate sync sequenziali — è latenza seriale. Usa /v1/batch. L'SDK lo espone come client.batch(): from pathlib import Path from myocr_client import MyOCRClient client = MyOCRClient() # MYOCR_API_KEY da env folder = Path("./fatture") pdfs = sorted(folder.glob("*.pdf"))[:20] # /v1/batch accetta max 20 file batch = client.batch([str(p) for p in pdfs], model="invoice") print(f"Creati {batch.jobs_created} job, {len(batch.errors)} errori") 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"Fallito: {job.request_id} — {job.error_detail}") Tre cose da notare. Primo, l'endpoint /v1/batch accetta al massimo 20 file per chiamata — per 100 fatture, dividi la cartella in 5 batch. Secondo, wait_all() fa polling per ogni job con backoff esponenziale (1s → 2s → 4s → 8s → 15s cap), così 100 sleep(1) non saturano il tuo rate limit. Terzo, se un singolo file fallisce l'estrazione OCR, solo quel Job finisce in failed — gli altri completano normalmente. Passo 4: processa 100 fatture in 5 chunk from pathlib import Path from myocr_client import MyOCRClient client = MyOCRClient() folder = Path("./fatture") 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)} file") 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} pagine)") else: print(f" ✗ {job.request_id}: {job.error_detail}") print("\nFatto.") Tempo totale su una chiave del tier gratuito con concorrenza default: circa 8-10 minuti per 100 fatture, dominato dalla latenza OCR, non dal tuo codice. Sui piani a pagamento con maggior concorrenza, lo stesso carico finisce in 3-5 minuti. Passo 5: gestione errori da adulto L'SDK mappa ogni codice di errore dell'API in un'eccezione tipata. Codifica in modo difensivo: from myocr_client import ( MyOCRClient, QuotaExceeded, OcrEngineError, RateLimited, InvalidApiKey, FileTooLarge, ) client = MyOCRClient() try: result = client.convert("fattura.pdf", model="invoice") except QuotaExceeded as e: print(f"Piano {e.current_plan}: {e.calls_used}/{e.calls_limit} chiamate usate") print(f"Upgrade su {e.upgrade_url}, reset {e.reset_date}") except FileTooLarge: print("Usa create_job() invece di convert() — passa al path async") except OcrEngineError: pass # motore OCR a monte fallito, sicuro ritentare dopo 30s except RateLimited: pass # raro: l'SDK ritenta 429 in automatico fino a 3 volte except InvalidApiKey: raise SystemExit("Ruota la API key — quella corrente non è valida") Il retry automatico su 429 e 5xx (rispettando Retry-After) è la vittoria ergonomica più comune rispetto a scrivere codice requests grezzo. Ti risparmia il classico incidente in produzione "ho dimenticato di gestire la rete instabile". Passo 6: passa ai webhook (zero polling) Il polling funziona ma è chiacchierone. Se hai un endpoint HTTP esponibile pubblicamente, la delivery via webhook è più pulita. Passa webhook_url alla creazione dei job: batch = client.batch( pdfs, model="invoice", webhook_url="https://miaapp.com/webhooks/myocr", ) # Niente attesa — il tuo endpoint riceverà un POST per ogni job Sul lato ricevente (esempio Flask): from flask import Flask, request from myocr_client import verify_webhook_signature app = Flask(__name__) SECRET = "il-tuo-secret-condiviso" @app.route("/webhooks/myocr", methods=["POST"]) def myocr_webhook(): body = request.get_data() # IMPORTANTE: byte grezzi, non request.get_json() sig = request.headers.get("X-MyOCR-Signature", "") if not verify_webhook_signature(body, sig, SECRET): return "firma non valida", 401 event = request.get_json() request_id = event["data"]["request_id"] if event["event"] == "job.completed": ... # scarica result_url, aggiorna DB, notifica utente elif event["event"] == "job.failed": ... # logga error_detail, retry o alerta ops return "", 200 Due cose non ovvie: (1) verifica la firma sui byte grezzi — se ri-serializzi il JSON parsato, la firma non corrisponderà per via di whitespace e ordine delle chiavi; (2) i webhook hanno retry policy automatica lato server (1m → 5m → 30m → 2h), quindi non preoccuparti se il tuo endpoint è giù brevemente. Passo 7: scegli il modello giusto L'SDK espone gli stessi sei modelli prebuilt dell'API REST. Scegli il più specifico per il tipo di documento: invoice — fatture fornitore, righe, totali, IVA. Quello usato in questo tutorial. receipt — scontrini POS, esercente, items, totale. Ottimo per note spese. bank_statement — transazioni, date, debito/credito, saldo progressivo. business_card — contatti, azienda, telefoni, email, indirizzi. tables — estrazione tabelle generica per documenti senza modello specializzato. text — OCR testo semplice, senza struttura. Usare un modello specializzato è la differenza fra ottenere una tabella destrutturata da ripulire e ottenere Fornitore / Totale / Righe articoli già parsati in colonne Excel tipizzate. Passo 8: checklist produzione Prima di portare questo in un carico reale: Usa chiavi sk_test_* in dev — sono rate-limited ma non consumano la tua quota fatturabile Setta MYOCR_API_KEY via env var, mai hardcoded — l'SDK la legge in automatico Configura il tuo secret manager per il webhook signing secret su entrambi i lati (server myocr e tuo ricevitore) Logga request_id di ogni chiamata così puoi correlare con i log lato server se apri un ticket Imposta un timeout sensato su Job.wait() — il default 600s va bene per le fatture, alzalo per estratti conto con 50+ pagine Monitora QuotaExceeded nel tuo error tracker — è il segnale per fare upgrade del piano prima che blocchi Dove andare ora La reference completa dell'API è in Scalar UI con esempi copy-paste per ogni endpoint. Il codice sorgente dell'SDK è open source su GitHub — leggi client.py se vuoi estenderlo, oppure apri una issue se trovi una feature mancante. Se stai integrando in un SaaS che ha bisogno di OCR, l'SDK è anche il path raccomandato per le nostre integrazioni Zapier, QuickBooks e Xero (tutte lo usano internamente). Riepilogo in una schermata # pip install myocr-client import os from myocr_client import MyOCRClient, QuotaExceeded client = MyOCRClient() # MYOCR_API_KEY env var # Sync (≤5MB, ≤10 pagine): client.convert("doc.pdf", model="invoice").save("out.xlsx") # Async + batch (≤20 file/chiamata, ≤50MB ciascuno): batch = client.batch( ["a.pdf", "b.pdf", "c.pdf"], model="invoice", webhook_url="https://miaapp.com/webhooks/myocr", ) for job in batch.wait_all(timeout=600): if job.is_done: job.download(f"out/{job.request_id}.xlsx") Stesso pattern in Node.js / TypeScript Preferisci JavaScript? L'SDK Node myocr-client ha la stessa superficie, stessi nomi metodi (camelCase), eccezioni tipate, zero dipendenze runtime (Node 18+ usa fetch / FormData / crypto nativi). // npm install myocr-client import { MyOCRClient } from 'myocr-client'; const client = new MyOCRClient(); // MYOCR_API_KEY da env // Sync: const r = await client.convert('fattura.pdf', { model: 'invoice' }); await r.save('fattura.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`); } Stessa API dietro le quinte, stessi codici errore (mappati a classi TS), stessa delivery webhook e verifica firma. Scegli il linguaggio del tuo stack. Provalo oggi: ottieni una API key gratuita su myocr.app/account/api (senza carta), pip install myocr-client (o npm install myocr-client) e processa il tuo primo batch in 5 minuti. Ottieni API key e SDK in 30 secondi Tier gratuito: 100 conversioni al mese, tutti e 6 i modelli prebuilt, senza carta. pip install myocr-client e metti OCR in produzione oggi pomeriggio. Ottieni API key (gratis)