Strukturierte Daten von Websites extrahieren (API)#
POST /v2/distill ist eine API, um strukturierte Daten aus Websites zu
extrahieren: Sie zieht Felder aus einer oder mehreren URLs heraus, passend
zu einem von dir gelieferten Schema, entweder einem JSON-Schema-Objekt
oder einer flachen {field: description}-Map. Sie läuft als
Zwei-Pass-Engine: zuerst ein kostenloser CSS-Pass (Crawl4AIs
JsonCssExtractionStrategy, gesteuert von deinen Selektoren), dann ein
gedeckelter, LLM-gestützter Pass für die Felder, die der CSS-Pass leer
gelassen hat. Das data-Feld der Antwort kommt
garantiert exakt in der angeforderten Form zurück. Es wird EnConverts
Antwort auf Firecrawl /extract sein.
Hier der kleinste nützliche Aufruf. Sende eine URL und ein flaches
{field: description}-Schema und erhalte die extrahierten Felder zurück:
curl -X POST https://api.enconvert.com/v2/distill \
-H "X-API-Key: sk_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"urls": ["https://example.com/product/widget"],
"schema": {
"name": "the product name",
"price": "the listed price",
"in_stock": "whether it is in stock"
}
}'
Die Antwort enthält ein Ergebnis pro URL, die extrahierten data und
welche Stufe sie geliefert hat:
{
"operation_id": "dst_3f9a2c1b8e7d4a6f90b1c2d3e4f5a6b7",
"total": 1,
"completed": 1,
"failed": 0,
"results": [
{
"url": "https://example.com/product/widget",
"url_final": "https://example.com/product/widget",
"status": "completed",
"data": {
"name": "Widget Pro",
"price": "$49.00",
"in_stock": "yes"
},
"extraction_tier": "llm",
"fields_from_css": 0,
"fields_from_llm": 3,
"render_quality": 0.91,
"tokens": {"input": 4120, "output": 38},
"cost_cents": 0.45,
"warnings": []
}
],
"total_cost_cents": 0.45,
"warnings": []
}
Endpunkte#
| Methode | Pfad | Zweck |
|---|---|---|
POST |
/v2/distill |
Führt distill für eine explizite URL-Liste aus, oder ermittelt zunächst mit discover die URLs einer Site und führt distill für jede aus, jeweils gegen ein Schema. |
Content-Type: application/json.
Anders als perceive ist distill ein einzelner synchroner Endpunkt: Es gibt keinen separaten GET-Re-Fetch oder asynchronen Batch-Pfad. Jede URL wird sequenziell über das gemeinsam genutzte Headless-Chrome-Singleton gerendert, und die vollständige Ergebnismenge kommt in einer einzigen Antwort zurück.
Authentifizierung#
Authentifiziere dich mit einem privaten Schlüssel im X-API-Key-Header
für Server-zu-Server-Aufrufe. Diesen Weg verwenden die folgenden
Beispiele.
X-API-Key: sk_your_private_key
Öffentliche Schlüssel mit einem JWT-Bearer-Token funktionieren ebenfalls,
nach demselben Ablauf wie bei jedem anderen Endpunkt: Erzeuge ein Token
mit deinem pk_-Schlüssel und sende es als Authorization: Bearer
<token>. Der vollständige Ablauf, einschließlich Domain-Lock und
Token-Refresh, steht in der Authentifizierungsanleitung.
Jeder API-Schlüssel trägt eine Allowlist erlaubter Endpunkte. Steht
/v2/distill nicht auf der Liste des Schlüssels, wird die Anfrage mit
403 abgelehnt.
Wie distill funktioniert#
Eine Anfrage führt distill für eine Liste von URLs gegen ein Schema aus. Der Ablauf ist für jede URL derselbe:
- URL-Liste auflösen. Bei
urlsist die Liste exakt das, was du gesendet hast (dedupliziert, Reihenfolge erhalten). Beidiscover_fromführt distill zuerst discover auf der Seed-URL aus (parst die Sitemap, crawlt, oder beides) und verarbeitet anschließend die entdeckten URLs bis zumax_pages. - Rendern. Jede URL wird einmal in Headless-Chrome gerendert, über
dieselbe Capture-Pipeline, die auch perceive
antreibt. Das Rendering wird auf SSRF geprüft und, falls
respect_robots=true, gegen dierobots.txtder Site abgeglichen. Es werden keine Artefakte in den Storage hochgeladen, denn distill braucht nur das gerenderte DOM. - Pass 1: CSS (kostenlos). Hast du ein
css_schemamitgeschickt, läuft der CSS-Extraktor über das gerenderte HTML und füllt jedes selektor-adressierbare Feld zu null LLM-Kosten. Dieser Pass ist auf 10 Sekunden zeitlich begrenzt; bei Timeout fällt die URL mit einer Warnung in den LLM-Pass durch. - Pass 2: LLM (gedeckelt, nur bei Bedarf). Distill sammelt die
Schema-Felder, die der CSS-Pass fehlend oder leer gelassen hat, und
eskaliert nur diese Felder an die LLM-Stufe, unter harten
Budgetgrenzen pro Aufruf und pro Zeitraum. Hat dein Plan keine
LLM-Stufe, wurde die Seite als blockiert markiert, oder wird eine
Budgetgrenze erreicht, wird der LLM-Pass übersprungen, und die
fehlenden Felder kommen mit einer Warnung als
nullzurück. - Normalisieren. Das zusammengeführte Ergebnis wird exakt auf die
Keys deines Schemas umgeformt: Fehlende Skalare werden zu
null, fehlende Arrays zu[], und alle zusätzlichen Keys werden verworfen. Die Formgarantie gilt unabhängig davon, was CSS oder das LLM geliefert haben.
Pro abgeschlossener URL wird eine Op berechnet, und erst nachdem die
URL fertig ist. Render-Fehlschläge (SSRF-Ablehnung, Robots-Blockade,
ein abgestürztes Rendering) erzeugen eine Ergebniszeile mit failed und
kosten keine Ops.
Request-Parameter#
Du musst genau eines von urls oder discover_from angeben, plus
ein schema. Beides oder keines von beiden zu senden, ergibt 422.
Quelle: explizite URLs#
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
urls |
string[] |
-- | Explizite URLs für distill. Jede muss mit http:// oder https:// beginnen und darf höchstens 2,048 Zeichen lang sein. Max. 50 URLs pro Request (MAX_DISTILL_URLS). Schließt sich mit discover_from gegenseitig aus. |
Quelle: discover, dann distill#
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
discover_from |
object |
-- | Ermittelt zunächst mit discover die URLs einer Site, führt distill dann für jede einzelne aus. Schließt sich mit urls gegenseitig aus. Erfordert das Plan-Flag discover_enabled (sonst 402). |
discover_from.url |
string |
-- | Seed-URL. Muss mit http:// oder https:// beginnen. Max. 2,048 Zeichen. |
discover_from.mode |
string |
hybrid |
sitemap, crawl oder hybrid. Dieselben Modi wie beim discover-Endpunkt. |
discover_from.max_pages |
integer |
10 |
Obergrenze für die Anzahl der über discover ermittelten und mit distill verarbeiteten URLs, von 1 bis 50. Jede ist ein vollständiges Rendering, daher begrenzt durch MAX_DISTILL_URLS. |
Schema oder Prompt#
Gib entweder ein schema (die gewünschte Ausgabeform) oder
einen prompt (eine Beschreibung in natürlicher Sprache, was extrahiert
werden soll) an. Genau eines von beiden ist erforderlich; sendest du
beide, gewinnt schema.
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
schema |
object |
null |
Die Ausgabeform, gesendet unter dem JSON-Key schema. Entweder ein JSON-Schema-Objekt ({"type": "object", "properties": {...}}) oder eine nachsichtige flache {field: description}-Map. Max. 200 Top-Level-Properties. Die data der Antwort entspricht garantiert dieser Form. Ein strukturell ungültiges Schema ergibt 422. |
prompt |
string |
null |
Eine Beschreibung in natürlicher Sprache, was extrahiert werden soll. Wird er ohne schema angegeben, synthetisiert distill daraus das Extraktionsschema (ein einzelnes Modell) und führt dann die normale Zwei-Pass-Engine aus. Max. 2,000 Zeichen. |
Das Schema ist der Vertrag. Sendest du ein JSON-Schema-Objekt, liest
distill dessen properties; sendest du eine flache Map, benennt jeder
Key ein Feld, und jeder Value ist die Beschreibung, die ans LLM übergeben
wird. So oder so kommt data mit exakt den Top-Level-Keys des Schemas
zurück.
Prompt-only-Modus. Sendest du einen prompt statt eines schema,
synthetisiert distill zuerst ein Schema von Feldern aus deinem Prompt
und extrahiert dann dagegen. Die synthetisierten Felder werden in der
Antwort als synthesized_schema zurückgegeben. Der Prompt-only-Modus
verwendet die LLM-Extraktionsstufe und erfordert einen Plan, der sie
enthält; ohne einen solchen liefert distill eine klare Warnung, statt zu
raten.
CSS-Schema (optional)#
Liefere ein css_schema, um Felder kostenlos zu beantworten, bevor ein
LLM-Aufruf stattfindet. Ohne es fällt jedes Feld direkt in den LLM-Pass.
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
css_schema.baseSelector |
string |
-- | CSS-Selektor für den sich wiederholenden Container; pro Treffer wird ein Datensatz extrahiert. 1 bis 1,024 Zeichen. Erforderlich, wenn css_schema vorhanden ist. |
css_schema.fields |
CssField[] |
-- | 1 bis 128 Felddefinitionen, die aus jedem Container ausgelesen werden. Erforderlich. |
css_schema.name |
string |
"distill" |
Optionale Bezeichnung für das Schema. Max. 128 Zeichen. |
css_schema.target_field |
string |
abgeleitet | Welche Top-Level-Ausgabe-Property die CSS-Datensätze füllen: Eine Array-Property erhält die vollständige Datensatzliste, eine Skalar-/Objekt-Property erhält den ersten Datensatz. Fehlt der Wert, ermittelt distill die Property automatisch, sofern das Schema genau eine Array-Property hat. Max. 128 Zeichen. |
Jeder Eintrag in fields ist ein CssField:
| Feld | Typ | Standard | Beschreibung |
|---|---|---|---|
name |
string |
-- | Ausgabe-Key für dieses Feld. 1 bis 128 Zeichen. Erforderlich. |
type |
string |
-- | Eine von text, attribute, html, regex, nested, list, nested_list. Erforderlich. |
selector |
string |
null |
CSS-Sub-Selektor. Optional bei Blatt-Typen (text/attribute/html/regex); erforderlich bei nested/list/nested_list. Max. 1,024 Zeichen. |
attribute |
string |
null |
Name des auszulesenden Attributs. Erforderlich, wenn type gleich attribute ist. Max. 128 Zeichen. |
pattern |
string |
null |
Regex-Pattern. Erforderlich, wenn type gleich regex ist. Wird am Edge kompiliert; ein Pattern mit verschachtelten, erneut quantifizierten Gruppen (eine ReDoS-Form wie (a+)+) wird mit 422 abgelehnt. Max. 1,024 Zeichen. |
default |
any | null |
Wert, wenn der Selektor nichts trifft. |
transform |
string |
null |
Eine von lowercase, uppercase, strip. |
fields |
CssField[] |
null |
Kindfelder, für nested/list/nested_list. Max. 64 Kinder; maximale Verschachtelungstiefe 5. |
Wichtig zu wissen: Der Feldtyp computed aus Crawl4AI wird bewusst nicht
akzeptiert. Seine Expression-Form führt eval auf Caller-Input aus, und
seine Callable-Form kann keine JSON-Grenze überqueren, weshalb distill
nur die sieben oben genannten sicheren Typen zulässt.
Render-Einstellungen#
Distill rendert nur das DOM und stellt daher nur eine kleine Teilmenge der perceive-Render-Optionen bereit.
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
wait_for |
string |
null |
Wartet nach der Navigation auf einen CSS-Selektor oder einen JS-Ausdruck ("js:window.dataReady === true"). Max. 1,024 Zeichen. |
wait_timeout_ms |
integer |
30000 |
Wie lange wait_for warten darf, in Millisekunden. 0 bis 60,000. |
headers |
object |
null |
Benutzerdefinierte Request-Header für das Rendering. |
cookies |
array |
null |
Cookies, die vor der Navigation injiziert werden. |
respect_robots |
boolean |
false |
Bei true wird eine von der robots.txt der Site untersagte URL abgelehnt, und das Ergebnis dieser URL wird als failed markiert. |
Antwort#
POST /v2/distill liefert eine DistillResponse:
| Feld | Typ | Beschreibung |
|---|---|---|
operation_id |
string |
Opake ID (dst_...). Bei Support-Anfragen angeben. |
total |
integer |
Anzahl der verarbeiteten URLs (Zeilen in results). |
completed |
integer |
URLs, die gerendert wurden und ein data-Objekt geliefert haben. |
failed |
integer |
URLs, deren Rendering abgelehnt wurde oder abgestürzt ist. |
results |
object[] |
Ein DistillItemResult pro URL, unten beschrieben. |
total_cost_cents |
number |
Summe der LLM-Kosten pro URL über die gesamte Anfrage, in Cent. |
synthesized_schema |
object |
Nur im Prompt-only-Modus vorhanden: das Schema, das aus deinem prompt synthetisiert und für die Extraktion verwendet wurde. |
warnings |
string[] |
Hinweise auf Request-Ebene (z. B. Ops-Kontingent mitten in der Liste erschöpft, Crawl-Fehler bei discover). |
Jeder Eintrag in results ist ein DistillItemResult:
| Feld | Typ | Beschreibung |
|---|---|---|
url |
string |
Die URL, die du gesendet hast (oder die ermittelt wurde). |
url_final |
string |
Die URL nach Redirects. Entfällt bei einer failed-Zeile. |
status |
string |
completed oder failed. |
data |
object |
Die extrahierten Daten, normalisiert auf exakt die Keys deines Schemas. null bei einer failed-Zeile. |
extraction_tier |
string |
css (nur CSS), llm (nur LLM), mixed (beide haben beigetragen) oder none (nichts gefunden). |
fields_from_css |
integer |
Anzahl der Felder, die der CSS-Pass gefüllt hat. |
fields_from_llm |
integer |
Anzahl der Felder, die der LLM-Pass gefüllt hat. |
render_quality |
number |
0.0 bis 1.0. Niedrige Werte weisen auf Anti-Bot-Challenges oder Login-Walls hin. |
tokens |
object |
{input, output} verwendete LLM-Tokens. Null, außer der LLM-Pass lief. |
cost_cents |
number |
LLM-Kosten in Cent für diese URL. Null, außer der LLM-Pass lief. |
error |
string |
Nur gesetzt, wenn status gleich failed ist. Eine generische Meldung, denn interne Render-Details bleiben serverseitig. |
warnings |
string[] |
Hinweise pro URL: ein CSS-Timeout, ein übersprungener LLM-Pass, eine erreichte Budgetgrenze. |
Um ganz klar zu sein: Die Antwort enthält keine signierten Download-URLs
und keine gespeicherten Artefakte. Distill liefert die strukturierten
data inline und sonst nichts. Willst du zusätzlich das Markdown,
HTML, einen Screenshot oder ein PDF der Seite, ist dafür
perceive da.
Das Zwei-Pass-Kostenmodell#
Der CSS-Pass ist kostenlos. Der LLM-Pass kostet Geld, daher löst distill ihn so gezielt wie möglich aus und deckelt ihn aus mehreren Richtungen.
Es eskaliert nur die fehlenden Felder. Nach dem CSS-Pass berechnet
distill, welche Schema-Felder noch leer sind: ein Skalar, der als
null/"" zurückkam, ein Array, das leer zurückkam, oder ein Array,
dessen Elemente ein deklariertes Unterfeld vermissen lassen. Nur diese
Feldnamen fließen in ein reduziertes Schema für den LLM-Aufruf ein, was
Prompt und Kosten minimal hält.
Der LLM-Pass wird vollständig übersprungen, wenn eine der folgenden Bedingungen zutrifft; distill liefert dann das reine CSS-Ergebnis mit einer Warnung, statt zu überziehen:
- Dein Plan hat keine LLM-Stufe (
llm_extraction_enabledplus einenagent_model_tierungleichnone). - Die
render_qualityder Seite hat sie als durch Anti-Bot-Schutz blockiert markiert. - Das Pro-Request-LLM-Budget für diesen Aufruf ist erreicht, oder die Pro-Zeitraum-Budgetgrenze ist erreicht.
Die Budgetgrenzen sind gestaffelt:
| Grenze | Wert | Geltungsbereich |
|---|---|---|
| Pro Aufruf | $0.05 (PER_REQUEST_CAP_CENTS) |
Worst-Case-Kostenprognose eines einzelnen LLM-Aufrufs. Darüber → wird übersprungen, noch bevor Netzwerk-I/O stattfindet. |
| Pro Request | $0.50 (_REQUEST_LLM_BUDGET_CENTS) |
Gesamte LLM-Ausgaben über alle URLs eines /v2/distill-Aufrufs. Verbleibende URLs liefern nur CSS-Ergebnisse. |
| Eskalationen pro Request | 50 (_MAX_LLM_ESCALATIONS) |
Höchstens ein LLM-Aufruf pro URL, hart gedeckelt. |
| Pro Zeitraum | Dein monatliches AI-Credit-Guthaben: $5 / $15 / $40 pro Monat auf Indie / Studio / Production, ungenutzte Credits werden übertragen | ch_usage_periods.llm_cost_cents gegen die gewährten Credits der Periode (usage.reserve_llm_budget). |
Hinweis. Das Pro-Zeitraum-Budget wird vor dem Aufruf atomar reserviert und danach auf die tatsächlichen Kosten abgerechnet, sodass gleichzeitige Aufrufe die Grenze nicht gemeinsam überschreiten können. Ein Projekt ohne aktive Usage-Period-Zeile schlägt sicherheitshalber fehl (fail closed), denn Ausgaben, die EnConvert nicht zuordnen kann, sind Ausgaben, die nicht getätigt werden. Wird eine Grenze erreicht, kommen die betroffenen Felder mit einer Warnung als
nullzurück; die Anfrage ist trotzdem erfolgreich.
Läuft der LLM-Pass, meldet extraction_tier llm oder mixed, und
tokens sowie cost_cents melden die entstandenen Kosten. Läuft er
nicht, sind beide null.
CSS-Datensätze auf dein Schema abbilden#
Der Standardfall ist eine Listing-Seite: eine sich wiederholende Zeile
und ein Ausgabeschema mit einer Array-Property, die die Zeilen aufnimmt.
Gib distill ein css_schema, dessen baseSelector die Zeile trifft und
dessen fields die Spalten auslesen, und es füllt das Array kostenlos:
curl -X POST https://api.enconvert.com/v2/distill \
-H "X-API-Key: sk_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"urls": ["https://example.com/products"],
"schema": {
"type": "object",
"properties": {
"products": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"price": {"type": "string"},
"sku": {"type": "string"}
}
}
}
}
},
"css_schema": {
"baseSelector": ".product-card",
"target_field": "products",
"fields": [
{"name": "name", "type": "text", "selector": ".title"},
{"name": "price", "type": "text", "selector": ".price"},
{"name": "sku", "type": "attribute",
"selector": ".product-card", "attribute": "data-sku"}
]
}
}'
Wie Datensätze im Schema landen:
target_fieldauf eine Array-Property gesetzt → diese Property erhält die vollständige Datensatzliste.target_fieldauf eine Skalar-/Objekt-Property gesetzt → sie erhält den ersten Datensatz.target_fieldweggelassen, Schema hat genau eine Array-Property → distill ermittelt sie automatisch und füllt diese Property.- Andernfalls → der erste Datensatz wird als einzelnes flaches Objekt behandelt, und seine passenden Keys werden auf die oberste Ebene gehoben.
Füllt CSS das Array, aber einigen Elementen fehlt ein deklariertes
Unterfeld (sagen wir, sku fehlt bei der Hälfte der Karten), eskaliert
distill products an den LLM-Pass, um die Lücken zu füllen. Das ist der
Zwei-Pass-Unterschied gegenüber einem simplen Scraper: strukturiert, wo
es geht, modellgestützt, wo es sein muss.
Codebeispiele#
curl: flaches Schema, nur LLM#
curl -X POST https://api.enconvert.com/v2/distill \
-H "X-API-Key: sk_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"urls": ["https://example.com/article"],
"schema": {
"headline": "the article headline",
"author": "the author name",
"published": "the publish date"
}
}'
curl: discover, dann distill#
curl -X POST https://api.enconvert.com/v2/distill \
-H "X-API-Key: sk_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"discover_from": {
"url": "https://example.com/blog",
"mode": "sitemap",
"max_pages": 25
},
"schema": {
"title": "the post title",
"summary": "a one-line summary"
}
}'
Python#
import requests
response = requests.post(
"https://api.enconvert.com/v2/distill",
headers={"X-API-Key": "sk_your_private_key"},
json={
"urls": ["https://example.com/product/widget"],
"schema": {
"name": "the product name",
"price": "the listed price",
"in_stock": "whether it is in stock",
},
},
)
response.raise_for_status()
result = response.json()
for item in result["results"]:
if item["status"] == "completed":
print(item["url"], "->", item["data"])
else:
print(item["url"], "FAILED:", item["error"])
print("total cost (cents):", result["total_cost_cents"])
Node.js#
const res = await fetch("https://api.enconvert.com/v2/distill", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": "sk_your_private_key"
},
body: JSON.stringify({
urls: ["https://example.com/product/widget"],
schema: {
name: "the product name",
price: "the listed price",
in_stock: "whether it is in stock"
}
})
});
const result = await res.json();
for (const item of result.results) {
if (item.status === "completed") {
console.log(item.url, "->", item.data);
} else {
console.log(item.url, "FAILED:", item.error);
}
}
console.log("total cost (cents):", result.total_cost_cents);
Fehlerantworten#
| Status | Bedingung |
|---|---|
400 Bad Request |
Eine URL (oder der discover_from-Seed) löst zu einer privaten, Loopback- oder Link-Local-Adresse auf, hat keinen Hostnamen oder scheitert anderweitig an der SSRF-Prüfung. Wird pro URL während des Renderings ausgelöst. |
401 Unauthorized |
Fehlender oder ungültiger API-Schlüssel / JWT-Token. |
402 Payment Required |
distill ist nicht in deinem aktuellen Plan enthalten, dein monatliches Ops-Kontingent ist erschöpft, oder discover_from wurde ohne das Plan-Flag discover_enabled gesendet. |
403 Forbidden |
/v2/distill steht nicht in den erlaubten Endpunkten des API-Schlüssels. |
422 Unprocessable Entity |
Kein schema, beides oder keines von urls/discover_from, ein strukturell ungültiges Schema, über 200 Schema-Properties, ein ungültiges CssField (fehlendes attribute/pattern/fields für seinen Typ, ein nicht kompilierbarer oder ReDoS-anfälliger Regex), oder CSS-Feld-Verschachtelung tiefer als 5. |
500 Internal Server Error |
Die Orchestrierung ist unerwartet fehlgeschlagen. Die Meldung enthält die operation_id zur Angabe beim Support. |
Ein paar Status-Feinheiten, die man auseinanderhalten sollte: Eine
einzelne URL, deren Rendering wegen SSRF abgelehnt wird, führt nur dann
zu einem 400, wenn sie der Seed einer discover_from-Anfrage ist; bei
einer expliziten urls-Liste wird eine per-URL-Render-Ablehnung
stattdessen zu einer Ergebniszeile mit failed, statt die gesamte
Anfrage scheitern zu lassen. Eine erreichte LLM-Budgetgrenze ist niemals
ein Fehler, denn sie degradiert zu einem reinen CSS-Ergebnis mit einer
Warnung. Die vollständige Status-Code-Referenz steht in
der Fehlercode-Anleitung.
Limits#
| Limit | Wert |
|---|---|
URLs pro Request (urls) |
50 (MAX_DISTILL_URLS) |
discover_from.max_pages |
1 bis 50 |
| URL-Länge | 2,048 Zeichen |
| Schema-Top-Level-Properties | 200 (MAX_SCHEMA_PROPERTIES) |
css_schema.fields |
1 bis 128 |
CssField.fields-Kinder |
64 |
| CSS-Feld-Verschachtelungstiefe | 5 (MAX_CSS_FIELD_DEPTH) |
wait_for-Länge |
1,024 Zeichen |
wait_timeout_ms |
0 bis 60,000 ms |
| CSS-Pass-Timeout | 10 Sekunden pro URL |
| LLM-Grenze pro Aufruf | $0.05 |
| LLM-Grenze pro Request | $0.50 |
| LLM-Eskalationen pro Request | 50 |
| LLM-Grenze pro Zeitraum | Monatliches AI-Credit-Guthaben ($5 / $15 / $40 je Tarif; ungenutzte Credits werden übertragen) |
| Monatliche Ops (über alle Endpunkte geteilt, 1 pro abgeschlossener URL) | 500 / 3.000 / 15.000 / 50.000 je Tarif; siehe Preise |
Häufig gestellte Fragen#
Wie extrahiere ich strukturierte Daten von einer Website mit einer REST-API?#
Sende POST /v2/distill mit urls (bis zu 50 pro Request) und einem schema, entweder ein JSON-Schema-Objekt oder eine flache {field: description}-Map. Die data der Antwort kommt normalisiert auf exakt die Top-Level-Keys deines Schemas zurück.
Kann ich eine Website ohne CSS-Selektoren in ein JSON-Schema scrapen?#
Ja. css_schema ist optional, und ohne es fällt jedes Feld direkt in den LLM-gestützten Pass. Ein mitgeschicktes css_schema füllt selektor-adressierbare Felder kostenlos und eskaliert nur die Felder, die der CSS-Pass leer gelassen hat.
Was kostet der LLM-Extraktionspass, und wie wird er gedeckelt?#
Die Budgetgrenzen sind gestaffelt: $0.05 pro LLM-Aufruf, $0.50 pro /v2/distill-Request, höchstens 50 Eskalationen pro Request und pro Zeitraum dein monatliches AI-Credit-Guthaben ($5 / $15 / $40 auf Indie / Studio / Production; ungenutzte Credits werden übertragen). LLM-Extraktion verbraucht Credits, keine Ops. Das Erreichen einer Grenze lässt die Anfrage nie scheitern: Betroffene Felder kommen mit einer Warnung als null zurück.
Warum sind manche Felder in meiner distill-Antwort null?#
Fehlende Skalare werden auf null normalisiert (fehlende Arrays auf []), um die Formgarantie zu wahren. Der LLM-Pass wird übersprungen (mit einer Warnung), wenn dein Plan keine LLM-Stufe hat, die render_quality der Seite sie als blockiert markiert hat oder eine Budgetgrenze erreicht wurde.
Kann ich eine ganze Site crawlen und aus jeder Seite dasselbe Schema extrahieren?#
Ja. Sende statt urls ein discover_from mit einer Seed-url, einem mode (sitemap, crawl oder hybrid) und max_pages (1 bis 50). Das erfordert das Plan-Flag discover_enabled; ohne es wird die Anfrage mit 402 abgelehnt.