Ga naar inhoud

Overzicht van de Python-SDK

De NextPDF Python-SDK is bedoeld voor Python-toepassingen die extractie uit Portable Document Format (PDF) met herkomst nodig hebben. De kit retourneert gestructureerde blokken met citatieankers, waaronder de pagina-index, het betrouwbaarheidsniveau, optionele begrenzingsvakken en semantische node-identificatoren wanneer die structuur in de bron-PDF beschikbaar is.

Gebruik de SDK wanneer uw pijplijn vragen moet kunnen beantwoorden zoals “Van welke pagina komt deze tekst?”, “Welke tabel ondersteunt deze waarde?” of “Wat is er veranderd tussen deze twee PDF’s?”, zonder PDF-extractie te behandelen als anonieme platte tekst.

  • Een synchrone NextPDF-client voor scripts, batchtaken en notebooks.
  • Een asynchrone AsyncNextPDF-client voor asyncio, FastAPI en andere asynchrone runtimes.
  • Een nextpdf-opdrachtregelinterface (CLI) voor eenmalige extractie vanuit een bestandspad of standaardinvoer, met uitvoer naar standaarduitvoer of een bestand.
  • Een optionele Model Context Protocol-server (MCP) zodat agents met kunstmatige intelligentie (AI) PDF-extractietools rechtstreeks kunnen aanroepen.
  • Een externe backend voor productiegebruik met NextPDF Connect.
  • Een lokale backend voor offline extractie uitsluitend via de bibliotheek, met pypdf.

De externe backend stuurt PDF-bytes naar een NextPDF Connect-server. Dit is het aanbevolen productiepad, omdat het extractiegedrag, de authenticatie, quota en operationele besturing centraal worden afgehandeld.

De lokale backend draait in het Python-proces en leest PDF’s via pypdf. Hij is handig voor offline ontwikkeling en getagde PDF’s, maar kan geen nauwkeurige begrenzingsvakken leveren en gebruikt heuristische extractie op alineaniveau voor niet-getagde PDF’s. De lokale backend werkt uitsluitend via de bibliotheek: injecteer een LocalBackend in AsyncNextPDF om hem te gebruiken. De nextpdf-CLI en de MCP-server kunnen hem niet gebruiken. Zie Backendkeuzematrix voor de volledige vergelijking.

De SDK voert geen optische tekenherkenning (OCR) uit. Gescande PDF’s of PDF’s die alleen uit afbeeldingen bestaan, vereisen een OCR-stap voordat NextPDF ingesloten tekst kan extraheren. Complexe lay-outs, overlappende tekst en ongebruikelijke PDF-producenten kunnen de extractiekwaliteit eveneens verlagen.

De nextpdf-CLI werkt uitsluitend op afstand en is geen streaming-interface. Elke opdracht leest de volledige PDF in het geheugen (vanuit een bestandspad of standaardinvoer), stuurt deze naar een NextPDF Connect-server, bouwt het volledige resultaat in het geheugen op en serialiseert het in één schrijfbewerking. U kunt die uitvoer met --output (of -o) omleiden naar een bestand of naar standaarduitvoer, maar het resultaat wordt volledig gebufferd en niet stapsgewijs geproduceerd. De CLI kan de lokale pypdf-backend niet gebruiken.

Een client kiezen: synchroon versus asynchroon

Sectie met titel “Een client kiezen: synchroon versus asynchroon”

Beide clients delen één ast-naamruimte voor methoden op de abstracte syntaxisboom (AST) en retourneren dezelfde Pydantic-modellen. Ze verschillen alleen in hun concurrency-model.

Uw contextGebruikWaarom
Scripts en batchtakenNextPDF (synchroon)Lineaire besturingsstroom; geen event loop om te beheren.
Jupyter-notebooksNextPDF (synchroon)run_sync detecteert de actieve event loop en stuurt het werk door naar een worker-thread, zodat blokkerende aanroepen in cellen werken.
De nextpdf-CLINextPDF (synchroon, intern)De CLI bouwt een synchrone client voor u.
asyncio-servicesAsyncNextPDFNative await; geen thread-overdracht.
FastAPI, Starlette, Asynchronous Server Gateway Interface (ASGI)AsyncNextPDFDeelt de event loop van het verzoek en dezelfde verbindingspool.
Fan-out met hoge concurrencyAsyncNextPDFVoer veel extracties gelijktijdig uit met asyncio.gather over één gepoolde client.

NextPDF omhult een interne AsyncNextPDF en voert elke aanroep uit via run_sync. Binnen een actieve event loop, zoals in een notebook, stuurt run_sync de coroutine door naar een thread met één worker en een eigen loop, zodat u niet tegen de fout van een geneste asyncio.run aanloopt. Roep in een asyncio- of ASGI-service AsyncNextPDF rechtstreeks aan, zodat u niet bij elke aanroep de kosten van thread-overdracht betaalt.

De asynchrone client heeft een httpx.AsyncClient voor het poolen van verbindingen, dus hergebruik één AsyncNextPDF-instantie en sluit deze één keer. De synchrone NextPDF-client stelt geen close()-methode beschikbaar. Geef voor langlopende asynchrone workloads de voorkeur aan AsyncNextPDF en beheer de levenscyclus expliciet (zie Operationeel productiemodel).

Een backend implementeert het PdfBackend-protocol. De externe backend (RemoteBackend) wordt automatisch geselecteerd wanneer u base_url en api_key doorgeeft. U moet de lokale backend (LocalBackend) expliciet injecteren via de backend=-parameter van AsyncNextPDF; hij wordt niet geëxporteerd uit het pakket nextpdf op topniveau en is niet bereikbaar vanuit de CLI of de MCP-server.

MogelijkheidExtern (RemoteBackend)Lokaal (LocalBackend)
Geselecteerd viabase_url + api_keyAsyncNextPDF(backend=LocalBackend(...))
NetwerkNextPDF Connect via Hypertext Transfer Protocol Secure (HTTPS)Geen; draait in-process
Authenticatie, quota, meteringGecentraliseerd op de serverGeen
Observeerbaarheid en operationele besturingAan de serverzijdeGeen
Extractie uit getagde PDF (StructTree)JaJa
Extractie uit niet-getagde PDFServer-engineHeuristische alineasplitsing, betrouwbaarheid 0.5
BegrenzingsvakkenJa (wanneer de server ze levert)Nee (bbox is None)
Tabelextractie uit niet-getagde PDF’sServer-engineRetourneert geen tabellen
Bereikbaar vanuit CLI / MCP-serverJaNee (uitsluitend via de bibliotheek)
Aanbevolen voorProductieOffline ontwikkeling, tests met getagde PDF’s

Gebruik de externe backend voor productie, omdat dit het enige pad is met gecentraliseerde authenticatie, quotahandhaving, metering en observeerbaarheid. Gebruik de lokale backend voor offline ontwikkeling en tests met getagde PDF’s, waarbij u heuristische resultaten, het ontbreken van begrenzingsvakken en het ontbreken van tabellen bij niet-getagde invoer accepteert.

"""Inject the local backend for offline, library-only extraction."""
from nextpdf import AsyncNextPDF
from nextpdf.backends.local import LocalBackend
async def extract_offline(pdf_bytes: bytes) -> None:
"""Extract cited text without a NextPDF Connect server."""
async with AsyncNextPDF(backend=LocalBackend()) as client:
blocks = await client.ast.extract_cited_text(pdf_bytes)
for block in blocks:
# Heuristic blocks on untagged PDFs report confidence 0.5.
print(block.citation.confidence, block.text)

Gebruik in productie de externe backend met NextPDF Connect. De onderstaande patronen behandelen clienthergebruik, foutafhandeling, herhaalpogingen, quotabeheer en time-outs. Elk symbool dat hier wordt gebruikt, bestaat in de SDK. De SDK voert voor u geen herhaalpogingen uit, dus de herhaallus is uw verantwoordelijkheid.

RemoteBackend houdt één persistente httpx.AsyncClient in stand voor het poolen van verbindingen. Maak AsyncNextPDF één keer, deel deze tussen verzoeken en sluit de client bij het afsluiten. Maak geen client per verzoek aan.

"""Reuse one pooled async client for the lifetime of the process."""
import asyncio
import os
from pathlib import Path
from nextpdf import AsyncNextPDF
async def main() -> None:
"""Run several extractions over a single pooled client."""
base_url = os.environ["NEXTPDF_BASE_URL"]
# Treat the API key as a secret; read it from the environment, never hard-code it.
api_key = os.environ["NEXTPDF_API_KEY"]
async with AsyncNextPDF(base_url=base_url, api_key=api_key) as client:
pdf_paths = (Path("a.pdf"), Path("b.pdf"), Path("c.pdf"))
tasks = [
client.ast.get_document_ast(path.read_bytes())
for path in pdf_paths
]
documents = await asyncio.gather(*tasks)
for document in documents:
print(document.page_count, document.estimated_tokens)
if __name__ == "__main__":
asyncio.run(main())

De asynchrone contextmanager roept bij het afsluiten close() aan, waardoor de onderliggende transportlaag wordt gesloten. Als u geen contextmanager gebruikt, roep dan zelf await client.close() aan.

Handel fouten af met de uitzonderingshiërarchie

Sectie met titel “Handel fouten af met de uitzonderingshiërarchie”

De SDK genereert een getypeerde uitzonderingshiërarchie. Alle fouten zijn afgeleid van NextPDFError; storingen op het niveau van Hypertext Transfer Protocol (HTTP) zijn afgeleid van NextPDFAPIError en bevatten een status_code. Vang de specifieke typen af waarop u kunt reageren en val terug op het basistype.

UitzonderingGegenereerd wanneerBelangrijkste attributen
NextPDFErrorBasistype voor elke SDK-foutstatus_code
NextPDFAPIErrorElke HTTP-fout van de serverstatus_code, error_code
NextPDFLicenseErrorHTTP 402; de functie vereist een hoger serverniveaustatus_code (402)
QuotaExceededErrorHTTP 429; snelheidslimiet of quotum overschredenretry_after
AstNoStructTreeErrorHTTP 422; niet-getagde PDF met heuristische modus uitstatus_code (422)
AstBuildTimeoutErrorHTTP 504; AST-opbouw is verlopen door een time-outstatus_code (504)
"""Map SDK exceptions to caller-facing outcomes."""
from nextpdf import (
AstBuildTimeoutError,
AstNoStructTreeError,
AsyncNextPDF,
NextPDFAPIError,
NextPDFError,
NextPDFLicenseError,
QuotaExceededError,
)
async def safe_extract(client: AsyncNextPDF, pdf_bytes: bytes) -> str:
"""Extract text, translating known failures into a stable status string."""
try:
blocks = await client.ast.extract_cited_text(pdf_bytes)
except QuotaExceededError as exc:
# exc.retry_after holds the server Retry-After value in seconds, or None.
return f"rate-limited; retry after {exc.retry_after}s"
except NextPDFLicenseError:
return "feature requires a higher server tier"
except AstNoStructTreeError:
return "untagged PDF; enable heuristic mode or use a tagged PDF"
except AstBuildTimeoutError:
return "build timed out; reduce the page range"
except NextPDFAPIError as exc:
return f"server error (status {exc.status_code})"
except NextPDFError:
return "extraction failed"
return "\n".join(block.text for block in blocks)

Doe opnieuw pogingen bij tijdelijke fouten met backoff

Sectie met titel “Doe opnieuw pogingen bij tijdelijke fouten met backoff”

De SDK voert niet automatisch herhaalpogingen uit. Plaats aanroepen in uw eigen lus die tijdelijke HTTP-storingen opnieuw probeert en de Retry-After-waarde van de server respecteert, die QuotaExceededError beschikbaar stelt als retry_after (een geheel aantal seconden, of None). Gebruik exponentiële backoff voor andere tijdelijke statussen en probeer niet opnieuw bij NextPDFLicenseError.

"""Retry transient failures with exponential backoff and Retry-After support."""
import asyncio
from collections.abc import Awaitable, Callable
from typing import TypeVar
from nextpdf import NextPDFAPIError, QuotaExceededError
_RETRYABLE_STATUS = frozenset({500, 502, 503, 504})
_T = TypeVar("_T")
async def with_retry(
coro_factory: Callable[[], Awaitable[_T]],
*,
max_attempts: int = 4,
) -> _T:
"""Call coro_factory() with bounded retries on transient server errors.
Args:
coro_factory: A zero-argument callable returning a fresh awaitable.
max_attempts: Maximum number of attempts before giving up.
Returns:
The awaited result of the first successful attempt.
Raises:
NextPDFAPIError: When all attempts fail or the error is not retryable.
"""
delay = 1.0
for attempt in range(1, max_attempts + 1):
try:
return await coro_factory()
except QuotaExceededError as exc:
if attempt == max_attempts:
raise
await asyncio.sleep(exc.retry_after if exc.retry_after is not None else delay)
delay *= 2.0
except NextPDFAPIError as exc:
if attempt == max_attempts or exc.status_code not in _RETRYABLE_STATUS:
raise
await asyncio.sleep(delay)
delay *= 2.0
raise RuntimeError("unreachable")

Quota- en snelheidslimiethandhaving vinden plaats op de server. Bij HTTP 429 genereert de SDK QuotaExceededError en parseert de Retry-After-header naar retry_after. De externe backend levert ook X-RateLimit-*-headers op render-antwoorden, zodat u proactief kunt afremmen voordat u tegen een harde limiet aanloopt.

Verzoektime-outs gebruiken een vaste standaard van 60 seconden in totaal met een verbindingstime-out van 10 seconden (httpx.Timeout(60.0, connect=10.0)). Om lange AST-opbouwprocessen te begrenzen, beperkt u het werk met page_range_start, page_range_end of token_budget in plaats van alleen op de time-out te vertrouwen; een opbouw die te lang duurt, retourneert AstBuildTimeoutError (HTTP 504).

Een batchworker leest PDF’s, extraheert geciteerde tekst en schrijft gestructureerde uitvoer. Hergebruik één gepoolde client, begrens de concurrency met een semafoor en pas de bovenstaande herhaalhelper toe.

"""Batch-extract a directory of PDFs over one pooled async client."""
import asyncio
import os
from pathlib import Path
from nextpdf import AsyncNextPDF
async def run_batch(input_dir: Path, concurrency: int = 8) -> None:
"""Extract cited text for every PDF in input_dir, bounded by concurrency."""
semaphore = asyncio.Semaphore(concurrency)
async def worker(client: AsyncNextPDF, path: Path) -> None:
async with semaphore:
blocks = await client.ast.extract_cited_text(path.read_bytes())
out = path.with_suffix(".txt")
out.write_text("\n".join(b.text for b in blocks), encoding="utf-8")
async with AsyncNextPDF(
base_url=os.environ["NEXTPDF_BASE_URL"],
api_key=os.environ["NEXTPDF_API_KEY"],
) as client:
await asyncio.gather(*(worker(client, p) for p in input_dir.glob("*.pdf")))

Een FastAPI-service deelt één AsyncNextPDF tussen verzoeken gedurende de levensduur van de toepassing, zodat elk verzoek de verbindingspool hergebruikt. Lees de inloggegevens uit de omgeving en behandel de API-sleutel als een geheim.

"""FastAPI service that shares one pooled NextPDF client across requests."""
import os
from contextlib import asynccontextmanager
from fastapi import FastAPI, UploadFile
from nextpdf import AsyncNextPDF
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Create the pooled client on startup and close it on shutdown."""
app.state.client = AsyncNextPDF(
base_url=os.environ["NEXTPDF_BASE_URL"],
api_key=os.environ["NEXTPDF_API_KEY"],
)
try:
yield
finally:
await app.state.client.close()
app = FastAPI(lifespan=lifespan)
@app.post("/extract")
async def extract(file: UploadFile) -> dict[str, list[str]]:
"""Return cited text blocks for an uploaded PDF."""
pdf_bytes = await file.read()
blocks = await app.state.client.ast.extract_cited_text(pdf_bytes)
return {"text": [block.text for block in blocks]}

Draai voor AI-agents de MCP-server. Deze stelt PDF-tools beschikbaar (bijvoorbeeld nextpdf_extract_text, nextpdf_extract_tables, nextpdf_get_ast, nextpdf_info, nextpdf_search, nextpdf_get_outline, nextpdf_diff en nextpdf_health) via standaardinvoer en standaarduitvoer. De server leest NEXTPDF_BASE_URL en NEXTPDF_API_KEY uit de omgeving, dus hij gebruikt de externe backend; net als de CLI kan hij de lokale backend niet gebruiken. Installeer de optionele extra en voer de module uit.

Terminal window
pip install "nextpdf[mcp]"
python -m nextpdf.mcp

Zie Python MCP-server voor de walkthrough van de agent-integratie, Python-CLI voor terminalgebruik en Python API-referentie voor de volledige client-, model- en uitzonderingsinterface.