Craigslist est la plus grande plateforme d'annonces classées des États-Unis depuis la fin des années 1990, et elle compte encore des millions d'annonces publiques dans les catégories logement, articles à vendre, services et communauté. Ces pages d'annonces constituent une source utile de signaux de marché public : comment les loyers évoluent selon les quartiers, à quel prix les biens d'occasion se vendent dans une métropole, où l'offre est rare. Chaque résultat de recherche se trouve sur la page dans une mise en page prévisible et rendue côté serveur, ce qui rend les champs publics simples à lire.
Ce guide vous montre comment scraper Craigslist avec JavaScript et Node.js en utilisant Cheerio. Vous construisez un scraper petit et exécutable qui récupère une page de résultats de recherche publique de Craigslist via la Crawling API, analyse le titre, le prix, l'emplacement, la date de publication et le lien de chaque annonce, et exporte le résultat en JSON et CSV. L'ensemble du tutoriel reste limité aux données d'annonces publiques et non personnelles. Les coordonnées du vendeur et le contenu en texte libre d'une publication d'une personne sont des données personnelles, et la section légalité proche de la fin explique pourquoi ce scraper les exclut délibérément, alors lisez-la avant de l'utiliser à grande échelle.
Ce que vous allez construire
Un script Node.js qui prend une URL de recherche publique Craigslist, récupère le HTML via la Crawling API, et extrait un enregistrement structuré pour chaque annonce sur la page de résultats. Nous utilisons une recherche immobilière comme exemple fil conducteur et récupérons ces champs par annonce :
- Title le titre de l'annonce affiché sur la fiche de résultat, par exemple "2 bedroom trailer for rent".
- Price le prix demandé tel qu'affiché, comme "$675", conservé en texte car les prix Craigslist contiennent des symboles monétaires et des virgules.
- Location l'indication de quartier ou de zone que Craigslist affiche à côté de l'annonce.
- Post date la date de publication de l'annonce, lorsque la fiche de résultat l'expose.
- Link l'URL absolue vers la page de l'annonce individuelle.
Pourquoi une simple requête peut échouer sur Craigslist
Une requête HTTP brute vers une URL de recherche Craigslist peut fonctionner pour un seul accès, mais elle ne tient pas dès que vous scraper à un certain volume. Craigslist surveille le trafic automatisé et s'en protège : les adresses IP de centres de données et les schémas de requêtes qui ne ressemblent pas à un vrai navigateur sont limités en débit, reçoivent un CAPTCHA ou sont bloqués purement et simplement. Lancez une boucle serrée depuis une adresse et vous verrez des réponses non-200 et des pages de défi au lieu d'annonces assez rapidement.
Un scraper Craigslist durable a donc besoin d'une IP que la plateforme lit comme un visiteur réel, et il doit se comporter poliment. Vous pouvez assembler cela vous-même avec un pool de proxies résidentiels rotatifs, mais maintenir ce pool sain et non bloqué représente la majeure partie du travail. La Crawling API regroupe tout cela en un seul appel : vous lui envoyez l'URL, elle récupère la page derrière une IP de confiance avec la gestion des CAPTCHA intégrée, et elle renvoie le HTML que vous analysez avec Cheerio.
Tout dans ce guide lit des champs que n'importe quel visiteur voit sur une page de résultats de recherche publique : titre, prix, indication d'emplacement, date de publication et lien. Il n'ouvre pas les annonces individuelles pour collecter le numéro de téléphone ou l'e-mail d'un vendeur, et ne crée pas de profil d'un utilisateur. Cette limite est intentionnelle, et la section légalité ci-dessous l'explique.
Prérequis
Vous avez besoin de quelques éléments en place avant d'écrire du code. Aucun ne prend longtemps.
JavaScript et Node.js de base. Vous devez être à l'aise pour écrire et exécuter un script Node et installer des packages avec npm. Si vous êtes nouveau sur Node, la documentation officielle ou n'importe quel cours débutant vous amènera au niveau que ce tutoriel suppose. Pour un tutoriel plus complet, notre guide sur la construction d'un scraper web avec Node.js couvre les bases.
Node.js 16 ou supérieur. Confirmez votre version avec node --version. Si vous ne l'avez pas, installez-le depuis le site Node.js ou via un gestionnaire de version comme nvm.
Un compte Crawlbase et un token. Inscrivez-vous, ouvrez votre tableau de bord et copiez votre token depuis la page de documentation du compte. Le niveau gratuit vous donne jusqu'à 20 000 requêtes sans carte, et vous ne payez que pour les requêtes réussies. Traitez le token comme un mot de passe : il authentifie vos requêtes, alors ne le mettez pas dans le 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.
node --version mkdir craigslist-scraper && cd craigslist-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 de style jQuery afin que vous puissiez extraire des champs individuels par sélecteur CSS. La version originale de ce tutoriel utilisait jsdom pour analyser le HTML sauvegardé ; Cheerio fait le même travail avec une API plus légère et plus rapide, et convient mieux à un pipeline de scraping. 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 de résultats de recherche
Commencez par obtenir le HTML de la page. Importez la classe CrawlingAPI, initialisez-la avec votre token et demandez une URL de recherche publique Craigslist. Choisissez une page de liste de recherche que vous souhaitez scraper, par exemple une recherche immobilière à vendre avec la vue galerie, et vérifiez le code de statut avant d'analyser afin que les échecs restent visibles plutôt que silencieux.
const { CrawlingAPI } = require('crawlbase'); const fs = require('fs'); const api = new CrawlingAPI({ token: 'YOUR_CRAWLBASE_TOKEN' }); const craigslistPageURL = 'https://chicago.craigslist.org/search/rea?hasPic=1'; api .get(craigslistPageURL) .then((response) => { if (response.statusCode === 200) { fs.writeFileSync('response.html', response.body); console.log('HTML saved to response.html'); } else { console.error(`Request failed: ${response.statusCode}`); } }) .catch((error) => console.error('API request error:', error));
Exécutez le script avec node scraper.js. En cas de succès, il écrit la page dans response.html, ce qui vous permet d'inspecter le balisage et de développer des sélecteurs sur une copie stable plutôt que d'accéder au réseau à chaque modification. La Crawling API récupère la page derrière une IP de confiance, de sorte que les annonces sont présentes dans le HTML que vous récupérez plutôt qu'une page de blocage.
Cette première requête vient de renvoyer une vraie page de résultats Craigslist sans pool de proxies ni résolution de CAPTCHA de votre côté. La Crawling API récupère la page derrière des IPs résidentielles rotatives côté serveur et gère les défis que Craigslist lance aux scrapers, de sorte que vous obtenez du HTML utilisable en un seul appel. Pointez-la vers une recherche publique sur le niveau gratuit d'abord, puis ajoutez votre parseur.
Étape 2 : Analyser chaque annonce avec Cheerio
Avec le HTML sauvegardé en main, chargez-le dans Cheerio et parcourez les annonces. Craigslist affiche ses résultats de recherche statiques dans une liste ol.cl-static-search-results, chaque annonce dans son propre élément li.cl-static-search-result, alors sélectionnez chaque élément et lisez le titre, le prix, l'emplacement, la date de publication et le lien depuis l'intérieur. Lire chaque champ de manière défensive évite qu'une valeur manquante ne fasse planter l'exécution.
const cheerio = require('cheerio'); function parseListings(html) { const $ = cheerio.load(html); const listings = []; $('ol.cl-static-search-results li.cl-static-search-result').each((_, el) => { const item = $(el); const title = item.find('.title').text().trim(); const price = item.find('.price').text().trim(); const location = item.find('.location').text().trim(); const postDate = item.find('.meta time').attr('datetime') || ''; const link = item.find('a').attr('href') || ''; if (title) { listings.push({ title, price: price || 'N/A', location: location || 'N/A', postDate, url: link, }); } }); return listings; }
Les sélecteurs correspondent directement à la page. Le titre de chaque annonce vient de .title, le prix demandé de .price, l'indication de quartier de .location, et le lien de l'ancre href de l'élément. La date de publication est lue depuis l'attribut datetime de l'élément time dans la ligne .meta de l'annonce, ce qui vous donne une date lisible par machine plutôt qu'un texte relatif. Le prix reste une chaîne intentionnellement, car les valeurs Craigslist incluent le symbole monétaire et les séparateurs de milliers ; convertissez-le en nombre plus tard si votre analyse en a besoin.
Craigslist ajuste son balisage de temps en temps, et les sous-domaines de villes individuelles peuvent différer légèrement. Traitez ces sélecteurs comme un modèle de départ, pas comme un contrat. Quand un champ revient vide, ouvrez response.html ou la page en direct dans les outils de développement de votre navigateur et mettez à jour le sélecteur. La maintenance périodique des sélecteurs est normale pour tout scraper en production, ce n'est pas le signe que quelque chose est cassé.
Étape 3 : Assembler le script complet avec export JSON et CSV
Reliez maintenant la récupération et l'analyse en un seul script exécutable, puis écrivez les enregistrements sur le disque en JSON et CSV.
const fs = require('fs'); const { CrawlingAPI } = require('crawlbase'); const cheerio = require('cheerio'); const api = new CrawlingAPI({ token: 'YOUR_CRAWLBASE_TOKEN' }); async function crawl(pageUrl) { const response = await api.get(pageUrl); if (response.statusCode === 200) return response.body; console.error(`Request failed: ${response.statusCode}`); return null; } function toCsv(rows) { const headers = ['title', 'price', 'location', 'postDate', 'url']; 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://chicago.craigslist.org/search/rea?hasPic=1'; const html = await crawl(url); if (!html) return; const listings = parseListings(html); fs.writeFileSync('listings.json', JSON.stringify(listings, null, 2)); fs.writeFileSync('listings.csv', toCsv(listings)); console.log(`Saved ${listings.length} listings to JSON and CSV`); } main();
Collez la fonction parseListings de l'étape 2 dans le même fichier afin que main puisse l'appeler. Exécutez-la avec node scraper.js et vous obtenez deux fichiers : listings.json avec les enregistrements structurés complets et listings.csv prêt à ouvrir dans un tableur. L'assistant toCsv met entre guillemets chaque champ et double les guillemets incorporés, ce qui est important ici car les titres d'annonces contiennent fréquemment des virgules.
À quoi ressemble la sortie
Le fichier JSON contient un objet par annonce, chacun avec le titre, le prix, l'emplacement, la date de publication et le lien. Les valeurs ci-dessous sont illustratives, tirées d'une recherche immobilière.
[ { "title": "2 bedroom trailer for rent", "price": "$675", "location": "165th & Kennedy", "postDate": "2024-04-05 09:12", "url": "https://chicago.craigslist.org/nwi/reo/d/hammond-bedroom-trailer-for-rent/7732856568.html" }, { "title": "Barrington Village Home", "price": "$439,000", "location": "northwest suburbs", "postDate": "2024-04-04 16:48", "url": "https://chicago.craigslist.org/nwc/reo/d/barrington-barrington-village-home/7734168844.html" } ]
Le CSV reflète les mêmes lignes avec une ligne d'en-tête, il s'intègre donc directement dans Excel, Google Sheets ou tout pipeline de données qui lit des fichiers délimités.
title,price,location,postDate,url "2 bedroom trailer for rent","$675","165th & Kennedy","2024-04-05 09:12","https://chicago.craigslist.org/nwi/reo/d/hammond-bedroom-trailer-for-rent/7732856568.html" "Barrington Village Home","$439,000","northwest suburbs","2024-04-04 16:48","https://chicago.craigslist.org/nwc/reo/d/barrington-barrington-village-home/7734168844.html"
Gérer la pagination
Une page de recherche est une démonstration ; un vrai projet récupère chaque page de résultats. Craigslist pagine ses URL de recherche avec un décalage numérique, avançant de 120 résultats à la fois, vous pouvez donc boucler sur les décalages, récupérer chaque page via la Crawling API, l'analyser avec la même fonction et vous arrêter quand une page ne renvoie aucune annonce. Puisque chaque page de résultats partage la même structure d'éléments, le parseur que vous avez déjà écrit fonctionne sur toutes sans modification.
async function scrapeAllPages(baseUrl, maxPages) { const all = []; for (let page = 0; page < maxPages; page++) { // Craigslist pages search results in steps of 120 const offset = page * 120; const pageUrl = `${baseUrl}&s=${offset}`; const html = await crawl(pageUrl); if (!html) break; const listings = parseListings(html); if (listings.length === 0) break; // no more results all.push(...listings); console.log(`Page ${page + 1}: ${listings.length} listings`); // Pace requests so you stay under the rate limit await new Promise((r) => setTimeout(r, 2000)); } return all; }
Le paramètre exact de pagination peut changer, alors vérifiez quelques vrais liens "page suivante" dans votre navigateur et faites correspondre le schéma. Les bonnes habitudes s'appliquent à n'importe quelle cible : bouclez jusqu'à ce que les résultats soient épuisés et ajoutez un court délai entre les requêtes pour ne pas surcharger le site. Pour plus d'informations sur ce style de travail, consultez notre guide sur le crawling de sites JavaScript, et si vous suivez les prix dans le temps, nos notes sur le web scraping pour l'intelligence des prix.
Rester non bloqué
Craigslist s'oppose aux scrapers, donc quelques habitudes maintiennent une exécution saine. Elles s'appliquent à toute cible difficile.
- Rythmez vos requêtes. Introduisez un délai entre les récupérations de pages plutôt que de surcharger la recherche dans une boucle serrée. Espacer les requêtes est le facteur le plus important pour rester sous les limites de débit de Craigslist.
- Misez sur la rotation. Un pool d'IPs résidentielles répartit les requêtes sur de nombreuses adresses d'utilisateurs réels afin qu'aucune d'entre elles ne déclenche une limite ou un CAPTCHA. La Crawling API gère cela pour vous ; si vous construisez votre propre pile, c'est la partie à bien faire.
- Lisez les codes de statut. Une exécution qui commence à renvoyer des défis ou des réponses non-200 vous indique que le débit actuel ou le niveau d'IP n'est plus suffisant. Traitez cela comme un signal pour ralentir, pas comme du bruit à ignorer.
Pour le guide plus large, consultez comment scraper des sites sans être bloqué. Si vous souhaitez des données d'annonces similaires provenant d'autres sites de petites annonces et de location, le même schéma de récupération puis d'analyse s'applique au scraping d'Apartments.com.
Est-il légal de scraper Craigslist ?
La légalité du scraping de Craigslist dépend des conditions d'utilisation de Craigslist, de votre juridiction et de ce que vous faites avec les données. Cela compte plus sur Craigslist que sur la plupart des sites : Craigslist s'oppose activement à l'accès automatisé et a un long historique de poursuites judiciaires contre les scrapers. Ses conditions d'utilisation interdisent la collecte automatisée, le scraping peut donc aller à l'encontre de ces conditions quelle que soit la prudence de vos outils. Aucun code ici ne change cela ; il fait juste fonctionner la partie technique. Lisez les conditions d'utilisation de Craigslist et son robots.txt, respectez les limites de débit qu'ils impliquent, et traitez les deux comme la limite de ce que vous collectez.
Ce guide est délibérément limité aux données d'annonces publiques et non personnelles : le titre, le prix, l'indication d'emplacement, la date de publication et le lien que n'importe qui voit sur une page de résultats de recherche sans se connecter. C'est différent des données personnelles sur la plateforme. Le nom, le numéro de téléphone, l'e-mail d'un vendeur ou le contenu en texte libre qu'il a écrit dans une publication sont des données personnelles. Ne collectez pas les coordonnées des vendeurs, ne créez pas de profils des utilisateurs et ne republiez pas une publication liée à une personne identifiable. Dès qu'un projet touche des personnes identifiables, le droit à la vie privée comme le RGPD et le CCPA s'applique, et cela est clairement hors de portée ici. Les faits agrégés comme "les loyers de deux chambres dans ce quartier se situent autour de X" sont acceptables ; une liste de qui vend quoi, avec leurs coordonnées, ne l'est pas.
Craigslist ne publie pas d'API publique à usage général, bien que certaines catégories exposent des flux RSS pour un accès limité et sanctionné. Quand un flux ou un accord de données explicite existe, préférez-le : une voie sanctionnée vient avec des conditions d'utilisation claires plutôt que le risque légal et technique de scraper un site qui s'y oppose. Quand vous n'êtes pas sûr qu'une utilisation est autorisée, obtenez une autorisation ou un accord de données plutôt que de supposer que le silence est un consentement, et gardez le volume et la portée de ce que vous collectez proportionnels à un objectif de recherche légitime et non personnel.
Points clés
- Craigslist s'oppose aux scrapers. Une boucle serrée depuis une IP de centre de données est limitée en débit, défiée ou bloquée, donc récupérez la page derrière une IP de confiance et rotative et rythmez vos requêtes.
- La Crawling API fait le travail difficile en un seul appel. Elle récupère la page derrière des IPs résidentielles et gère les CAPTCHAs côté serveur, renvoyant du HTML que vous analysez avec Cheerio.
-
Cheerio extrait les champs. Sélectionnez chaque
li.cl-static-search-resultdansol.cl-static-search-results, puis lisez le titre, le prix, l'emplacement, la date de publication et le lien, et attendez-vous à ce que le balisage change selon les villes et au fil du temps. - Paginatez et exportez. Bouclez sur le paramètre de décalage de Craigslist jusqu'à ce que les résultats soient épuisés, rythmez vos requêtes et écrivez des enregistrements structurés en JSON et CSV.
- Restez sur des données publiques et non personnelles. Ne collectez que les champs d'annonces, jamais les coordonnées du vendeur ni le corps des publications liées à une personne, respectez les CGU et le robots.txt, et n'oubliez pas que le RGPD et le CCPA s'appliquent dès que des données personnelles sont impliquées.
Foire aux questions
Craigslist dispose-t-il d'une API officielle ?
Craigslist ne fournit pas d'API publique à usage général pour accéder à ses données. Certaines sections proposent des flux RSS pour un accès limité, mais il n'existe pas d'API complète. Quand un flux sanctionné ou un accord de données existe pour ce dont vous avez besoin, utilisez-le de préférence au scraping, car il comporte des conditions d'utilisation claires et autorisées.
Puis-je construire un scraper Craigslist dans un langage autre que JavaScript ?
Oui. Ce guide utilise JavaScript avec Cheerio, mais la même approche fonctionne dans n'importe quel langage. La Crawling API dispose de bibliothèques et de SDK pour plusieurs langages, vous récupérez donc le HTML de la même façon et l'analysez avec le parseur HTML que votre pile préfère, comme BeautifulSoup en Python. Les sélecteurs et les champs restent les mêmes ; seule la syntaxe d'analyse change.
Mes sélecteurs renvoient des valeurs vides. Qu'est-ce qui a changé ?
Presque certainement le balisage de Craigslist, ou une différence entre les sous-domaines de villes. Ouvrez le response.html sauvegardé ou une page en direct dans les outils de développement de votre navigateur, confirmez que le conteneur d'annonces est toujours ol.cl-static-search-results avec des éléments li.cl-static-search-result, et mettez à jour les sélecteurs internes dans parseListings. La maintenance périodique des sélecteurs est normale pour tout scraper en production.
Vais-je être bloqué lors du scraping de Craigslist ?
Vous pouvez l'être, surtout sur Craigslist, si vous envoyez trop de requêtes trop vite depuis une seule adresse. La Crawling API réduit ce risque en faisant tourner des IPs résidentielles et en gérant les CAPTCHAs pour vous, mais vous devriez quand même rythmer vos requêtes, ajouter des délais entre les pages et surveiller les codes de statut afin de pouvoir ralentir quand des défis apparaissent.
Puis-je scraper les numéros de téléphone et les coordonnées des vendeurs dans les publications ?
Non, et ce scraper est conçu pour ne pas le faire. Le nom, le numéro de téléphone, l'e-mail d'un vendeur et le corps en texte libre qu'il a écrit sont des données personnelles. Les collecter, créer des profils d'utilisateurs ou republier une publication liée à une personne implique le droit à la vie privée comme le RGPD et le CCPA et va à l'encontre des conditions de Craigslist. Limitez votre collecte aux champs d'annonces publics et non personnels couverts ici.
À quoi servent les données Craigslist ?
Les données d'annonces publiques servent à la recherche de marché et à l'analyse des prix : suivre l'évolution des loyers et des prix des biens d'occasion dans les quartiers et les métropoles, repérer les lacunes d'offre et étudier la demande locale dans le temps. La valeur est dans le signal agrégé et non personnel sur de nombreuses annonces, pas dans l'identité ou les coordonnées d'un utilisateur particulier.
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.
