API Sitemap Crawler#
POST /v2/discover è un'API di sitemap crawling che elenca gli URL di un
sito in modo economico: una scansione HTTP-first più il parsing della
sitemap, con un fallback opzionale di rendering JavaScript per le
single-page app. Non c'è alcuno screenshot, alcun PDF né alcun artefatto
salvato. Restituisce un elenco piatto e deduplicato
di URL con un conteggio di provenienza per ciascuno, in modo sincrono in
un'unica chiamata. Sarà la primitiva leggera per "mappare il sito":
puntala a un dominio, ottieni le pagine che vale la pena elaborare, poi
passa quell'elenco all'endpoint perceive oppure a
un job di ingest in modalità crawl.
Ecco la chiamata minima utile. Invia un URL, ricevi la sua mappa:
curl -X POST https://api.enconvert.com/v2/discover \
-H "X-API-Key: sk_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com"
}'
La risposta è un semplice elenco di URL con contatori di provenienza. Non ci sono URL firmati, né ID operazione, né polling:
{
"url": "https://example.com",
"mode": "hybrid",
"total": 47,
"urls": [
"https://example.com/",
"https://example.com/pricing",
"https://example.com/docs",
"https://example.com/blog/launch"
],
"pages_crawled": 12,
"truncated": false,
"robots_respected": false,
"sources": {"sitemap": 42, "crawl": 30},
"warnings": []
}
Endpoints#
| Metodo | Percorso | Scopo |
|---|---|---|
POST |
/v2/discover |
Mappa gli URL di un sito solo via HTTP e restituisce un elenco piatto con i conteggi per fonte. |
/v2/discover espone un solo percorso. È stateless: non c'è una riga di
operazione da recuperare né un job da interrogare, quindi non esiste un
endpoint GET di supporto come avviene per perceive.
Content-Type: application/json sulla POST.
Autenticazione#
Autenticati con una chiave privata nell'header X-API-Key per le
chiamate server-to-server. È il percorso usato negli esempi qui sotto.
X-API-Key: sk_your_private_key
Funzionano anche le chiavi pubbliche con un token bearer JWT, usando lo
stesso flusso di ogni altro endpoint: genera un token con la tua chiave
pk_, poi invialo come Authorization: Bearer <token>. Il flusso
completo, incluso il domain locking e il refresh del token, si trova
nella guida all'autenticazione.
Ogni chiave API porta con sé un'allowlist di endpoint consentiti. Se
/v2/discover non è nell'elenco della chiave, la richiesta viene
rifiutata con 403 e un messaggio che indica il percorso bloccato.
Come funziona discover#
Una richiesta viene eseguita interamente via HTTP. Il singleton Chrome
headless che alimenta perceive non viene mai
toccato. Il percorso di crawl usa la strategia di crawler HTTP di
Crawl4AI (una GET httpx più un parsing dei link con lxml per pagina),
e il percorso sitemap riutilizza gli stessi helper puramente HTTP per
sitemap e feed usati dal resto della piattaforma.
- Verifica del seed. L'URL che invii viene controllato per SSRF
prima di qualsiasi fetch: schema, credenziali incorporate, hostname
bloccati e IP risolto vengono tutti validati. Un URL che si risolve in
un indirizzo privato, loopback, link-local o di metadata cloud viene
rifiutato con
400. Il seed è sempre incluso come prima voce nella propria mappa. - Raccolta dalle sitemap. In modalità
sitemapohybrid, discover leggerobots.txte recupera gli URLSitemap:che vi sono dichiarati, sondasitemap.xml(ricorrendo nei figli<sitemapindex>), ed estrae le pagine dei feed RSS/Atom. Esegue questi controlli sia sull'host che hai inviato sia sul dominio registrabile (apex) del sito, così una sitemap pubblicata solo sull'apex viene comunque trovata a partire da un seed su un sottodominio o su un percorso profondo. Una sitemap mancante o non funzionante diventa un warning, non un errore. - Crawl via HTTP. In modalità
crawlohybrid, discover esegue una scansione breadth-first a partire dal seed fino amax_depth, raccogliendo i link<a href>dall'HTML grezzo di ogni pagina recuperata. Ogni link seguito viene sottoposto a screening SSRF prima di essere recuperato. - Normalizzazione e filtro. L'elenco grezzo combinato viene
canonicalizzato (frammenti e parametri di tracking rimossi, porte
predefinite eliminate, chiavi di query ordinate), poi passa attraverso
il controllo dello stesso dominio, i tuoi pattern regex di inclusione
ed esclusione, il filtro
robots.txt, la deduplicazione e infine il tetto dimax_urls.
Sul percorso solo HTTP, una single-page app renderizzata lato client
restituisce solo il proprio HTML shell in modalità crawl, tipicamente
il seed più zero o un URL. Il fallback opzionale render_js (vedi
Rendering JavaScript) colma questa lacuna: nella
sua impostazione predefinita "auto", discover renderizza la pagina una
volta nel browser e raccoglie i link che essa inietta a runtime ogni volta
che la scansione HTTP restituisce solo uno shell. La modalità sitemap
resta un percorso veloce e senza browser per le SPA attente alla SEO, che
di norma pubblicano una sitemap.
Parametri della richiesta#
Principali#
| Parametro | Tipo | Predefinito | Descrizione |
|---|---|---|---|
url |
string |
nessuno | Il sito da mappare. Deve iniziare con http:// o https://. Massimo 2,048 caratteri. Obbligatorio. |
mode |
string |
"hybrid" |
sitemap, crawl o hybrid. Vedi Modalità. |
max_urls |
integer |
100 |
Numero massimo di URL restituiti. 1–1,000. L'elenco viene limitato qui e truncated segnala se ne esistevano altri. |
max_depth |
integer |
2 |
Profondità di scansione dal seed, in modalità crawl/hybrid. 1–5. |
same_domain_only |
boolean |
true |
Mantiene solo gli URL sull'host del seed. Quando è false, vengono mantenuti anche i link fuori host scoperti durante la scansione. |
render_js |
string |
"auto" |
Scoperta renderizzata nel browser per siti JavaScript/SPA (solo crawl/hybrid). auto renderizza solo quando la scansione HTTP restituisce uno shell; always la forza; never resta solo HTTP. Vedi Rendering JavaScript. |
Filtri#
| Parametro | Tipo | Predefinito | Descrizione |
|---|---|---|---|
include_patterns |
string[] |
[] |
Allowlist di regex Python (semantica re.search, non glob). Un URL deve corrispondere ad almeno una per essere mantenuto. Vuoto significa consenti tutto. Massimo 50 pattern. |
exclude_patterns |
string[] |
[] |
Denylist di regex Python. Un URL che corrisponde a qualsiasi pattern viene scartato. Applicata dopo include_patterns. Massimo 50 pattern. |
respect_robots |
boolean |
false |
Quando è true, gli URL non consentiti dal robots.txt del sito vengono rimossi dall'elenco restituito. |
I pattern sono vere espressioni regolari Python, compilate al momento
della validazione. Un pattern malformato produce un 422 al bordo, non
un 500 a metà scansione. Poiché la semantica è re.search, una
semplice sottostringa come "/blog/" corrisponde ovunque nell'URL,
quindi ancorala con ^/$ se ti serve una corrispondenza posizionale.
Da segnalare subito.
respect_robotsviene applicato al momento del filtro in output, non al momento del fetch. Crawl4AI 0.8.9 non ha un gate robots nativo, quindi in modalitàcrawlohybriduna pagina non consentita può comunque essere recuperata via HTTP e poi scartata prima di raggiungere la risposta. A differenza di perceive, doverespect_robots=truerifiuta un URL non consentito con403, discover non restituisce mai403per una regola robots. Scarta silenziosamente l'URL e non riporta nulla.
Modalità#
mode |
Cosa fa |
|---|---|
sitemap |
Voci sitemap da robots.txt, sitemap.xml sondato (con ricorsione sull'indice) e pagine dei feed RSS/Atom. Istantaneo, nessuna scansione. |
crawl |
Scansione breadth-first solo HTTP a partire dal seed, che raccoglie i link <a href> dal markup grezzo. |
hybrid (predefinita) |
L'unione deduplicata di sitemap e crawl. |
La modalità crawl recupera fino al tuo max_urls completo (fino a
1,000), così un sito grande viene enumerato in un solo passaggio. La
modalità crawl è solo HTTP (nessun browser), quindi resta veloce. Gli
operatori possono abbassare il tetto con la variabile d'ambiente
DISCOVER_CRAWL_MAX_PAGES se una scansione molto grande dovesse mai
richiedere un limite. pages_crawled nella risposta ti dice esattamente
quante GET sono state eseguite.
Il fetch delle sitemap gestisce le sitemap compresse con gzip
(sitemap.xml.gz e qualsiasi sitemap servita come application/gzip),
e invia header da browser realistici, così i siti dietro un WAF hanno
molte più probabilità di restituire la loro sitemap invece di un
403/503.
Rendering JavaScript#
Le modalità crawl e hybrid leggono l'HTML grezzo che un server
restituisce, quindi una single-page app renderizzata lato client che
costruisce i propri link nel browser è invisibile per loro. render_js
attiva un fallback browser limitato che colma questa lacuna:
render_js |
Cosa fa |
|---|---|
auto (predefinito) |
Esegue prima la scansione HTTP; renderizza nel browser solo quando questa restituisce uno shell nudo (un URL o nessuno), poi raccoglie i link iniettati lato client. |
always |
Esegue sempre la scansione renderizzata nel browser. |
never |
Resta rigorosamente solo HTTP, il comportamento preesistente. |
Il fallback usa lo stesso Chrome headless condiviso di
perceive ed è limitato a poche pagine così che la
chiamata resti entro il timeout della richiesta. I link che trova vengono
conteggiati sotto la chiave crawl_js in sources. Si applica solo alle
modalità crawl e hybrid, perché la modalità sitemap è già senza
browser e non ne è influenzata.
Risposta#
POST /v2/discover restituisce direttamente questo oggetto, senza alcun
job asincrono né una seconda chiamata.
| Campo | Tipo | Descrizione |
|---|---|---|
url |
string |
L'URL seed che hai inviato. |
mode |
string |
La modalità eseguita: sitemap, crawl o hybrid. |
total |
integer |
Numero di URL in urls (dopo dedup, filtro e limite). |
urls |
string[] |
L'elenco di URL deduplicato, normalizzato e limitato. Il seed è sempre il primo candidato. |
pages_crawled |
integer |
GET HTTP emesse dalla scansione. 0 in modalità sitemap pura. |
truncated |
boolean |
true quando esistevano più URL unici di quanti ne permettesse max_urls. |
robots_respected |
boolean |
Rispecchia il valore di respect_robots che hai inviato. |
sources |
object |
Conteggio grezzo di URL per fonte prima di dedup/filtro, ad es. {"sitemap": 42, "crawl": 30}. Le chiavi includono sitemap, crawl, sitemap_apex (sitemap trovate sul dominio apex) e crawl_js (link dal fallback di rendering JavaScript). I conteggi si sovrappongono e sommano oltre total. |
warnings |
string[] |
Note non fatali: una sitemap mancante, una scansione fallita, un robots.txt irraggiungibile. |
I conteggi di sources sono grezzi: rappresentano il numero di URL
prodotti da ciascun percorso prima che venissero eseguiti la
normalizzazione, il controllo dello stesso dominio, i tuoi filtri e la
deduplicazione. Di norma sommano più di total, perché la modalità
hybrid trova le stesse pagine sia dalla sitemap sia dalla scansione.
Usali per capire quale percorso sta portando la mappa, non come conteggio
post-filtro.
Esempi di codice#
curl: mappa hybrid predefinita#
curl -X POST https://api.enconvert.com/v2/discover \
-H "X-API-Key: sk_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com"
}'
curl: solo sitemap, pagine del blog, limite a 500#
curl -X POST https://api.enconvert.com/v2/discover \
-H "X-API-Key: sk_your_private_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com",
"mode": "sitemap",
"max_urls": 500,
"include_patterns": ["/blog/"],
"exclude_patterns": ["/tag/", "/author/"],
"respect_robots": true
}'
Python#
import requests
response = requests.post(
"https://api.enconvert.com/v2/discover",
headers={"X-API-Key": "sk_your_private_key"},
json={
"url": "https://example.com",
"mode": "hybrid",
"max_urls": 200,
"include_patterns": [r"/docs/"],
},
)
response.raise_for_status()
data = response.json()
print(f"found {data['total']} URLs from {data['sources']}")
for page_url in data["urls"]:
print(page_url)
Node.js#
const res = await fetch("https://api.enconvert.com/v2/discover", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": "sk_your_private_key"
},
body: JSON.stringify({
url: "https://example.com",
mode: "hybrid",
max_urls: 200,
include_patterns: ["/docs/"]
})
});
const data = await res.json();
console.log(`found ${data.total} URLs from`, data.sources);
data.urls.forEach((pageUrl) => console.log(pageUrl));
Uno schema comune è scoprire prima e poi renderizzare: prendi data.urls
e passalo all'endpoint perceive, con chiamate
singole per una manciata di pagine oppure il suo percorso batch per
l'intero elenco.
Risposte di errore#
| Stato | Condizione |
|---|---|
400 Bad Request |
L'URL non è http(s), contiene credenziali incorporate, non ha hostname, oppure si risolve in un indirizzo privato, loopback, link-local o di metadata cloud (protezione SSRF). |
401 Unauthorized |
Chiave API / token JWT mancante o non valido. |
402 Payment Required |
Discover non è abilitato sul tuo piano attuale, oppure la tua quota mensile di ops è esaurita. Ogni chiamata a /v2/discover addebita una op. |
403 Forbidden |
/v2/discover non è tra gli endpoint consentiti della chiave API. |
422 Unprocessable Entity |
Validazione della richiesta fallita: enum mode non valido, max_urls fuori da 1–1,000, max_depth fuori da 1–5, oltre 50 pattern include/exclude, una regex malformata, oppure un url oltre 2,048 caratteri. |
500 Internal Server Error |
La scoperta degli URL è fallita inaspettatamente. Il client riceve un messaggio generico; il dettaglio completo va solo nei log del server. |
Nota che un fetch della sitemap fallito o un errore di scansione non
producono uno stato di errore. Questi degradano a voci nell'array
warnings, e la richiesta restituisce comunque 200 con tutto ciò che è
stato trovato. Il riferimento completo dei codici di stato è nella
guida ai codici di errore.
Limiti#
| Limite | Valore |
|---|---|
| Lunghezza URL | 2,048 caratteri |
max_urls |
1–1,000 (predefinito 100) |
max_depth |
1–5 (predefinito 2) |
include_patterns |
Massimo 50 pattern |
exclude_patterns |
Massimo 50 pattern |
| Pagine recuperate in modalità crawl | fino a max_urls (max 1,000; abbassabile con DISCOVER_CRAWL_MAX_PAGES) |
| Timeout richiesta | 300 secondi |
| Ops per chiamata | 1, addebitata sulla quota mensile unificata |
Domande frequenti#
Come elenco tutti gli URL di un sito web con un'API?#
Invia POST /v2/discover con l'URL del sito. La modalità predefinita
hybrid combina il parsing della sitemap (voci robots.txt,
sitemap.xml con ricorsione sull'indice, feed RSS/Atom) con una
scansione HTTP breadth-first, e restituisce fino a max_urls (1–1,000,
predefinito 100) URL deduplicati in un'unica risposta sincrona.
L'endpoint discover usa un browser headless o renderizza JavaScript?#
Per impostazione predefinita viene eseguito via HTTP e renderizza solo
quando è necessario. L'opzione render_js controlla questo comportamento:
nella modalità predefinita "auto", discover resta solo HTTP e renderizza
una pagina nel browser solo quando la scansione HTTP restituisce uno shell
JavaScript nudo, raccogliendo i link iniettati lato client; "always"
forza la scansione nel browser e "never" la mantiene rigorosamente solo
HTTP. La modalità sitemap resta un'opzione veloce e senza browser per le
SPA attente alla SEO.
Quante pagine recupera effettivamente la modalità crawl?#
La modalità crawl recupera fino al tuo max_urls completo (fino a
1,000). Resta solo HTTP, quindi rimane veloce; gli operatori possono
abbassare il tetto con la variabile d'ambiente
DISCOVER_CRAWL_MAX_PAGES. Ogni pagina recuperata contribuisce inoltre
con molti link. Il campo pages_crawled della risposta riporta
esattamente quante GET HTTP sono state eseguite.
Posso filtrare quali URL vengono restituiti?#
Sì. include_patterns e exclude_patterns accettano fino a 50 regex
Python ciascuno (semantica re.search, non glob), e
respect_robots: true rimuove dall'elenco restituito gli URL non
consentiti dal robots.txt del sito.