SDK Python per la conversione file#
enconvert è il client Python ufficiale per l'API EnConvert: un solo pip install, una sola chiave API e metodi tipizzati per convertire file e per leggere il web live. Gira su Python 3.9 o successivo con un'unica dipendenza runtime, requests, e include type hint inline più un marcatore py.typed, così mypy e Pyright vedono tutto. Il client ha due superfici. Nove metodi di conversione coprono 43 coppie {input}-to-{output} più URL in PDF, screenshot e Markdown, supportati da tre helper di polling dello stato. Il namespace client.v2 aggiunge la web intelligence: perceive, discover, lookup, distill, ingest e watch.
enconvert · Sorgente: conversionapi/python-sdk · Python: 3.9+ · Dipendenza runtime: requests>=2.28 · Licenza: MIT
Installazione#
pip install enconvert
uv add enconvert e poetry add enconvert funzionano allo stesso modo. requests è l'unica dipendenza runtime, e gli stub di tipo viaggiano dentro la wheel, quindi non c'è nessun pacchetto types- da inseguire.
Guida rapida#
Leggi una pagina come dovrebbe farlo il tuo agente, con un punteggio di qualità allegato, poi converti un file locale con lo stesso client.
import os
from enconvert import Enconvert
client = Enconvert(api_key=os.environ["ENCONVERT_API_KEY"])
op = client.v2.perceive("https://example.com", outputs=["markdown", "structured"])
print(op.outputs["markdown"].url, op.render_quality)
print(client.convert_to_pdf("report.docx", save_to="report.pdf").presigned_url)
Ogni metodo è sincrono e bloccante. L'SDK è solo lato server: si autentica con una chiave API privata, quindi non distribuirlo mai dentro un client desktop, mobile o browser. Prendi una chiave dalla tua dashboard e consulta Autenticazione per capire come sono definiti gli ambiti delle chiavi.
Cosa espone il client#
Enconvert è tutta la superficie pubblica. I metodi di conversione pendono direttamente dal client; tutto ciò che riguarda il web vive sotto client.v2.
| Metodo di conversione | Endpoint | Restituisce |
|---|---|---|
convert_url_to_pdf(url, ...) |
POST /v1/convert/url-to-pdf |
ConversionResult |
convert_url_to_screenshot(url, ...) |
POST /v1/convert/url-to-screenshot |
ConversionResult |
convert_url_to_markdown(url, ...) |
POST /v1/convert/url-to-markdown |
ConversionResult |
convert_image(file, output_format=...) |
POST /v1/convert/{input}-to-{output} |
ConversionResult |
convert_document(file, ...) |
POST /v1/convert/{input}-to-{output} |
ConversionResult |
convert_to_markdown(file, ...) |
POST /v1/convert/anything-to-markdown |
ConversionResult |
convert_to_pdf(file, ...) |
POST /v1/convert/anything-to-pdf |
ConversionResult |
convert_website_to_pdf(url, ...) |
POST /v1/convert/website-to-pdf |
BatchSubmission |
convert_website_to_screenshot(url, ...) |
POST /v1/convert/website-to-screenshot |
BatchSubmission |
get_job_status(job_id) |
GET /v1/convert/status/{job_id} |
JobStatus |
get_batch_status(batch_id) |
GET /v1/convert/batch/{batch_id} |
BatchStatus |
wait_for_batch(batch_id, ...) |
GET /v1/convert/batch/{batch_id} (con polling) |
BatchStatus |
Capacità di client.v2 |
Metodi | Restituisce |
|---|---|---|
| Perceive | perceive, perceive_direct, get_perceive_operation, download_perceive_artifact, perceive_batch, get_perceive_batch |
PerceiveResult, PerceiveDirectResult, PerceiveBatchResult |
| Discover, Lookup, Distill | discover, lookup, distill |
DiscoverResult, LookupResult, DistillResult |
| Ingest | ingest, ingest_files, list_ingest_jobs, get_ingest_job, cancel_ingest_job, retry_ingest_webhook, get_webhook_secret, rotate_webhook_secret |
IngestJob, IngestJobList, WebhookSecret, WebhookRetryResult |
| Watch | create_watcher, list_watchers, get_watcher, get_watcher_snapshots, update_watcher, delete_watcher |
Watcher, WatcherList, WatcherSnapshotList |
Ogni argomento dopo il primo posizionale è solo per parola chiave, in snake_case e facoltativo, se non indicato diversamente in una tabella. I risultati sono dataclass congelate, quindi costruisci una nuova istanza invece di mutarne una. Le forme REST sono nella panoramica degli endpoint.
Conversione file#
Ogni metodo di conversione accetta save_to (uno str o un os.PathLike; il risultato viene scritto lì in streaming e le directory superiori vengono create) e output_filename (per sovrascrivere il nome generato). Entrambi sono omessi dalle tabelle qui sotto.
convert_url_to_pdf#
Esegue il rendering in PDF di qualsiasi URL raggiungibile.
result = client.convert_url_to_pdf(
"https://example.com", single_page=False, viewport_width=1440, save_to="report.pdf"
)
print(result.presigned_url, result.file_size)
| Opzione | Tipo | Default | Descrizione |
|---|---|---|---|
single_page |
bool |
True |
True produce una sola pagina continua. False impagina usando pdf_options.page_size. |
pdf_options |
PdfOptions |
-- | Dimensione pagina, orientamento, margini, scala, scala di grigi, intestazione, piè di pagina. Vedi Opzioni PDF. |
viewport_width / viewport_height |
int |
1920 / 1080 |
Dimensione del viewport del browser in pixel. |
load_media ed enable_scroll valgono entrambi True per impostazione predefinita: il primo attende immagini e video, il secondo scorre dall'alto in basso così i lazy loader scattano. Altre tre opzioni raggiungono pagine dietro un accesso protetto: auth (HttpBasicAuth), cookies (list[BrowserCookie]) e headers (dict[str, str]).
auth con un header Authorization. L'API rifiuta il conflitto invece di indovinare quale credenziale debba prevalere. Scegline una.
convert_url_to_screenshot#
Cattura un PNG di qualsiasi URL.
client.convert_url_to_screenshot("https://example.com", viewport_width=1440, save_to="shot.png")
Accetta le stesse opzioni di viewport, media, scroll, nome file e accesso al browser di convert_url_to_pdf, esclusi single_page e pdf_options.
convert_url_to_markdown#
Estrae Markdown GitHub-Flavored pulito da un URL. Navigazione, piè di pagina, pubblicità e script vengono rimossi, il corpo principale dell'articolo viene mantenuto e viene anteposto un frontmatter YAML con titolo, descrizione, url, link e immagini.
client.convert_url_to_markdown("https://example.com/article", save_to="article.md")
Stesso insieme di opzioni di convert_url_to_screenshot. Quando sulla stessa lettura vuoi anche un punteggio di qualità, i metadati della pagina o l'estrazione strutturata, usa invece v2.perceive.
convert_image#
Converte tra jpeg, png, svg, heic e webp, oppure rasterizza un PDF in JPEG. Il formato di input viene ricavato dall'estensione del nome file.
client.convert_image("photo.heic", output_format="webp", save_to="photo.webp")
client.convert_image("scan.pdf", output_format="jpeg", save_to="scan.jpeg")
output_format è obbligatorio e deve essere uno tra jpeg, png, svg, heic o webp; gli alias jpg, yml, htm e md vengono normalizzati per te. file accetta una stringa di percorso, un os.PathLike, bytes grezzi o un wrapper FileData(data, filename). I bytes grezzi non portano alcun nome file e vengono caricati come upload.bin, quindi preferisci FileData ogni volta che l'estensione conta.
from pathlib import Path
from enconvert import FileData
blob = FileData(data=Path("photo.heic").read_bytes(), filename="photo.heic")
client.convert_image(blob, output_format="webp", save_to="photo.webp")
convert_document#
Converte documenti e formati dati. output_format vale "pdf" per impostazione predefinita, e pdf_options viene rispettato quando l'output è un PDF.
from enconvert import PdfMargins, PdfOptions
client.convert_document("report.docx", save_to="report.pdf")
client.convert_document("data.json", output_format="yaml", save_to="data.yaml")
client.convert_document(
"README.md", pdf_options=PdfOptions(page_size="A4", margins=PdfMargins(top=20)), save_to="r.pdf"
)
Input supportati: .doc, .docx, .xls, .xlsx, .ppt, .pptx, .html, .htm, .odt, .ods, .odp, .ots, .pages, .numbers, .md, .markdown, .csv, .json, .xml, .yaml, .yml, .toml.
EPUB non ha una coppia documenti dedicata. Passa i .epub attraverso convert_to_pdf o convert_to_markdown.
convert_to_markdown#
Rileva automaticamente lato server un documento caricato e restituisce Markdown pulito. È il mattone di base per l'ingestione RAG di un singolo file.
client.convert_to_markdown("handbook.docx", save_to="handbook.md")
Input accettati: PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT e MD, più i formati office legacy e ODF. Le immagini non sono supportate qui, e l'endpoint non accetta opzioni PDF. Per un sito intero invece che per un singolo file, usa v2.ingest.
convert_to_pdf#
Rileva automaticamente lato server un file caricato e restituisce un PDF.
from enconvert import PdfOptions
client.convert_to_pdf("slides.pptx", save_to="slides.pdf")
client.convert_to_pdf("scan.pdf", pdf_options=PdfOptions(grayscale=True), save_to="gray.pdf")
Input accettati: office, ODF, Pages, Numbers, RTF, CSV, HTML, Markdown, testo semplice, immagini raster, SVG, EPUB e un PDF esistente in passthrough. Dato che un input .pdf viene restituito così com'è, questo metodo funziona anche come normalizzatore in scala di grigi.
pdf_options.grayscale. Gli altri campi di geometria della pagina vengono ignorati qui. Quando ti serve una vera impostazione di pagina, fai passare il file attraverso convert_document o convert_url_to_pdf.
convert_website_to_pdf e convert_website_to_screenshot#
Individua ogni pagina di un sito, converte ciascuna in background e raccoglie tutto in un unico ZIP. Entrambi sono asincroni per progetto e restituiscono subito un BatchSubmission.
batch = client.convert_website_to_pdf(
"https://example.com", crawl_mode="sitemap", exclude_patterns=["/blog/tag/"]
)
print(batch.batch_id, batch.url_count, batch.discovery_method)
status = client.wait_for_batch(batch.batch_id, save_to="site.zip")
print(status.completed, "of", status.total, "pages converted")
for item in client.get_batch_status(batch.batch_id).items:
print(item.source_url, item.status, item.download_url)
| Opzione | Tipo | Default | Descrizione |
|---|---|---|---|
crawl_mode |
"auto" \| "sitemap" \| "full" |
default del server | sitemap legge solo sitemap.xml. full aggiunge un crawl in ampiezza. auto sceglie la modalità più alta disponibile per la chiave. |
include_patterns / exclude_patterns |
list[str] |
-- | Mantiene o scarta URL in base a un frammento di percorso. Le esclusioni valgono solo in modalità full crawl. |
notification_email / callback_url |
str |
-- | Indirizzo da avvisare via email, e webhook da chiamare, quando il batch finisce. |
single_page |
bool |
default del server | Solo PDF. |
pdf_options |
PdfOptions |
-- | Solo PDF. Vedi Opzioni PDF. |
Anche le opzioni di rendering per singola pagina si applicano a ogni URL individuato: viewport_width, viewport_height, load_media, enable_scroll, auth, cookies e headers. Tutto ciò che lasci non impostato mantiene il valore predefinito del gateway.
wait_for_batch accetta interval_seconds (default 5.0), timeout_seconds (default 1800.0) e save_to. Solleva APIError(504, ...) se il batch è ancora in elaborazione quando la scadenza viene superata.
Coppie di conversione supportate#
L'SDK porta con sé una copia della mappa di conversione del gateway e rifiuta in locale una coppia non implementata, prima di qualsiasi round-trip di rete, indicando nel messaggio gli output validi per quell'input.
| Input | Output |
|---|---|
json |
csv, toml, xml, yaml |
xml |
csv, json |
yaml, toml |
json |
csv |
json, xml |
markdown |
html, pdf |
html |
pdf |
doc, excel, ppt, odt, ods, odp, ots, pages, numbers |
pdf |
jpeg, png, svg, heic, webp |
l'uno verso l'altro, tutte e 20 le coppie |
pdf |
jpeg |
In totale fanno 43 coppie implementate. Controllale a livello di codice:
from enconvert import IMPLEMENTED_CONVERSIONS, valid_outputs_for
valid_outputs_for("json") # ['csv', 'toml', 'xml', 'yaml']
"heic-to-webp" in IMPLEMENTED_CONVERSIONS # True
Il riferimento completo dei parametri vive in Parametri e opzioni.
Web intelligence (V2)#
Ogni lettura V2 porta con sé render_quality, un float da 0.0 a 1.0 che dice quanto onestamente si è renderizzata la pagina. Una schermata di sfida, un muro dei cookie, un accesso protetto da login, una pagina di errore HTTP o uno shell SPA vuoto tornano con un punteggio basso, una mappa deductions che nomina cosa è scattato e un elenco warnings. Il contenuto viene comunque restituito, solo segnalato, così una lettura sbagliata non entra mai di nascosto nel contesto del tuo agente. Tratta il punteggio come un filtro e controllalo prima di usare il testo. PerceiveResult, PerceiveDirectResult, DistillItem, LookupItem.perceive e WatcherSnapshot lo espongono tutti. I concetti sono nella panoramica V2.
Perceive#
Esegue il rendering di un URL in artefatti pronti per gli agenti. È sincrono: la chiamata restituisce l'operazione completata con gli URL firmati degli artefatti.
op = client.v2.perceive(
"https://example.com",
outputs=["markdown", "screenshot", "structured"],
extract=["tables", "metadata"],
only_main_content=True,
)
print(op.render_quality) # da 0.0 a 1.0
print(op.status_code) # stato HTTP della pagina stessa
print(op.deductions) # ad es. {"login_wall": 0.65}
print(op.outputs["markdown"].url) # URL firmato, 15 minuti
print(op.structured)
if (op.render_quality or 0) < 0.6:
print("Low-confidence read:", op.warnings)
| Opzione | Tipo | Default | Descrizione |
|---|---|---|---|
outputs |
list[str] |
["markdown", "structured"] |
Uno o più tra markdown, html_cleaned, html_raw, screenshot, screenshot_full_page, pdf, links, images, structured. |
extract |
list[str] |
-- | Uno o più tra tables, prices, contacts, metadata, main_content, headings, structured_data, technologies, all. |
wait_for |
str |
-- | Selettore CSS da attendere prima della cattura. |
viewport |
PerceiveViewport |
1920 x 1080 | width da 320 a 3840, height da 240 a 2160. |
cache_mode |
"enabled" \| "bypass" \| "refresh" |
default del server | Riusa, salta o riscrive il render in cache. |
block_resources |
list[str] |
-- | Uno o più tra image, media, font, stylesheet, script, xhr, fetch, websocket, manifest, other. |
only_main_content |
bool |
default del server | Rimuove navigazione, header, footer e altri elementi di contorno della pagina dal contenuto estratto. |
direct_download |
bool |
default del server | Restituisce i byte grezzi invece di un URL firmato. Non impostata per impostazione predefinita, quindi la chiave viene omessa dalla richiesta e vale il default del server (false). Accettata solo da perceive; l'endpoint batch la rifiuta. |
Sono accettati anche: schema (dict, uno schema di estrazione libero passato invariato), js_code (str, eseguito nella pagina prima della cattura), wait_timeout_ms (int), headers (dict[str, str]), cookies (list[BrowserCookie]), auth (HttpBasicAuth), proxy_url (str), geolocation (dict), action_chain (list[dict] di passaggi scriptati di click, digitazione e scroll), pdf_options (PdfOptions, applicato all'output pdf), mobile (bool) e respect_robots (bool). perceive_batch accetta esattamente lo stesso insieme a parte direct_download.
Gli URL degli artefatti vengono rifirmati a ogni lettura, quindi chiama client.v2.get_perceive_operation(op.operation_id) per averne uno fresco invece di mettere in cache la stringa.
Byte grezzi, senza giro di andata e ritorno sull'URL firmato. perceive_direct forza direct_download a on e ti consegna l'artefatto stesso, con i metadati letti dagli header della risposta.
direct = client.v2.perceive_direct("https://example.com", outputs=["markdown"])
print(direct.filename, direct.content_type, len(direct.content), direct.render_quality)
raw = client.v2.download_perceive_artifact(op.operation_id, output="markdown")
perceive_direct richiede esattamente un output che produca un artefatto tra markdown, html_cleaned, html_raw, screenshot, screenshot_full_page, pdf, links e images. structured può viaggiare insieme ma resta inline lato server; passa qualsiasi altra cosa e l'SDK solleva EnconvertError prima di inviare la richiesta. Su download_perceive_artifact, output si può omettere quando l'operazione ha prodotto esattamente un artefatto, e un artefatto oltre la sua finestra di conservazione risponde 410.
Batch. Fino a 1000 URL condividono un unico blocco di opzioni. I batch piccoli si completano inline; quelli più grandi tornano con stato "queued", quindi interroga l'id del job.
batch = client.v2.perceive_batch(
["https://a.example.com", "https://b.example.com"], outputs=["markdown"], output_mode="zip"
)
done = client.v2.get_perceive_batch(batch.job_id)
print(done.status, done.completed, done.failed, done.pending)
for item in done.items:
print(item.url, item.render_quality)
output_mode è "manifest" (predefinito) o "zip"; quando è "zip", l'archivio finito si trova su done.zip.url. I dettagli sono in Perceive.
Discover#
Elenca gli URL di un sito senza alcun rendering del browser, il che ne fa il primo passo economico prima di percepire qualsiasi cosa.
found = client.v2.discover(
"https://example.com", mode="hybrid", max_urls=200, exclude_patterns=["/tag/"]
)
print(found.total, found.truncated, found.sources)
| Opzione | Tipo | Default | Descrizione |
|---|---|---|---|
mode |
"sitemap" \| "crawl" \| "hybrid" |
default del server | Analisi della sitemap, un crawl HTTP, o entrambi uniti e deduplicati. |
max_urls / max_depth |
int |
default del server | Limite sugli URL restituiti (truncated è True quando ce n'erano di più) e profondità del crawl dall'URL di partenza. |
same_domain_only |
bool |
default del server | Resta sull'host di partenza. |
respect_robots |
bool |
default del server | Rispetta robots.txt. |
include_patterns ed exclude_patterns (entrambi list[str]) filtrano l'insieme dei risultati. DiscoverResult.sources contiene i conteggi grezzi per sorgente prima della deduplicazione, ad esempio {"sitemap": 42, "crawl": 30}. Altro in Discover.
Lookup#
Esegue una ricerca web categorizzata, con la possibilità di renderizzare i primi risultati nella stessa chiamata.
search = client.v2.lookup(
"best static site generators", category="web", num_results=10, perceive_top=3
)
for hit in search.results:
quality = hit.perceive.render_quality if hit.perceive else None
print(hit.position, hit.title, hit.url, quality)
| Opzione | Tipo | Default | Descrizione |
|---|---|---|---|
category |
"web" \| "news" \| "images" \| "scholar" \| "patents" \| "maps" |
default del server | Verticale di ricerca. |
time_filter |
"hour" \| "day" \| "week" \| "month" \| "year" |
-- | Finestra temporale di recency. |
num_results / page |
int |
default del server | Risultati per pagina, e numero di pagina a base 1. |
perceive_top |
int |
0 |
Esegue il rendering automatico dei primi N URL dei risultati. Ognuno arriva con il suo PerceiveResult completo su hit.perceive. |
Sono accettati anche: country (str), locale (str), location (str) per query sensibili alla geolocalizzazione e autocorrect (bool). LookupResult porta con sé answer_box, knowledge_graph, perceive_operation_ids e perceive_top, dove quest'ultimo riporta quanti risultati sono stati effettivamente renderizzati, che possono essere meno di quanti ne avevi chiesti. Riferimento in Lookup.
Distill#
Estrazione strutturata guidata da uno schema su una o più pagine. Fornisci esattamente uno tra urls e discover_from; schema è sempre obbligatorio. Entrambe le regole vengono applicate lato client e sollevano EnconvertError prima che parta una richiesta.
from enconvert import CssField, CssSchema
extraction = client.v2.distill(
urls=["https://example.com/pricing"],
schema={"plans": "list of plan names with monthly prices"},
css_schema=CssSchema(
base_selector=".plan-card",
fields=[
CssField(name="name", type="text", selector="h3"),
CssField(name="price", type="text", selector=".price"),
],
target_field="plans",
),
)
for item in extraction.results:
print(item.url, item.extraction_tier, item.fields_from_css, item.fields_from_llm, item.data)
Il css_schema facoltativo gira per primo e risponde a tutto ciò che i selettori riescono a raggiungere. Solo i campi che mancano vengono escalati al tier del modello linguistico, ed extraction_tier su ciascun elemento riporta quale percorso è stato usato: css, llm, mixed o none.
Scoprire e distillare in un'unica chiamata:
from enconvert import DistillDiscoverFrom
client.v2.distill(
discover_from=DistillDiscoverFrom(url="https://example.com", mode="sitemap", max_pages=10),
schema={"title": "page title"},
)
| Opzione | Tipo | Default | Descrizione |
|---|---|---|---|
schema |
dict |
-- (obbligatorio) | La forma di output che vuoi indietro, passata invariata. |
urls |
list[str] |
-- | Elenco esplicito di pagine. Mutuamente esclusivo con discover_from. |
discover_from |
DistillDiscoverFrom |
-- | url, mode facoltativo, max_pages facoltativo (da 1 a 50, default 10). |
css_schema |
CssSchema |
-- | Passaggio sui selettori eseguito prima di qualsiasi chiamata al modello. |
Sono accettati anche: wait_for (str), wait_timeout_ms (int), headers (dict[str, str]), cookies (list[BrowserCookie]) e respect_robots (bool). CssField supporta i tipi text, attribute, html, regex, nested, list e nested_list, con attribute, pattern, default, transform (lowercase, uppercase, strip) facoltativi e fields annidati fino a cinque livelli di profondità. Vedi Distill.
Ingest#
Trasforma un sito intero, un elenco esplicito di URL o una pila di documenti caricati in JSONL suddiviso in chunk e pronto per RAG. Ingest è sempre asincrono.
import time
from enconvert import IngestChunkOptions
job = client.v2.ingest(
mode="sitemap",
url="https://docs.example.com",
max_pages=100,
chunk=IngestChunkOptions(max_words=512, sentence_overlap=1),
webhook_url="https://my.app/hooks/enconvert",
)
status = client.v2.get_ingest_job(job.job_id)
while status.status in ("queued", "discovering", "processing"):
time.sleep(10)
status = client.v2.get_ingest_job(job.job_id)
print(status.status, status.pages_processed, status.total_chunks, status.output_url)
I file caricati percorrono lo stesso ciclo di vita del job sotto la modalità files. Sono accettati PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT e MD, più i formati office legacy e ODF, e ogni voce può essere un percorso, un os.PathLike, bytes grezzi o un FileData.
file_job = client.v2.ingest_files(["handbook.pdf", "notes.docx"])
| Opzione | Tipo | Default | Descrizione |
|---|---|---|---|
mode |
"urls" \| "sitemap" \| "crawl" \| "files" |
"urls" |
urls richiede un elenco urls non vuoto e rifiuta url. Ogni altra modalità richiede un url di partenza e rifiuta urls. |
url / urls |
str / list[str] |
-- | URL di partenza per sitemap e crawl, oppure l'elenco esplicito di pagine per la modalità urls. |
max_pages |
int |
default del server | Limite alle pagine ingerite. |
chunk |
IngestChunkOptions |
-- | max_words da 32 a 4000, default 512. sentence_overlap da 0 a 10, default 1. Abbinalo a webhook_url (str), chiamato quando il job raggiunge uno stato terminale. |
Sono accettate anche le opzioni di modellazione del crawl e di rendering: max_depth, same_domain_only, include_patterns, exclude_patterns, respect_robots, wait_for e wait_timeout_ms. ingest_files accetta solo chunk e webhook_url.
for summary in client.v2.list_ingest_jobs(limit=20).jobs:
print(summary.job_id, summary.status, summary.total_chunks)
client.v2.cancel_ingest_job(job.job_id)
client.v2.retry_ingest_webhook(job.job_id)
secret = client.v2.get_webhook_secret()
print(secret.signature_header, secret.signature_scheme, secret.replay_tolerance_seconds)
client.v2.rotate_webhook_secret()
cancel_ingest_job è idempotente; annullare un job già in stato terminale lo restituisce invariato. retry_ingest_webhook risponde 409 quando il job non è completato e 400 quando non era configurato alcun webhook. rotate_webhook_secret invalida immediatamente il segreto precedente. Approfondimento in Ingest.
Watch#
Riesegue il rendering di un URL a cadenza fissa e ti avvisa quando cambia.
watcher = client.v2.create_watcher(
"https://example.com/pricing",
frequency_minutes=60,
diff_mode="auto",
webhook_url="https://my.app/hooks/changes",
notify_email=True,
)
for snap in client.v2.get_watcher_snapshots(watcher.watcher_id, limit=10).snapshots:
print(snap.checked_at, snap.has_changes, snap.similarity, snap.change_count)
client.v2.list_watchers(limit=20)
client.v2.update_watcher(watcher.watcher_id, status="paused")
client.v2.update_watcher(watcher.watcher_id, webhook_url="")
client.v2.delete_watcher(watcher.watcher_id)
| Opzione | Tipo | Default | Descrizione |
|---|---|---|---|
frequency_minutes |
int |
default del server | Intervallo tra i controlli. Il limite minimo è di un'ora. |
diff_mode |
"auto" \| "text" \| "structured" \| "tables" \| "metadata" |
default del server | Quale livello della pagina confronta il motore di diff. |
track_fields |
dict |
-- | Campi con nome da tracciare, passati invariati. |
webhook_url |
str |
-- | Chiamato a ogni cambiamento rilevato. |
notify_email |
bool |
default del server | Invia le notifiche di cambiamento via email. |
update_watcher richiede almeno un campo e altrimenti solleva EnconvertError; status accetta "active" o "paused", e un webhook_url vuoto azzera il webhook. delete_watcher è una eliminazione soft e idempotente che restituisce il watcher marcato come eliminato con stato "deleted", dopodiché il watcher risulta 404.
WatcherSnapshot.changes arrivano direttamente dal sito sorvegliato. Applica l'escape prima di renderizzarli in HTML, nel corpo di un'email o in un messaggio di chat.
Il motore di diff e i payload di notifica sono documentati in Watch.
Opzioni PDF#
PdfOptions è una dataclass congelata condivisa da convert_url_to_pdf, convert_website_to_pdf, convert_document, convert_to_pdf e dalla famiglia v2.perceive.
from enconvert import BrowserCookie, HttpBasicAuth, PdfHeaderFooter, PdfMargins, PdfOptions
client.convert_url_to_pdf(
"https://internal.example.com/report",
pdf_options=PdfOptions(
page_size="A4",
orientation="landscape",
margins=PdfMargins(top=10, bottom=10, left=15, right=15),
scale=0.9,
header=PdfHeaderFooter(content="Quarterly Report", height=15),
footer=PdfHeaderFooter(content="Confidential", height=12),
),
auth=HttpBasicAuth(username="user", password="pass"),
cookies=[BrowserCookie(name="session", value="abc123", domain="internal.example.com")],
save_to="report.pdf",
)
| Campo | Tipo | Descrizione |
|---|---|---|
page_size |
str |
"A4", "A3", "Letter", "Legal" e simili. |
page_width / page_height |
float |
Geometria di pagina personalizzata. Insieme prevalgono su page_size. |
orientation |
"portrait" \| "landscape" |
Il valore predefinito è verticale. |
margins |
PdfMargins |
top, bottom, left, right, tutti facoltativi. |
scale |
float |
Scala di rendering, per esempio 0.9 per il 90 percento. |
grayscale |
bool |
Post-elabora il PDF convertendolo in scala di grigi. |
header |
PdfHeaderFooter |
content (fino a 2000 caratteri) e height. |
footer |
PdfHeaderFooter |
content (fino a 2000 caratteri) e height. |
BrowserCookie accetta name, value e o domain o url, più path, expires, http_only, secure e same_site ("Strict", "Lax", "None") facoltativi. L'SDK mappa http_only e same_site sulle rispettive chiavi wire in camelCase al posto tuo.
Gestione degli errori#
Gli errori sono classi di eccezione, quindi intercettali con except. Ordina i gestori dal più specifico al più generale: AuthenticationError, QuotaError e RateLimitError sono tutte sottoclassi di APIError, che a sua volta è sottoclasse di EnconvertError.
from enconvert import APIError, AuthenticationError, EnconvertError, QuotaError, RateLimitError
try:
op = client.v2.perceive("https://example.com")
except AuthenticationError:
print("Invalid or missing API key. Check ENCONVERT_API_KEY.")
except QuotaError as e:
print(f"402 from the API: {e.message}")
except RateLimitError:
print("Too many requests. Back off and retry.")
except APIError as e:
print(f"API error [{e.status_code}]: {e.message}")
except EnconvertError as e:
print(f"Rejected before the request was sent: {e}")
| Classe | Sollevata su | Codice di stato |
|---|---|---|
AuthenticationError |
Chiave non valida, mancante o revocata | 401, 403 |
QuotaError |
HTTP 402 | 402 |
RateLimitError |
Troppe richieste | 429 |
APIError |
Qualsiasi altro 4xx o 5xx | il codice effettivo |
EnconvertError |
Classe base, e validazione lato client che non raggiunge mai la rete | -- |
APIError porta con sé status_code e message, e il suo str() si legge come [404] Not found. Errori lato client in cui puoi incappare: una api_key vuota, un'estensione di file non supportata, una coppia di conversione non implementata, una chiamata distill con entrambi o nessuno tra urls e discover_from, una mancata corrispondenza tra modalità e argomenti di ingest, un payload update_watcher vuoto e un elenco di output di perceive_direct che non si risolve in esattamente un artefatto. La mappa completa dei messaggi è in Codici di errore.
Recupero dei timeout#
Le conversioni lunghe di URL e documenti possono sopravvivere più a lungo del timeout di un reverse-proxy anche quando il server porta a termine il job. L'SDK Python recupera in modo trasparente:
- Prima di ogni conversione di un singolo file o di un singolo URL, l'SDK genera una stringa esadecimale UUID4 e la invia come
job_id. - Se quella richiesta torna con un 5xx, l'SDK passa al polling di
GET /v1/convert/status/{job_id}ogni 3 secondi. Un404lì significa che la riga del job non è ancora stata scritta, quindi il polling continua. - Su
successl'SDK restituisce il risultato come se nulla fosse; sufailedsollevaAPIError(500, ...)con il messaggio di errore del server; e oltre la scadenza di polling di 300 secondi sollevaAPIError(504, "Conversion timed out").
Per tutto questo non scrivi codice. Quando una risposta arriva attraverso il percorso di recupero, ConversionResult.job_id viene valorizzato, così puoi correlarla nei tuoi log.
Due eccezioni. convert_website_to_pdf e convert_website_to_screenshot non partecipano, perché l'invio di un intero sito non ha una riga di job per singola pagina, quindi un 5xx lì significa che è fallito l'invio stesso e l'errore emerge direttamente. Nemmeno gli endpoint V2 vengono interrogati con polling: usa i loro id di job con get_perceive_batch o get_ingest_job.
Configurazione#
client = Enconvert(
api_key=os.environ["ENCONVERT_API_KEY"], timeout=300.0, base_url="https://api.enconvert.com"
)
| Opzione | Tipo | Default | Descrizione |
|---|---|---|---|
api_key |
str |
-- (obbligatoria) | Chiave API privata. Un valore vuoto solleva EnconvertError alla costruzione. |
timeout |
float |
300.0 |
Timeout per richiesta in secondi, applicato a ogni chiamata inclusi gli upload. |
base_url |
str |
https://api.enconvert.com |
URL base dell'API. Le barre finali vengono rimosse. |
Il client mantiene una requests.Session, quindi le connessioni vengono riusate tra le chiamate; riusa un solo client invece di crearne uno per richiesta. La tua chiave viaggia come header X-API-Key, e i download con save_to colpiscono l'URL firmato dello storage come una semplice GET non autenticata scritta su disco in streaming a blocchi da 64 KB, così la chiave non lascia mai l'host dell'API.
Forma del risultato#
I metodi di conversione restituiscono un ConversionResult congelato:
@dataclass(frozen=True)
class ConversionResult:
presigned_url: str
object_key: str
filename: str
file_size: int | None = None
conversion_time_seconds: float | None = None
job_id: str | None = None
L'URL pre-firmato è di breve durata. Passa save_to, oppure recupera tu stesso l'URL, e archivia i byte nel tuo bucket quando ti serve un accesso duraturo.
| Tipo | Restituito da | Campi principali |
|---|---|---|
JobStatus |
get_job_status |
status (processing, success, failed), presigned_url, object_key, error |
BatchSubmission, BatchStatus |
convert_website_to_*, get_batch_status, wait_for_batch |
batch_id, status, url_count, total, completed, failed, discovery_method, zip_download_url, items |
PerceiveResult |
v2.perceive, v2.get_perceive_operation |
operation_id, render_quality, status_code, deductions, outputs, structured, warnings, cache_hit |
PerceiveDirectResult |
v2.perceive_direct, v2.download_perceive_artifact |
content (byte grezzi), content_type, filename, render_quality, source_status_code |
IngestJob |
v2.ingest, v2.ingest_files, v2.get_ingest_job |
job_id, status, mode, pages_processed, total_chunks, output_url, error_message |
Watcher |
i metodi watch di v2 |
watcher_id, status, frequency_minutes, diff_mode, checks_count, next_check_at, last_change_at |
Gli URL degli artefatti V2 sono firmati per 15 minuti e rifirmati ogni volta che leggi l'operazione, quindi chiama get_perceive_operation invece di mettere in cache una stringa di URL.
Sorgente e segnalazioni#
- PyPI: enconvert
- GitHub: conversionapi/python-sdk
- Python: 3.9, 3.10, 3.11, 3.12, 3.13
- Licenza: MIT
- Altri client: Tutti gli SDK
Domande frequenti#
Come converto file in Python?#
Esegui pip install enconvert, costruisci un client con Enconvert(api_key=os.environ["ENCONVERT_API_KEY"]) e chiama un metodo tipizzato come convert_document, convert_image, convert_to_pdf o convert_to_markdown. Passa save_to="out.pdf" e l'SDK scrive il file finito direttamente su disco in streaming, invece di consegnarti un URL da recuperare da solo.
Come converto un URL in PDF con Python?#
Chiama client.convert_url_to_pdf("https://example.com", save_to="page.pdf"). Imposta single_page=False più pdf_options=PdfOptions(page_size="A4") per un output impaginato, e regola viewport_width, load_media o enable_scroll quando una pagina ha bisogno di un canvas più largo o di immagini caricate in lazy loading.
Come converto DOCX in PDF con Python?#
O client.convert_document("report.docx", save_to="report.pdf"), dato che output_format vale già "pdf" per impostazione predefinita, oppure client.convert_to_pdf("report.docx", save_to="report.pdf") quando vuoi il rilevamento automatico del formato lato server. La stessa chiamata gestisce XLSX, PPTX, ODT, ODS, ODP, OTS, Pages e Numbers.
Come converto HEIC in WebP con Python?#
client.convert_image("photo.heic", output_format="webp", save_to="photo.webp"). Il formato di input viene ricavato dall'estensione del nome file, e jpeg, png, svg, heic e webp si convertono tutti l'uno nell'altro. Stai lavorando in memoria invece che su disco? Avvolgi i byte in FileData(data=blob, filename="photo.heic") così l'estensione sopravvive.
Come estraggo una pagina web in Markdown pulito con Python?#
Usa client.v2.perceive(url, outputs=["markdown"]) e leggi op.outputs["markdown"].url, oppure client.v2.perceive_direct(url, outputs=["markdown"]) per ottenere i byte nel corpo della risposta. Aggiungi only_main_content=True per eliminare navigazione e piè di pagina. Per una conversione semplice senza punteggio né estrazione, convert_url_to_markdown è la chiamata più leggera.
Cosa significa render_quality e quando conviene riprovare una pagina?#
È un float da 0.0 a 1.0 su ogni lettura V2 che dice quanto onestamente si è renderizzata la pagina. Una schermata di sfida, un muro dei cookie, un accesso protetto da login, una pagina di errore HTTP o uno shell SPA vuoto ottengono un punteggio basso e indicano cosa è scattato in deductions, con il dettaglio in warnings e lo stato HTTP della pagina stessa in status_code. Usalo come filtro: tratta un punteggio basso come il segnale per riprovare con cache_mode="refresh", con un selettore wait_for che solo il contenuto reale soddisfa, oppure con cookies diversi, invece di dare quel testo in pasto al tuo modello.
Come trasformo un intero sito di documentazione in chunk RAG con Python?#
Chiama client.v2.ingest(mode="sitemap", url="https://docs.example.com", max_pages=100, chunk=IngestChunkOptions(max_words=512, sentence_overlap=1)). Il job è asincrono, quindi o interroghi get_ingest_job(job_id) finché lo stato non esce da queued, discovering e processing, oppure passi webhook_url e aspetti di essere chiamato. Il JSONL finito si trova su output_url. Per documenti locali invece che per un sito, ingest_files esegue la stessa pipeline.
L'SDK Python supporta asyncio?#
Non in modo nativo. Ogni metodo è sincrono e costruito su requests. Dentro un'applicazione asincrona, avvolgi le chiamate in await asyncio.to_thread(client.convert_to_pdf, "report.docx") oppure passale a un concurrent.futures.ThreadPoolExecutor così l'event loop continua a girare. Il client si può condividere tra thread in sicurezza perché mantiene una requests.Session con pool di connessioni.
Come sopravvive l'SDK a un timeout del proxy su una conversione lunga?#
Ogni conversione di un singolo file o di un singolo URL invia un job_id generato. Se la richiesta restituisce 5xx, l'SDK interroga GET /v1/convert/status/{job_id} ogni 3 secondi per un massimo di 300 secondi, restituisce normalmente una volta che il job riporta success, solleva APIError(500, ...) se riporta failed e solleva APIError(504, "Conversion timed out") se la scadenza viene superata. Gli invii di batch di interi siti saltano questo percorso, dato che un errore lì significa che l'invio stesso non è andato a buon fine.