API de crawl de sitemap#
POST /v2/discover est une API de crawl de sitemap qui liste les URLs
d'un site à moindre coût : un crawl en priorité HTTP combiné à un
parsing de sitemap, avec un repli de rendu JavaScript optionnel pour les
applications monopage (SPA). Il n'y a ni capture d'écran, ni PDF, ni
artefact stocké. Elle renvoie une liste plate et dédupliquée
d'URLs ainsi qu'un décompte de la provenance de chacune, de façon
synchrone en un seul appel. Ce sera la primitive légère « cartographier
le site » : pointez-la vers un domaine, récupérez les pages qui
méritent d'être traitées, puis injectez cette liste dans
l'endpoint perceive ou dans un job d'ingestion en
mode crawl.
Voici l'appel minimal utile. Envoyez une URL, récupérez sa carte :
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 réponse est une simple liste d'URLs avec des compteurs de provenance. Il n'y a pas d'URLs signées, pas d'ID d'opération et pas de 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#
| Méthode | Chemin | Objectif |
|---|---|---|
POST |
/v2/discover |
Cartographie les URLs d'un site en HTTP uniquement et renvoie une liste plate avec des compteurs par source. |
/v2/discover expose un seul chemin. Il est sans état : il n'y a
aucune ligne d'opération à récupérer ni aucun job à interroger, donc il
n'existe pas d'endpoint GET compagnon comme
c'est le cas pour perceive.
Content-Type : application/json sur le POST.
Authentification#
Authentifiez-vous avec une clé privée dans l'en-tête X-API-Key pour
les appels serveur à serveur. C'est la voie utilisée par les exemples
ci-dessous.
X-API-Key: sk_your_private_key
Les clés publiques avec un jeton bearer JWT fonctionnent également,
selon le même flux que tous les autres endpoints : générez un jeton
avec votre clé pk_, puis envoyez-le en tant que
Authorization: Bearer <token>. Le flux complet, y compris le
verrouillage de domaine et le renouvellement du jeton, se trouve dans
le guide d'authentification.
Chaque clé API dispose d'une liste d'endpoints autorisés. Si
/v2/discover ne figure pas dans la liste de la clé, la requête est
rejetée avec 403 et un message précisant le chemin bloqué.
Fonctionnement de discover#
Une requête s'exécute entièrement en HTTP. Le Chrome headless
singleton qui alimente perceive n'est jamais
sollicité. Le chemin de crawl utilise la stratégie de crawler HTTP de
Crawl4AI (un GET httpx suivi d'un parsing de liens lxml par
page), et le chemin sitemap réutilise les mêmes helpers sitemap et
feed purement HTTP que le reste de la plateforme.
- Filtrer l'URL de départ. L'URL que vous envoyez est vérifiée
contre le SSRF avant toute requête : le schéma, les identifiants
intégrés, les noms d'hôte bloqués et l'IP résolue sont tous
validés. Une URL qui résout vers une adresse privée, loopback,
link-local ou de métadonnées cloud est rejetée avec
400. L'URL de départ est toujours incluse comme première entrée de sa propre carte. - Collecter depuis les sitemaps. En mode
sitemapouhybrid, discover litrobots.txtet récupère les URLsSitemap:qu'il déclare, sondesitemap.xml(en récursant dans les enfants<sitemapindex>), et récupère les pages de flux RSS/Atom. Elle exécute ces sondes à la fois contre l'hôte que vous avez envoyé et contre le domaine enregistrable (apex) du site, de sorte qu'un sitemap publié uniquement sur l'apex est quand même trouvé depuis un sous-domaine ou une URL de départ à chemin profond. Un sitemap manquant ou cassé devient un avertissement, pas une erreur. - Crawler en HTTP. En mode
crawlouhybrid, discover exécute un crawl en largeur depuis l'URL de départ jusqu'àmax_depth, en récupérant les liens<a href>de chaque page brute récupérée. Chaque lien suivi est filtré contre le SSRF avant d'être récupéré. - Normaliser et filtrer. La liste brute combinée est
canonicalisée (fragments et paramètres de tracking supprimés, ports
par défaut retirés, clés de requête triées), puis passée par la
vérification du même domaine, vos motifs regex d'inclusion et
d'exclusion, le filtre
robots.txt, la déduplication, et enfin le plafondmax_urls.
Sur le chemin HTTP uniquement, une application monopage (SPA) rendue
côté client ne renvoie que sa coquille HTML en mode crawl,
typiquement l'URL de départ plus zéro ou une URL. Le repli optionnel
render_js (voir Rendu JavaScript) comble
cette lacune : dans son réglage "auto" par défaut, discover effectue
le rendu de la page une fois dans le navigateur et récolte les liens
qu'elle injecte à l'exécution chaque fois que le crawl HTTP ne renvoie
qu'une coquille. Le mode sitemap reste une voie rapide et sans
navigateur pour les SPA soucieuses du SEO, qui publient généralement un
sitemap.
Paramètres de la requête#
Paramètres de base#
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
url |
string |
aucun | Le site à cartographier. Doit commencer par http:// ou https://. Max 2,048 caractères. Obligatoire. |
mode |
string |
"hybrid" |
sitemap, crawl ou hybrid. Voir Modes. |
max_urls |
integer |
100 |
Nombre maximum d'URLs renvoyées. De 1 à 1,000. La liste est plafonnée ici et truncated l'indique si davantage existait. |
max_depth |
integer |
2 |
Profondeur de crawl depuis l'URL de départ, en mode crawl/hybrid. De 1 à 5. |
same_domain_only |
boolean |
true |
Ne conserve que les URLs sur l'hôte de l'URL de départ. Quand false, les liens hors hôte découverts pendant le crawl sont aussi conservés. |
render_js |
string |
"auto" |
Découverte par rendu navigateur pour les sites JavaScript/SPA (crawl/hybrid uniquement). auto n'effectue le rendu que lorsque le crawl HTTP renvoie une coquille ; always le force ; never reste en HTTP uniquement. Voir Rendu JavaScript. |
Filtrage#
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
include_patterns |
string[] |
[] |
Liste d'autorisation de regex Python (sémantique re.search, pas de glob). Une URL doit correspondre à au moins un motif pour être conservée. Vide signifie tout autoriser. Max 50 motifs. |
exclude_patterns |
string[] |
[] |
Liste de blocage de regex Python. Une URL correspondant à un motif quelconque est écartée. Appliqué après include_patterns. Max 50 motifs. |
respect_robots |
boolean |
false |
Quand true, les URLs interdites par le robots.txt du site sont retirées de la liste renvoyée. |
Les motifs sont de véritables expressions régulières Python, compilées
au moment de la validation. Un motif malformé produit un 422 en
amont, pas un 500 en plein crawl. Comme la sémantique est celle de
re.search, une simple sous-chaîne comme "/blog/" correspond
n'importe où dans l'URL, donc ancrez avec ^/$ si vous avez besoin
d'une correspondance positionnelle.
À signaler d'emblée.
respect_robotsest appliqué au moment du filtrage de sortie, pas au moment de la récupération. Crawl4AI 0.8.9 n'a pas de blocage robots natif, donc en modecrawlouhybridune page interdite peut quand même être récupérée en HTTP puis écartée avant d'atteindre la réponse. Contrairement à perceive, oùrespect_robots=truerejette une URL interdite avec403, discover ne renvoie jamais403pour une règle robots. Elle retire l'URL en silence et ne le signale nulle part.
Modes#
mode |
Ce que ça fait |
|---|---|
sitemap |
Entrées sitemap de robots.txt, sitemap.xml sondé (avec récursion d'index), et pages de flux RSS/Atom. Instantané, sans crawl. |
crawl |
Crawl HTTP pur en largeur depuis l'URL de départ, récupérant les liens <a href> du balisage brut. |
hybrid (par défaut) |
L'union dédupliquée de sitemap et crawl. |
Le mode crawl récupère jusqu'à votre max_urls complet (jusqu'à
1,000), de sorte qu'un grand site est énuméré en une seule passe. Le
mode crawl est purement HTTP (pas de navigateur), donc cela reste
rapide. Les opérateurs peuvent abaisser ce plafond avec la variable
d'environnement DISCOVER_CRAWL_MAX_PAGES si un très grand crawl doit
un jour être borné. pages_crawled dans la réponse vous indique
exactement combien de GET ont été exécutés.
La récupération de sitemap gère les sitemaps compressés en gzip
(sitemap.xml.gz et tout sitemap servi en application/gzip), et
envoie des en-têtes de navigateur réalistes, de sorte que les sites
derrière un WAF sont bien plus susceptibles de renvoyer leur sitemap
plutôt qu'un 403/503.
Rendu JavaScript#
Les modes crawl et hybrid lisent le HTML brut renvoyé par un
serveur, de sorte qu'une application monopage (SPA) rendue côté client,
qui construit ses liens dans le navigateur, leur est invisible.
render_js active un repli navigateur borné qui comble cette lacune :
render_js |
Ce que ça fait |
|---|---|
auto (par défaut) |
Exécute d'abord le crawl HTTP ; n'effectue le rendu dans le navigateur que lorsqu'il ne renvoie qu'une coquille nue (une URL ou aucune), puis récolte les liens injectés côté client. |
always |
Exécute toujours le crawl par rendu navigateur. |
never |
Reste strictement en HTTP uniquement, le comportement préexistant. |
Le repli utilise le même Chrome headless partagé que
perceive et est plafonné à quelques pages afin
que l'appel reste dans le timeout de la requête. Les liens qu'il trouve
sont comptabilisés sous la clé crawl_js dans sources. Il s'applique
aux modes crawl et hybrid uniquement, car le mode sitemap est
déjà sans navigateur et n'est pas affecté.
Réponse#
POST /v2/discover renvoie directement cet objet, sans job asynchrone
ni second appel.
| Champ | Type | Description |
|---|---|---|
url |
string |
L'URL de départ que vous avez envoyée. |
mode |
string |
Le mode exécuté : sitemap, crawl ou hybrid. |
total |
integer |
Nombre d'URLs dans urls (après déduplication, filtrage et plafonnement). |
urls |
string[] |
La liste d'URLs dédupliquée, normalisée et plafonnée. L'URL de départ est toujours le premier candidat. |
pages_crawled |
integer |
GET HTTP émis par le crawl. 0 en mode sitemap pur. |
truncated |
boolean |
true quand il existait plus d'URLs uniques que max_urls n'en autorisait. |
robots_respected |
boolean |
Reprend la valeur de respect_robots que vous avez envoyée. |
sources |
object |
Décompte brut d'URLs par source avant déduplication/filtrage, ex. {"sitemap": 42, "crawl": 30}. Les clés incluent sitemap, crawl, sitemap_apex (sitemaps trouvés sur le domaine apex) et crawl_js (liens issus du repli de rendu JavaScript). Les décomptes se chevauchent et leur somme dépasse total. |
warnings |
string[] |
Notes non bloquantes : un sitemap manquant, un crawl en échec, un robots.txt inaccessible. |
Les décomptes de sources sont bruts : ce sont les nombres d'URLs
produits par chaque chemin avant la normalisation, la vérification du
même domaine, vos filtres et la déduplication. Ils dépassent
régulièrement total, parce que le mode hybrid retrouve les mêmes
pages à la fois via le sitemap et le crawl. Utilisez-les pour voir
quel chemin porte la carte, pas comme un décompte post-filtrage.
Exemples de code#
curl : carte hybride par défaut#
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 : sitemap uniquement, pages de blog, plafonné à 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));
Un pattern courant consiste à découvrir d'abord, puis à rendre :
prenez data.urls et transmettez-les à
l'endpoint perceive, avec des appels individuels
pour une poignée de pages ou son chemin batch pour la liste entière.
Réponses d'erreur#
| Statut | Condition |
|---|---|
400 Bad Request |
L'URL n'est pas en http(s), contient des identifiants intégrés, n'a pas de nom d'hôte, ou résout vers une adresse privée, loopback, link-local ou de métadonnées cloud (protection SSRF). |
401 Unauthorized |
Clé API / jeton JWT manquant ou invalide. |
402 Payment Required |
Discover n'est pas activé sur votre plan actuel, ou votre quota mensuel d'ops est épuisé. Chaque appel /v2/discover facture une op. |
403 Forbidden |
/v2/discover ne figure pas dans les endpoints autorisés de la clé API. |
422 Unprocessable Entity |
Échec de validation de la requête : énumération mode invalide, max_urls en dehors de la plage 1 à 1,000, max_depth en dehors de la plage 1 à 5, plus de 50 motifs include/exclude, une regex malformée, ou une url de plus de 2,048 caractères. |
500 Internal Server Error |
La découverte d'URLs a échoué de façon inattendue. Le client reçoit un message générique ; le détail complet ne va que dans les logs serveur. |
À noter qu'un échec de récupération du sitemap ou un incident de crawl
ne produit pas de statut d'erreur. Ces cas dégradent en entrées dans
le tableau warnings, et la requête renvoie quand même 200 avec ce
qui a été trouvé. La référence complète des codes de statut se trouve
dans le guide des codes d'erreur.
Limites#
| Limite | Valeur |
|---|---|
| Longueur d'URL | 2,048 caractères |
max_urls |
de 1 à 1,000 (défaut 100) |
max_depth |
de 1 à 5 (défaut 2) |
include_patterns |
50 motifs max |
exclude_patterns |
50 motifs max |
| Pages récupérées en mode crawl | jusqu'à max_urls (max 1,000 ; à abaisser avec DISCOVER_CRAWL_MAX_PAGES) |
| Timeout de requête | 300 secondes |
| Ops par appel | 1, facturée sur le quota mensuel unifié |
Foire aux questions#
Comment lister toutes les URLs d'un site web avec une API ?#
Envoyez POST /v2/discover avec l'URL du site. Le mode hybrid par défaut combine le parsing de sitemap (entrées robots.txt, sitemap.xml avec récursion d'index, flux RSS/Atom) avec un crawl HTTP en largeur, et renvoie jusqu'à max_urls (de 1 à 1,000, défaut 100) URLs dédupliquées en une seule réponse synchrone.
L'endpoint discover utilise-t-il un navigateur headless ou effectue-t-il du rendu JavaScript ?#
Par défaut, il s'exécute en HTTP et n'effectue le rendu que lorsqu'il le faut. L'option render_js contrôle cela : dans le mode "auto" par défaut, discover reste en HTTP uniquement et n'effectue le rendu d'une page dans le navigateur que lorsque le crawl HTTP renvoie une coquille JavaScript nue, en récoltant les liens injectés côté client ; "always" force le crawl par navigateur et "never" le maintient strictement en HTTP uniquement. Le mode sitemap reste une option rapide et sans navigateur pour les SPA soucieuses du SEO.
Combien de pages le mode crawl récupère-t-il réellement ?#
Le mode crawl récupère jusqu'à votre max_urls complet (jusqu'à 1,000). Il reste purement HTTP, donc il reste rapide ; les opérateurs peuvent abaisser ce plafond avec la variable d'environnement DISCOVER_CRAWL_MAX_PAGES. Chaque page récupérée apporte en plus de nombreux liens. Le champ pages_crawled de la réponse indique exactement combien de GET HTTP ont été exécutés.
Puis-je filtrer les URLs renvoyées ?#
Oui. include_patterns et exclude_patterns acceptent jusqu'à 50 regex Python chacun (sémantique re.search, pas de glob), et respect_robots: true retire de la liste renvoyée les URLs interdites par le robots.txt du site.