AnyCrawl

Crawl

Parcourez un site entier et transformez-le en données structurées prêtes pour les LLM.

Introduction

L’API crawl AnyCrawl découvre et traite plusieurs pages à partir d’une URL de départ, en appliquant le même pipeline d’extraction par page que /v1/scrape. Elle est asynchrone : vous recevez immédiatement un job_id, puis interrogez l’état et récupérez les résultats par pages.

Points clés

  • Jobs asynchrones : mettez un crawl en file et récupérez les résultats plus tard
  • Multi-moteurs : auto (défaut), cheerio, playwright, puppeteer
  • Contrôle de portée : strategy, max_depth, include_paths, exclude_paths
  • Options par page : réutilisez les options de /v1/scrape dans scrape_options
  • Pagination : flux de résultats via skip pour limiter la taille des réponses

Points de terminaison de l’API

POST    https://api.anycrawl.dev/v1/crawl
GET     https://api.anycrawl.dev/v1/crawl/{jobId}/status
GET     https://api.anycrawl.dev/v1/crawl/{jobId}?skip=0
DELETE  https://api.anycrawl.dev/v1/crawl/{jobId}

Exemples d’utilisation

Créer un job de crawl

curl -X POST "https://api.anycrawl.dev/v1/crawl" \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://anycrawl.dev",
    "engine": "cheerio",
    "strategy": "same-domain",
    "max_depth": 5,
    "limit": 100,
    "exclude_paths": ["/blog/*"],
    "scrape_options": {
      "formats": ["markdown"],
      "timeout": 60000
    }
  }'

Scraping sélectif avec scrape_paths

Utilisez scrape_paths pour visiter des pages afin de découvrir des liens sans extraire le contenu. Cela réduit les coûts et le stockage :

curl -X POST "https://api.anycrawl.dev/v1/crawl" \
  -H "Authorization: Bearer <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://shop.example.com",
    "engine": "cheerio",
    "strategy": "same-domain",
    "max_depth": 5,
    "limit": 200,
    "include_paths": ["/*"],
    "scrape_paths": ["/products/*/details", "/products/*/reviews"],
    "scrape_options": {
      "formats": ["markdown", "json"]
    }
  }'

Dans cet exemple :

  • Toutes les pages correspondant à /* sont visitées pour découvrir les liens
  • Seules les pages correspondant à /products/*/details ou /products/*/reviews ont leur contenu extrait et enregistré
  • Les pages catégories, navigation, etc. sont crawlées mais pas scrapées, ce qui économise crédits et stockage
const start = await fetch("https://api.anycrawl.dev/v1/crawl", {
    method: "POST",
    headers: {
        Authorization: "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    body: JSON.stringify({
        url: "https://anycrawl.dev",
        engine: "cheerio",
        strategy: "same-domain",
        max_depth: 5,
        limit: 100,
        exclude_paths: ["/blog/*"],
        scrape_options: { formats: ["markdown"], timeout: 60000 },
    }),
});
const startResult = await start.json();
const jobId = startResult.data.job_id;

Interroger l’état

curl -H "Authorization: Bearer <YOUR_API_KEY>" \
  "https://api.anycrawl.dev/v1/crawl/7a2e165d-8f81-4be6-9ef7-23222330a396/status"

Récupérer les résultats (paginés)

curl -H "Authorization: Bearer <YOUR_API_KEY>" \
  "https://api.anycrawl.dev/v1/crawl/7a2e165d-8f81-4be6-9ef7-23222330a396?skip=0"

Annuler un job

curl -X DELETE -H "Authorization: Bearer <YOUR_API_KEY>" \
  "https://api.anycrawl.dev/v1/crawl/7a2e165d-8f81-4be6-9ef7-23222330a396"

Paramètres de requête

ParamètreTypeObligatoireDéfautDescription
urlstringOui-URL de départ du crawl
template_idstringNon-ID du modèle à utiliser pour ce crawl
variablesobjectNon-Variables du modèle (uniquement si template_id est fourni)
engineenumNonautoMoteur de scraping par page : auto, cheerio, playwright, puppeteer
exclude_pathsarray of stringNon-Règles de chemins à exclure (style glob), ex. /blog/*
include_pathsarray of stringNon-Règles de chemins à inclure pour le crawl (après exclusion)
scrape_pathsarray of stringNon-Règles pour l’extraction de contenu. Seules les URL correspondantes sont enregistrées. Si absent, toutes les URL incluses sont scrapées
max_depthnumberNon10Profondeur max depuis l’URL de départ
strategyenumNonsame-domainPortée : all, same-domain, same-hostname, same-origin
limitnumberNon100Nombre maximum de pages à crawler
max_agenumberNon-Durée de vie max du cache (ms). Utilisez 0 pour ignorer la lecture du cache ; omis = défaut serveur
store_in_cachebooleanNontrueÉcrire ou non le cache de page pour les scrapes par page
retrybooleanNonfalseRéessayer ou non en cas d’échec
proxystring (URI)Non-URL de proxy optionnelle
formatsarray of enumNon["markdown"]Formats de sortie pour les scrapes par page
timeoutnumberNon60000Délai d’attente par requête (ms)
wait_fornumberNon-Délai avant extraction (ms) ; moteurs navigateur uniquement
wait_untilenumNon-Condition d’attente de navigation : load, domcontentloaded, networkidle, commit
wait_for_selectorstring, object, or arrayNon-Attendre un ou plusieurs sélecteurs (moteurs navigateur uniquement). Priorité sur wait_for.
include_tagsarray of stringNon-N’inclure que les éléments correspondant aux sélecteurs CSS
exclude_tagsarray of stringNon-Exclure les éléments correspondant aux sélecteurs CSS
only_main_contentbooleanNontrueExtraire uniquement le contenu principal (en-têtes, pieds, navigation, etc. exclus)
json_optionsobjectNon-Options d’extraction JSON structurée (schema, user_prompt, schema_name, schema_description)
extract_sourceenumNonmarkdownSource pour extraire le JSON : markdown (défaut) ou html
ocr_optionsbooleanNonfalseOCR pour les images markdown uniquement. Affecte le markdown, pas html/rawHtml.
scrape_optionsobjectNon-Options de scrape par page (mêmes champs que /v1/scrape sans url/engine de niveau supérieur)

Champs scrape_options

| Champ | Type | Défaut | Notes | | ------------------- | ------------------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | --------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | formats | array of enum | ["markdown"] | Formats : markdown, html, text, screenshot, screenshot@fullPage, rawHtml, json, summary, links | | timeout | number | 60000 | Délai par requête (ms) | | wait_for | number | - | Délai avant extraction (ms) ; navigateur ; priorité inférieure à wait_for_selector | | wait_for_selector | string, object, or array | - | Attendre un ou plusieurs sélecteurs (navigateur). Chaîne CSS, objet { selector, state?, timeout? }, ou tableau. Chaque entrée attendue séquentiellement. Priorité sur wait_for. | | include_tags | array of string | - | N’inclure que les éléments correspondant aux sélecteurs CSS | | exclude_tags | array of string | - | Exclure les éléments correspondant aux sélecteurs CSS | | only_main_content | boolean | true | Contenu principal uniquement | | proxy | string (URI) | - | URL de proxy optionnelle | | json_options | object | - | Options d’extraction JSON structurée | | extract_source | enum | markdown | Source JSON : markdown (défaut) ou html | | ocr_options | boolean | false | OCR pour images markdown uniquement. | | max_age | number | - | Cache max (ms). 0 ignore la lecture du cache. | | store_in_cache | boolean | true | Écrire le cache de page pour les scrapes par page |

Comportement du cache

  • Le crawl ne lit pas actuellement le cache de page, mais peut toujours écrire.
  • Si vous passez scrape_options, définissez-y les contrôles de cache.

Format des réponses

1) Création (HTTP 200)

{
    "success": true,
    "data": {
        "job_id": "7a2e165d-8f81-4be6-9ef7-23222330a396",
        "status": "created",
        "message": "Crawl job has been queued for processing"
    }
}

Erreurs possibles

  • 400 Erreur de validation
{
    "success": false,
    "error": "Validation error",
    "message": "Invalid enum value...",
    "data": {
        "type": "validation_error",
        "issues": [
            { "field": "engine", "message": "Invalid enum value", "code": "invalid_enum_value" }
        ],
        "status": "failed"
    }
}
  • 401 Erreur d’authentification
{ "success": false, "error": "Invalid API key" }

2) État (HTTP 200)

{
    "success": true,
    "message": "Job status retrieved successfully",
    "data": {
        "job_id": "7a2e165d-8f81-4be6-9ef7-23222330a396",
        "status": "completed",
        "start_time": "2025-05-25T07:56:44.162Z",
        "expires_at": "2025-05-26T07:56:44.162Z",
        "credits_used": 0,
        "total": 120,
        "completed": 30,
        "failed": 2
    }
}

3) Page de résultats (HTTP 200)

{
    "success": true,
    "status": "pending",
    "total": 120,
    "completed": 30,
    "credits_used": 12,
    "next": "https://api.anycrawl.dev/v1/crawl/7a2e165d-8f81-4be6-9ef7-23222330a396?skip=100",
    "data": [
        {
            "url": "https://anycrawl.dev/",
            "title": "AnyCrawl",
            "markdown": "# AnyCrawl...",
            "timestamp": "2025-05-25T07:56:44.162Z"
        }
    ]
}

Erreurs possibles

  • 400 ID de job invalide / introuvable
{ "success": false, "error": "Invalid job ID", "message": "Job ID must be a valid UUID" }

4) Annulation (HTTP 200)

{
    "success": true,
    "message": "Job cancelled successfully",
    "data": { "job_id": "7a2e165d-8f81-4be6-9ef7-23222330a396", "status": "cancelled" }
}

Erreurs possibles

  • 404 Introuvable
  • 409 Job déjà terminé
{
    "success": false,
    "error": "Job already finished",
    "message": "Finished jobs cannot be cancelled"
}

Bonnes pratiques

  • Utilisez /v1/scrape pour les pages uniques afin de limiter le coût ; utilisez /v1/crawl pour les données à l’échelle du site.
  • Ajustez strategy, max_depth et les règles de chemins pour contrôler la portée et le coût.
  • Utilisez scrape_paths pour réduire les coûts : crawler navigation / catégories pour les liens, ne scraper que les pages de contenu.
  • Utilisez formats pour limiter la taille de sortie à ce dont vous avez besoin.
  • Paginez avec skip pour éviter des réponses trop volumineuses.

Optimisation des coûts avec scrape_paths

Le paramètre scrape_paths permet d’optimiser le coût du crawl :

Sans scrape_paths (défaut) :

  • Toutes les pages incluses → visitées + contenu extrait + enregistré

Avec scrape_paths :

  • Pages dans include_paths mais pas dans scrape_paths → visitées uniquement (découverte de liens)
  • Pages à la fois dans include_paths et scrape_paths → visitées + contenu extrait + enregistré

Exemples :

  • E-commerce : crawler toutes les catégories, ne scraper que les fiches produit
  • Documentation : visiter toute la navigation, n’extraire que le contenu des articles
  • Sites d’actualités : parcourir les rubriques, n’enregistrer que les articles complets

Exemple de gestion d’erreurs

async function fetchAllResults(jobId) {
    let skip = 0;
    while (true) {
        const res = await fetch(`https://api.anycrawl.dev/v1/crawl/${jobId}?skip=${skip}`);
        if (!res.ok) {
            const err = await res.json().catch(() => ({}));
            throw new Error(err.message || `HTTP ${res.status}`);
        }
        const page = await res.json();
        // handle page.data here
        if (!page.next) break;
        const next = new URL(page.next);
        skip = Number(next.searchParams.get("skip") || 0);
    }
}

Utilisation à forte concurrence

La file de crawl accepte des jobs concurrents. Soumettez plusieurs crawls et interrogez-les indépendamment :

const seeds = ["https://site-a.com", "https://site-b.com", "https://site-c.com"];
const jobs = await Promise.all(
    seeds.map((url) =>
        fetch("https://api.anycrawl.dev/v1/crawl", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ url, engine: "cheerio" }),
        }).then((r) => r.json())
    )
);

FAQ

En quoi /v1/crawl diffère-t-il de /v1/scrape ?

/v1/scrape récupère une URL unique de façon synchrone et renvoie le contenu immédiatement. /v1/crawl découvre plusieurs pages depuis une URL de départ et s’exécute de façon asynchrone.

Comment limiter la portée et le coût ?

Utilisez strategy, max_depth, limit et les règles de chemins (include_paths, exclude_paths, scrape_paths).

Différence entre include_paths et scrape_paths ?

  • include_paths : contrôle quelles URL sont visitées (découverte de liens)
  • scrape_paths : contrôle quelles URL ont leur contenu extrait et enregistré

Si scrape_paths n’est pas défini, toutes les URL incluses sont scrapées (comportement rétrocompatible).

Comment réduire les coûts de crawl ?

Utilisez scrape_paths pour visiter navigation / catégories sans enregistrer leur contenu. Extrayez et enregistrez uniquement les pages correspondant à vos motifs scrape_paths.

Comment paginer les résultats ?

Utilisez le paramètre de requête skip. Si la réponse contient next, suivez-le pour la page suivante.

Pourquoi certains jobs ne renvoient pas html/markdown ?

Vérifiez que les formats souhaités sont dans scrape_options.formats et que le moteur choisi les prend en charge.

Valeurs de statut

Le status du job suit les valeurs du modèle de job :

StatutSignification
pendingJob en file ou en cours (pas encore terminé)
completedJob terminé avec succès
failedJob terminé avec une erreur
cancelledJob annulé ; aucun traitement ultérieur

OpenAPI (généré automatiquement)

Voir la référence API pour la documentation générée :

  • POST /v1/crawl
  • GET /v1/crawl/{jobId}/status
  • GET /v1/crawl/{jobId}
  • DELETE /v1/crawl/{jobId}