Une grande partie du contenu que vous souhaitez extraire d'une page ne figure pas dans la première réponse. Les flux sociaux, les grilles de produits, les résultats de recherche et les listes d'avis chargent souvent une poignée d'éléments, puis en récupèrent et en rendent davantage seulement lorsque vous faites défiler vers le bas. Ce schéma, le défilement infini, maintient la page initiale légère, mais cela signifie aussi qu'une seule requête HTTP ne vous donne qu'une fraction des données visibles dans un navigateur.

Ce guide vous montre comment faire défiler un site web pendant le crawl avec JavaScript et Node.js. Vous construisez un petit scraper exécutable qui pilote le défilement via la Crawling API en utilisant ses options scroll et scroll_interval, laisse la page charger davantage d'éléments, puis analyse le contenu chargé avec Cheerio et l'exporte. Le tutoriel utilise une URL de liste neutre comme exemple pour que vous puissiez remplacer par votre propre cible publique, et il se limite aux données publiques uniquement.

Ce que vous allez construire

Un script Node.js qui pointe vers une page de liste publique à défilement infini, demande à la Crawling API de la rendre et de continuer à défiler pendant un nombre défini de secondes pour que davantage d'éléments se chargent, puis extrait un enregistrement structuré par élément depuis le HTML renvoyé. L'exemple de référence extrait une liste publique générique avec ces champs :

  • Titre le titre ou le titre principal de l'élément affiché sur la carte.
  • Sous-titre une ligne secondaire telle qu'un vendeur, un auteur ou une catégorie, quand présente.
  • Prix le prix ou la valeur listés, quand la carte en affiche un.
  • Lien l'URL absolue vers la page de l'élément individuel.
  • Nombre de résultats un compteur résumant le nombre d'éléments que la page signale.

Pourquoi une simple requête rate le contenu défilé

Envoyez une simple requête HTTP vers une page à défilement infini et vous récupérez le balisage renvoyé par le serveur avant tout défilement. C'est généralement le premier lot d'éléments et rien de plus. Le reste de la liste est récupéré par le JavaScript de la page lui-même en réponse aux événements de défilement, souvent via des appels AJAX en arrière-plan, et inséré dans le DOM seulement après que le navigateur fait défiler vers le bas. Une requête qui ne défile jamais ne déclenche jamais ces appels, les éléments supplémentaires n'existent donc jamais dans le HTML que vous recevez.

Pour obtenir la liste complète, deux choses doivent se produire en une seule requête. La page doit se rendre dans un vrai navigateur, et ce navigateur doit faire défiler suffisamment loin, assez longtemps, pour déclencher chaque cycle de chargement différé. Vous pouvez construire cela vous-même avec un navigateur sans tête qui défile en boucle et attend entre les passes, plus un pool d'IPs rotatives pour que la cible identifie le trafic comme un vrai visiteur. La Crawling API regroupe tout cela en un seul appel : vous envoyez l'URL avec les options de défilement définies, elle rend et fait défiler la page côté serveur derrière une IP de confiance, et renvoie le HTML entièrement chargé pour que vous l'analysiez avec Cheerio.

Trois éléments à connaître

Trois choses font fonctionner le défilement via la Crawling API. Le token JavaScript rend la page dans un vrai navigateur. L'option scroll demande à l'API de faire défiler la page après le chargement. L'option scroll_interval définit combien de secondes elle continue à défiler, jusqu'à un maximum de 60 ; après cela, l'API capture la page chargée et la renvoie.

Prérequis

Quelques éléments doivent être en place avant d'écrire du code. Aucun ne prend longtemps.

JavaScript de base et Node.js. Vous devez être à l'aise pour écrire et exécuter un script Node et installer des paquets avec npm. Si vous êtes plutôt débutant, notre guide pour construire un scraper web avec Node.js couvre les fondamentaux que ce tutoriel suppose.

Node.js 16 ou supérieur. Vérifiez votre version avec node --version. Si vous ne l'avez pas, installez-le depuis le site Node.js ou via un gestionnaire de versions comme nvm.

Un compte Crawlbase et un token JavaScript. Inscrivez-vous, ouvrez votre tableau de bord et copiez votre token JavaScript. Le niveau gratuit vous donne jusqu'à 5 000 requêtes sans carte, et vous ne payez que pour les requêtes réussies. Les requêtes JavaScript coûtent plus de crédits que les normales car elles rendent la page, ce qui compte quand vous faites défiler. Traitez le token comme un mot de passe et gardez-le hors du contrôle de version.

Configurer le projet

Créez un dossier de projet, initialisez-le et installez les deux bibliothèques dont le scraper a besoin.

bash
node --version

mkdir scroll-scraper && cd scroll-scraper
npm init -y

npm install crawlbase cheerio

Deux dépendances font le travail : crawlbase est le client Node officiel pour la Crawling API, et cheerio analyse le HTML renvoyé avec une API style jQuery pour extraire les champs par sélecteur CSS. Créez un fichier nommé scraper.js dans ce dossier et ajoutez le code des étapes ci-dessous.

Étape 1 : récupérer la page avec le défilement activé

Commencez par obtenir la page chargée. Importez la classe CrawlingAPI, initialisez-la avec votre token JavaScript et demandez l'URL cible avec l'option scroll activée. Sans scroll_interval, l'API adopte par défaut un défilement de 10 secondes, qui charge le premier lot supplémentaire. Vérifier le statut avant d'analyser maintient les échecs visibles plutôt que silencieux.

javascript
const { CrawlingAPI } = require('crawlbase');

const api = new CrawlingAPI({ token: 'YOUR_CRAWLBASE_TOKEN' });

const targetUrl = 'https://example.com/listings';

api
  .get(targetUrl, { scroll: true })
  .then((response) => {
    if (response.statusCode === 200) {
      console.log(response.body.length, 'bytes of rendered HTML');
      console.log(response.body.slice(0, 500));
    }
  })
  .catch((error) => console.error('API request error:', error));

Exécutez le script avec node scraper.js. Passer { scroll: true } demande à la Crawling API de rendre la page et de la faire défiler avant de la renvoyer, le HTML que vous récupérez contient donc déjà les éléments chargés lors du défilement, pas seulement le premier lot. Le nombre d'octets et l'extrait en tête du corps confirment que vous recevez une vraie page rendue et non une coquille vide. Comme vous n'avez pas encore défini d'intervalle, cela adopte par défaut un défilement de 10 secondes, qui charge naturellement moins d'éléments qu'un défilement plus long.

Crawlbase Crawling API

Ce seul appel vient de rendre une page à défilement infini et de la faire défiler pour vous, sans navigateur sans tête défilant en boucle ni pool de proxies de votre côté. La Crawling API exécute la page dans un vrai navigateur, continue à défiler aussi longtemps que scroll_interval le stipule, fait tourner les IPs résidentielles côté serveur et gère les CAPTCHA, vous obtenez donc le HTML entièrement chargé depuis une seule requête. Essayez-la sur une liste publique depuis le niveau gratuit, puis ajoutez votre parseur.

Étape 2 : charger davantage d'éléments avec scroll_interval

Le défilement de 10 secondes par défaut ne charge que le premier lot supplémentaire. Pour en charger davantage, définissez scroll_interval sur le nombre de secondes pendant lesquelles vous voulez que l'API continue à défiler. Le maximum est 60 secondes ; après cela, l'API capture ce qui a été chargé et le renvoie. Chaque seconde supplémentaire de défilement donne à la page plus de temps pour récupérer et rendre des éléments supplémentaires.

javascript
const { CrawlingAPI } = require('crawlbase');

const api = new CrawlingAPI({ token: 'YOUR_CRAWLBASE_TOKEN' });

async function fetchScrolled(url, seconds) {
  const response = await api.get(url, {
    scroll: true,
    scroll_interval: seconds,
  });

  if (response.statusCode === 200) return response.body;
  console.error(`Request failed: ${response.statusCode}`);
  return null;
}

fetchScrolled('https://example.com/listings', 20)
  .then((html) => html && console.log(html.length, 'bytes after 20s scroll'));

Ici l'appel défile pendant 20 secondes au lieu des 10 secondes par défaut, la page a donc le temps de charger davantage d'éléments, et le HTML renvoyé est plus grand en conséquence. Gardez votre connexion ouverte assez longtemps pour que le défilement se termine : si vous défilez pendant les 60 secondes complètes, accordez jusqu'à environ 90 secondes à la requête pour se compléter avant que la page chargée ne revienne. Commencez avec un intervalle plus petit et augmentez-le uniquement jusqu'à ce que le nombre d'éléments cesse de croître, car les rendus plus longs coûtent plus cher et n'apportent que peu une fois la liste épuisée.

Ajustez l'intervalle

Il n'y a pas de valeur unique correcte pour scroll_interval. Un flux court peut être entièrement chargé en 10 à 20 secondes, tandis qu'un long peut continuer à charger jusqu'à la limite de 60 secondes. Augmentez l'intervalle par paliers et comparez le nombre d'éléments analysés ; une fois que le compteur stagne, un défilement plus long ne fait que dépenser des crédits sans ajouter de lignes.

Étape 3 : analyser les éléments chargés avec Cheerio

Avec le HTML chargé en main, passez-le à Cheerio et parcourez chaque carte d'élément. Utilisez des sélecteurs correspondant à votre vraie cible ; ceux ci-dessous supposent une liste générique où chaque élément se trouve dans une carte .listing-item. Lire chaque champ défensivement évite qu'une valeur manquante ne fasse planter l'exécution.

javascript
const cheerio = require('cheerio');

function parseItems(html, baseUrl) {
  const $ = cheerio.load(html);
  const result = {
    resultCount: $('.results-count').text().trim(),
    items: [],
  };

  $('.listing-item').each((_, element) => {
    const card = $(element);

    const title = card.find('.item-title').text().trim();
    const subtitle = card.find('.item-subtitle').text().trim();
    const price = card.find('.item-price').text().trim();
    let link = card.find('a.item-link').attr('href');
    if (link && link.startsWith('/')) {
      link = new URL(link, baseUrl).href;
    }

    if (title) {
      result.items.push({
        title,
        subtitle: subtitle || '',
        price: price || 'N/A',
        link: link || '',
      });
    }
  });

  return result;
}

Le compteur de résumé vient de .results-count, et chaque élément se trouve dans une carte .listing-item. Dans une carte, le titre vient de .item-title, la ligne secondaire de .item-subtitle, le prix de .item-price, et le lien de l'ancre a.item-link, résolu en URL absolue pour fonctionner en dehors de la page. Comme les éléments chargés pendant le défilement sont déjà dans le HTML, la même boucle attrape le premier lot et chaque lot suivant en une seule passe.

Les sélecteurs évoluent

Les noms de classes ci-dessus sont des placeholders pour une page générique. Sur une vraie cible, ouvrez la page en direct dans les outils de développement de votre navigateur, faites défiler jusqu'au chargement des éléments, et lisez la vraie classe ou l'attribut sur chaque carte. De nombreux sites en production utilisent des noms de classes générés qui changent sans préavis, traitez donc les sélecteurs comme un modèle de départ, pas un contrat, et réinspectez quand un champ revient vide.

Étape 4 : assembler le script complet avec export JSON et CSV

Reliez maintenant la récupération avec défilement et l'analyse en un script exécutable unique, puis écrivez les enregistrements sur le disque en JSON et CSV.

javascript
const fs = require('fs');
const { CrawlingAPI } = require('crawlbase');
const cheerio = require('cheerio');

const api = new CrawlingAPI({ token: 'YOUR_CRAWLBASE_TOKEN' });

async function fetchScrolled(url, seconds) {
  const response = await api.get(url, {
    scroll: true,
    scroll_interval: seconds,
  });
  if (response.statusCode === 200) return response.body;
  console.error(`Request failed: ${response.statusCode}`);
  return null;
}

function toCsv(rows) {
  const headers = ['title', 'subtitle', 'price', 'link'];
  const escape = (value) =>
    `"${String(value).replace(/"/g, '""')}"`;
  const lines = [headers.join(',')];
  for (const row of rows) {
    lines.push(headers.map((h) => escape(row[h])).join(','));
  }
  return lines.join('\n');
}

async function main() {
  const url = 'https://example.com/listings';
  const html = await fetchScrolled(url, 20);
  if (!html) return;

  const data = parseItems(html, url);
  fs.writeFileSync('items.json', JSON.stringify(data, null, 2));
  fs.writeFileSync('items.csv', toCsv(data.items));
  console.log(`Saved ${data.items.length} items to JSON and CSV`);
}

main();

Collez la fonction parseItems de l'étape 3 dans le même fichier pour que main puisse l'appeler. Exécutez-le avec node scraper.js et vous obtenez deux fichiers : items.json avec les enregistrements structurés complets, et items.csv prêt à ouvrir dans un tableur. L'assistant toCsv met entre guillemets chaque champ et double les guillemets imbriqués, ce qui importe car les titres et les prix contiennent souvent des virgules. Vous avez maintenant un scraper à défilement fonctionnel en bien moins de 50 lignes, et vous pouvez l'intégrer dans un scraper existant ou l'envelopper dans un endpoint plus tard si vous le souhaitez.

À quoi ressemble le résultat

Le fichier JSON contient le compteur de résultats plus un objet par élément chargé, chacun avec le titre, le sous-titre, le prix et le lien.

json
{
  "resultCount": "248 results",
  "items": [
    {
      "title": "Wireless Headphones",
      "subtitle": "AudioWorks",
      "price": "$59.00",
      "link": "https://example.com/listings/wireless-headphones"
    },
    {
      "title": "Mechanical Keyboard",
      "subtitle": "KeyForge",
      "price": "$89.00",
      "link": "https://example.com/listings/mechanical-keyboard"
    }
  ]
}

Le CSV reflète les mêmes lignes d'éléments avec une ligne d'en-tête, il s'importe donc directement dans Excel, Google Sheets ou tout pipeline qui lit les fichiers délimités.

csv
title,subtitle,price,link
"Wireless Headphones","AudioWorks","$59.00","https://example.com/listings/wireless-headphones"
"Mechanical Keyboard","KeyForge","$89.00","https://example.com/listings/mechanical-keyboard"

Passer à l'échelle au-delà d'une seule page défilée

Le défilement charge davantage d'éléments sur une seule URL, mais ce n'est pas un substitut à la pagination, et il y a un plafond pratique. La limite de 60 secondes et la propre vitesse de chargement de la page limitent le nombre d'éléments qu'une seule requête peut exposer. Pour une extraction plus grande, combinez les deux techniques : faites défiler chaque page pour charger son lot complet, puis passez à la page suivante si le site pagine, et analysez chacune avec la même fonction.

javascript
async function scrapeAllPages(baseUrl, maxPages, seconds) {
  const allItems = [];

  for (let page = 1; page <= maxPages; page++) {
    const pageUrl = `${baseUrl}?page=${page}`;
    const html = await fetchScrolled(pageUrl, seconds);
    if (!html) break;

    const { items } = parseItems(html, baseUrl);
    if (items.length === 0) break;

    allItems.push(...items);
    console.log(`Page ${page}: ${items.length} items`);

    await new Promise((r) => setTimeout(r, 2000));
  }

  return allItems;
}

Adaptez le schéma de page à votre cible en vérifiant un vrai lien "page suivante" dans le navigateur. Pour un volume élevé, vous n'avez pas à exécuter ces requêtes une par une et attendre. Le Crawler asynchrone vous permet de soumettre de nombreuses URLs et de collecter les résultats au fil de leur arrivée, ce qui convient mieux aux grands travaux combinant défilement et pagination qu'une boucle sérielle serrée. Pour plus d'informations sur les pages rendues et lourdes en scripts comme celles-ci, voir notre guide sur le crawl des sites JavaScript, et pour les flux AJAX purement en arrière-plan, l'extraction de données depuis les sites AJAX.

Scraper de façon responsable

Limitez-vous aux données publiques et exécutez de façon considérée. Lisez les Conditions d'utilisation du site cible et son fichier robots.txt avant de pointer un scraper à défilement dessus, et traitez les deux comme la limite de ce que vous collectez. Restez sur les listes publiques, pas sur quoi que ce soit derrière une connexion, et cadencez vos requêtes pour ne pas stresser le serveur : le défilement maintient déjà un rendu ouvert pendant de nombreuses secondes, ajoutez donc un délai entre les pages plutôt que de les envoyer en rafale serrée. Quand les données impliquent des personnes identifiables, les lois sur la vie privée comme le RGPD et le CCPA s'appliquent, évitez donc d'assembler des profils d'individus et ne republiez pas de données personnelles liées à l'identité de quelqu'un. Pour un guide plus complet, voir comment extraire des données sans être bloqué.

Récapitulatif

Points clés

  • Le défilement infini cache des données à une simple requête. Un simple appel HTTP ne renvoie que le premier lot d'éléments ; le reste se charge quand la page défile, une requête qui ne défile jamais ne les voit donc jamais.
  • La Crawling API défile pour vous. Envoyez l'URL avec scroll: true et elle rend la page dans un vrai navigateur, la fait défiler côté serveur derrière une IP rotative, et renvoie le HTML entièrement chargé en un seul appel.
  • scroll_interval contrôle ce qui se charge. La valeur par défaut est un défilement de 10 secondes ; augmentez l'intervalle jusqu'à la limite de 60 secondes pour charger davantage d'éléments, et accordez jusqu'à environ 90 secondes à une requête de durée maximale pour se compléter.
  • Cheerio analyse le HTML chargé. Sélectionnez chaque carte d'élément, lisez le titre, le sous-titre, le prix et le lien défensivement, attendez-vous à ce que les noms de classes générés évoluent, et exportez en JSON et CSV.
  • Défilement plus pagination pour l'échelle. Faites défiler chaque page pour charger son lot complet, passez à la page suivante quand le site pagine, cadencez vos requêtes, et optez pour le Crawler asynchrone pour les grands travaux.

Foire aux questions

Qu'est-ce que le défilement infini et pourquoi casse-t-il le scraping simple ?

Le défilement infini est un schéma où une page charge d'abord un petit ensemble d'éléments, puis en récupère et en rend davantage quand l'utilisateur fait défiler vers le bas, généralement via des appels AJAX en arrière-plan. Une simple requête HTTP capture la page avant tout défilement, elle ne voit donc que le premier lot. Pour obtenir le reste, vous devez rendre la page dans un vrai navigateur et réellement la faire défiler, ce que fait la Crawling API quand vous passez les options de défilement.

Que font les options scroll et scroll_interval ?

L'option scroll demande à la Crawling API de faire défiler la page après son chargement, ce qui déclenche le chargement différé qui apporte davantage d'éléments. L'option scroll_interval définit combien de secondes elle continue à défiler, jusqu'à un maximum de 60. Avec scroll activé et aucun intervalle défini, l'API adopte par défaut un défilement de 10 secondes. Les deux nécessitent le token JavaScript, car la page doit se rendre dans un vrai navigateur pour que le défilement ait un sens.

Quelle durée devrais-je définir pour scroll_interval ?

Commencez petit et augmentez. Un flux court peut être entièrement chargé en 10 à 20 secondes, tandis qu'un long continue à charger jusqu'à la limite de 60 secondes. Augmentez l'intervalle par paliers et comparez le nombre d'éléments analysés ; une fois que le compteur cesse de croître, un défilement plus long ne fait que dépenser des crédits supplémentaires sans ajouter de lignes. Si vous défilez pendant les 60 secondes complètes, accordez jusqu'à environ 90 secondes à la requête pour se compléter.

Ai-je besoin du token JavaScript pour faire défiler une page ?

Oui. Le défilement n'a de sens que sur une page qui se rend dans un vrai navigateur, et c'est le token JavaScript qui active ce rendu. Un token normal renvoie le HTML non rendu, où le défilement n'a aucun effet et les éléments supplémentaires ne se chargent jamais. Les requêtes JavaScript utilisent plus de crédits que les normales en raison du rendu, tenez-en compte quand vous planifiez une grande exécution.

Le défilement remplace-t-il la pagination ?

Non. Le défilement charge davantage d'éléments sur une seule URL, mais la limite de 60 secondes et la vitesse de chargement de la page limitent le nombre d'éléments qu'il peut exposer dans une seule requête. Pour un jeu de données complet sur un site qui pagine également, combinez les deux : faites défiler chaque page pour charger son lot complet, puis passez à la page suivante et analysez-la avec la même fonction. Pour les grands travaux, le Crawler asynchrone gère de nombreuses telles requêtes en parallèle.

Mes sélecteurs retournent des valeurs vides après le défilement. Qu'est-ce qui ne va pas ?

Généralement l'une de deux choses. Soit la page n'a pas défilé assez longtemps, les éléments que vous voulez ne se sont donc jamais chargés, auquel cas augmentez scroll_interval et confirmez que le HTML renvoyé a grandi. Soit le balisage du site utilise des noms de classes différents ou générés que vos sélecteurs n'attendent pas. Ouvrez la page en direct dans les outils de développement de votre navigateur, faites défiler jusqu'à ce que les éléments apparaissent, lisez la vraie classe ou l'attribut sur chaque carte, et mettez à jour les sélecteurs dans parseItems pour correspondre.

Commencer à construire

Crawlez n'importe quel site à grande échelle, sans combattre l'infrastructure.

Crawlbase gère les proxies, les empreintes et les CAPTCHA afin que votre équipe livre des pipelines de données au lieu de maintenir la plomberie de crawl. 1 000 requêtes gratuites, sans carte requise.

En libre-service · Sans appel commercial requis · Volumes de crawl entreprise disponibles