Les marchés des cryptomonnaies fonctionnent en continu, et les pages publiques de sites comme CoinGecko publient exactement les données structurées qui alimentent les outils de suivi des cours, les tableaux de bord de portefeuilles et les recherches : nom et symbole de chaque coin, cours actuel, variation sur 24 heures, volume de trading sur 24 heures et capitalisation boursière. Ce tableau se rafraîchit en permanence, et le lire manuellement pour des dizaines de coins est lent et source d'erreurs.

Ce guide vous montre comment extraire des données de marché crypto avec Python de façon fiable. Vous construisez un scraper simple et exécutable qui récupère la page de marché rendue via la Crawling API, analyse chaque ligne avec BeautifulSoup, gère la pagination et exporte des données propres en JSON et CSV. L'ensemble du tutoriel porte uniquement sur les données de marché publiques, celles que n'importe quel visiteur voit sans compte, et la section sur la légalité vers la fin n'est pas du remplissage.

Ce que vous allez construire

Un script Python qui récupère une page publique de marché crypto, parcourt chaque ligne de coin dans le tableau rendu et extrait un enregistrement structuré par coin. L'exemple utilisé est le tableau principal des marchés sur CoinGecko. Nous extrayons ces champs :

  • Nom le nom complet du coin, par exemple Bitcoin ou Ethereum.
  • Symbole le symbole du ticker, par exemple BTC ou ETH.
  • Cours le cours actuel dans la devise de référence choisie.
  • Variation 24h l'évolution en pourcentage du cours sur les dernières 24 heures.
  • Volume 24h le volume total échangé sur les dernières 24 heures.
  • Capitalisation boursière la capitalisation boursière totale du coin.

Pourquoi une simple requête échoue sur une page de marché crypto

Faites une requête vers une URL de marché crypto avec un client HTTP basique et vous obtenez un statut 200 avec seulement une partie des données dans le corps. Deux choses vous font obstacle. Premièrement, ces tableaux de marché chargent leurs lignes dans le navigateur via JavaScript, donc le HTML initial est une coquille vide qui ne se remplit qu'après l'exécution des scripts de la page. Analyser cette première réponse vous donne un tableau vide plutôt que la liste complète des coins. Deuxièmement, les sites à fort trafic détectent rapidement le trafic automatisé : les IP de datacenters et les schémas de requêtes qui ne ressemblent pas à un vrai navigateur sont limités ou bloqués avant même d'atteindre le contenu rendu.

Un scraper de données de marché fonctionnel a donc besoin de deux choses en une seule requête : un navigateur qui rend la page, et une IP que la plateforme perçoit comme un vrai visiteur. Vous pouvez assembler cela vous-même avec un navigateur headless et un pool de proxies résidentiels rotatifs, mais les assembler et les maintenir en bon état représente l'essentiel du travail. La Crawling API regroupe les deux en un seul appel : vous lui envoyez l'URL avec un token JavaScript, elle rend la page derrière une IP de confiance et retourne le HTML finalisé prêt à être analysé.

Pourquoi le token JS

Crawlbase propose deux types de tokens. Le token normal récupère le HTML statique ; le token JavaScript (JS) rend d'abord la page dans un vrai navigateur. Un tableau de marché crypto remplissant ses lignes côté client, vous avez besoin du token JS ici. Le token normal retourne la même coquille vide qu'une simple requête, et il n'y a pas grand-chose d'utile à en extraire.

Prérequis

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

Python de base. Vous devez être à l'aise pour écrire et exécuter un script Python et installer des packages avec pip. Si vous débutez avec l'analyse HTML, le guide BeautifulSoup est un bon complément à ce tutoriel.

Python 3.8 ou version ultérieure. Vérifiez votre version avec python --version. Si vous ne l'avez pas, installez-le depuis python.org ou via une distribution comme Anaconda, et assurez-vous que Python est dans votre PATH.

Un compte Crawlbase et un token JS. Créez un compte, ouvrez votre tableau de bord et copiez votre token JavaScript (JS) depuis la page de documentation de votre compte. Crawlbase inclut jusqu'à 20 000 requêtes gratuites pour commencer, ce qui est largement suffisant pour suivre ce guide. Traitez le token comme un mot de passe : il authentifie vos requêtes, donc ne le mettez pas dans le contrôle de version.

Configurer le projet

Créez un environnement virtuel pour isoler les dépendances du projet, puis installez les bibliothèques dont le scraper a besoin.

bash
python --version

python -m venv crypto_env
source crypto_env/bin/activate

pip install crawlbase beautifulsoup4

Sous Windows, activez l'environnement avec crypto_env\Scripts\activate à la place de la ligne source. Deux dépendances font le travail : crawlbase est le client officiel pour la Crawling API, et beautifulsoup4 analyse le HTML retourné pour extraire les champs individuels par sélecteur CSS. json et csv font partie de la bibliothèque standard, il n'y a donc rien de plus à installer pour l'étape d'export.

Étape 1 : Récupérer une page de marché rendue

Commencez par obtenir une page finalisée. Importez la classe CrawlingAPI, initialisez-la avec votre token JS et demandez l'URL du marché. Le tableau se chargeant de façon asynchrone, passez ajax_wait et page_wait pour attendre le contenu dynamique avant que la page ne soit capturée. Vérifier le cb_status (legacy pc_status) de Crawlbase avant d'analyser rend les échecs visibles plutôt que silencieux.

python
from crawlbase import CrawlingAPI

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_JS_TOKEN"})

OPTIONS = {
    "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/122.0",
    "ajax_wait": "true",
    "page_wait": 5000,
}

def crawl(page_url):
    response = api.get(page_url, OPTIONS)
    if response["headers"]["cb_status"] == "200":
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['headers']['cb_status']}")
    return None

if __name__ == "__main__":
    market_url = "https://www.coingecko.com/"
    html = crawl(market_url)
    print(html[:500] if html else "No HTML returned")

Les deux options d'attente sont importantes pour une cible rendue côté client. ajax_wait indique à l'API d'attendre le chargement du contenu asynchrone, et page_wait maintient un nombre fixe de millisecondes après le chargement pour que les lignes mises à jour en direct se stabilisent avant la capture de la page. Cinq secondes est un bon point de départ ; augmentez cette valeur si le tableau revient incomplet. Exécutez python crypto_scraper.py et vous devriez voir le vrai balisage du marché, pas la coquille vide qu'une simple requête retournerait, ce qui confirme que le rendu fonctionne avant d'écrire un seul sélecteur.

Crawlbase Crawling API

Une page de marché crypto nécessite un tableau rendu derrière une IP de confiance, en un seul appel, ce qui est exactement ce que les options ajax_wait et page_wait ci-dessus configurent. La Crawling API prend un token JS, exécute la page dans un vrai navigateur, fait tourner des IP résidentielles côté serveur et vous remet le HTML finalisé, vous évitant ainsi de gérer vous-même un parc headless et un pool de proxies. Pointez-la sur la page de marché publique avec le plan gratuit pour commencer.

Étape 2 : Analyser une ligne de coin

La page de marché est un tableau où chaque tr représente un coin. Chargez le HTML rendu dans BeautifulSoup et lisez les cellules qui vous intéressent. Les colonnes sont dans un ordre connu, et le nom et le symbole se trouvent ensemble dans la cellule du coin, donc une petite fonction auxiliaire qui mappe chaque champ à sa cellule rend l'analyse lisible. Chaque accès est protégé pour qu'un champ manquant retourne None plutôt que de faire planter l'exécution.

python
from bs4 import BeautifulSoup

ROW_SELECTOR = 'table[data-coin-table-target="table"] > tbody > tr'

def text_of(node, selector):
    el = node.select_one(selector)
    return el.get_text(strip=True) if el else None

def parse_row(row):
    return {
        "name": text_of(row, 'td[data-view-component="true"] a span.tw-text-gray-700'),
        "symbol": text_of(row, 'td[data-view-component="true"] a span.tw-text-gray-500'),
        "price": text_of(row, 'td[data-target="price.price"]'),
        "change_24h": text_of(row, 'td.tw-text-right span[data-target="price-change-percentage-24h"]'),
        "volume_24h": text_of(row, 'td.tw-text-right span[data-coin-table-target="totalVolume"]'),
        "market_cap": text_of(row, 'td.tw-text-right span[data-coin-table-target="marketCap"]'),
    }

La fonction auxiliaire text_of interroge un élément à l'intérieur d'une ligne et retourne son texte nettoyé, ou None si l'élément est absent, ce qui évite qu'un coin avec un champ manquant ne casse la boucle. La cellule du coin contient à la fois le name complet et le symbol dans deux spans imbriqués, tandis que le cours, la variation sur 24 heures, le volume et la capitalisation boursière se trouvent chacun dans leur propre cellule alignée à droite. Lire chaque ligne comme une unité maintient chaque champ aligné sur le bon coin même quand une colonne se déplace.

Les sélecteurs changent

Les noms de classes générés et les attributs data-target d'un site de marché changent sans préavis. Traitez les sélecteurs ici comme un modèle de départ, pas comme un contrat. Quand un champ revient None, réinspectez 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 un signe que quelque chose est cassé.

Étape 3 : Parcourir toutes les lignes de la page

Avec un parseur de ligne disponible, sélectionnez toutes les lignes du tableau et mappez chacune sur un enregistrement. Un petit wrapper de réessai autour de la récupération évite qu'une seule requête lente ne mette fin à l'exécution.

python
import time

def fetch_html(page_url, max_retries=2):
    for attempt in range(max_retries + 1):
        html = crawl(page_url)
        if html:
            return html
        if attempt < max_retries:
            print(f"Retrying ({attempt + 1}/{max_retries})...")
            time.sleep(1)
    print(f"Unable to fetch {page_url}")
    return None

def parse_market(html):
    soup = BeautifulSoup(html, "html.parser")
    rows = soup.select(ROW_SELECTOR)
    return [parse_row(r) for r in rows if r.select_one('td[data-target="price.price"]')]

fetch_html réessaie une récupération échouée jusqu'à deux fois avec une courte pause, retournant le HTML en cas de succès et None une fois qu'il abandonne. parse_market sélectionne chaque ligne de coin et mappe chacune sur un enregistrement, en ignorant les lignes sans cellule de cours pour que les lignes d'espacement ou d'en-tête ne produisent pas d'entrées vides. Le résultat est une liste propre de dictionnaires de coins provenant d'une page.

Étape 4 : Gérer la pagination sur l'ensemble du marché

Une page n'est qu'une partie du marché complet. CoinGecko pagine avec un paramètre de requête ?page=, vous parcourez donc chaque page jusqu'à un plafond et rassemblez les lignes de toutes. Limiter le crawl avec un argument max_pages évite qu'un grand marché ne s'emballe, et une courte pause entre les pages rythme l'exécution pour ne pas surcharger le site.

python
def collect_all_coins(base_url, max_pages):
    records = []
    for page in range(1, max_pages + 1):
        page_url = f"{base_url}?page={page}"
        html = fetch_html(page_url)
        if not html:
            continue
        page_coins = parse_market(html)
        if not page_coins:
            break
        records.extend(page_coins)
        print(f"Page {page}: {len(page_coins)} coins")
        time.sleep(2)
    return records

collect_all_coins demande chaque page à tour de rôle, analyse ses lignes et s'arrête tôt si une page ne retourne aucun coin, ce qui arrive une fois passé la dernière page peuplée. Le time.sleep(2) entre les pages étale les requêtes. Ajustez max_pages pour contrôler jusqu'où dans le classement du marché vous allez ; la première page seule couvre déjà les plus grandes cryptos par capitalisation boursière.

Étape 5 : Assembler le script complet

Assemblez maintenant les pièces en un seul script exécutable : collectez les coins sur plusieurs pages, puis exportez les enregistrements en JSON et CSV.

python
import csv
import json
import time
from crawlbase import CrawlingAPI
from bs4 import BeautifulSoup

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_JS_TOKEN"})

OPTIONS = {
    "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/122.0",
    "ajax_wait": "true",
    "page_wait": 5000,
}

ROW_SELECTOR = 'table[data-coin-table-target="table"] > tbody > tr'

def crawl(page_url):
    response = api.get(page_url, OPTIONS)
    if response["headers"]["cb_status"] == "200":
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['headers']['cb_status']}")
    return None

def fetch_html(page_url, max_retries=2):
    for attempt in range(max_retries + 1):
        html = crawl(page_url)
        if html:
            return html
        if attempt < max_retries:
            time.sleep(1)
    return None

def text_of(node, selector):
    el = node.select_one(selector)
    return el.get_text(strip=True) if el else None

def parse_row(row):
    return {
        "name": text_of(row, 'td[data-view-component="true"] a span.tw-text-gray-700'),
        "symbol": text_of(row, 'td[data-view-component="true"] a span.tw-text-gray-500'),
        "price": text_of(row, 'td[data-target="price.price"]'),
        "change_24h": text_of(row, 'td.tw-text-right span[data-target="price-change-percentage-24h"]'),
        "volume_24h": text_of(row, 'td.tw-text-right span[data-coin-table-target="totalVolume"]'),
        "market_cap": text_of(row, 'td.tw-text-right span[data-coin-table-target="marketCap"]'),
    }

def parse_market(html):
    soup = BeautifulSoup(html, "html.parser")
    rows = soup.select(ROW_SELECTOR)
    return [parse_row(r) for r in rows if r.select_one('td[data-target="price.price"]')]

def collect_all_coins(base_url, max_pages):
    records = []
    for page in range(1, max_pages + 1):
        html = fetch_html(f"{base_url}?page={page}")
        if not html:
            continue
        page_coins = parse_market(html)
        if not page_coins:
            break
        records.extend(page_coins)
        time.sleep(2)
    return records

def save_outputs(records):
    with open("crypto_market.json", "w") as f:
        json.dump(records, f, indent=2)
    if not records:
        return
    with open("crypto_market.csv", "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=records[0].keys())
        writer.writeheader()
        writer.writerows(records)

def main():
    market_url = "https://www.coingecko.com/"
    coins = collect_all_coins(market_url, max_pages=2)
    save_outputs(coins)
    print(f"Saved {len(coins)} coins")

if __name__ == "__main__":
    main()

Le script collecte les enregistrements de coins sur jusqu'à deux pages de marché et rythme la boucle avec une pause de deux secondes. save_outputs écrit à la fois un fichier JSON et un CSV en utilisant les clés du premier enregistrement comme en-tête, vous disposez ainsi des données dans la forme que votre outil en aval préfère. Ajustez max_pages et l'URL du marché selon la portion du classement que vous souhaitez couvrir.

À quoi ressemble la sortie

Exécutez le script complet avec python crypto_scraper.py et vous obtenez un enregistrement structuré propre par coin, prêt pour l'analyse, une base de données ou un tableur.

json
[
  {
    "name": "Bitcoin",
    "symbol": "BTC",
    "price": "$86,650.00",
    "change_24h": "2.4%",
    "volume_24h": "$28,540,118,233",
    "market_cap": "$1,712,884,991,402"
  },
  {
    "name": "Ethereum",
    "symbol": "ETH",
    "price": "$2,015.42",
    "change_24h": "1.1%",
    "volume_24h": "$14,902,551,870",
    "market_cap": "$243,118,440,905"
  }
]

Le CSV correspondant porte les mêmes colonnes, une ligne par coin, ce qui s'intègre directement dans pandas ou n'importe quel tableur pour trier par capitalisation boursière, filtrer par variation sur 24 heures ou visualiser le volume. Les valeurs ci-dessus sont illustratives ; les cours et pourcentages en direct changent en permanence, c'est précisément la raison pour laquelle vous les récupérez selon un calendrier plutôt qu'une seule fois.

Rester disponible à grande échelle

Même avec le rendu géré, un site de marché à fort trafic surveille le trafic qui ressemble à du scraping. Quelques habitudes maintiennent une exécution longue en bonne santé, et elles s'appliquent à toute cible commerciale difficile.

  • Rythmez vos requêtes. Marteler les pages en boucle serrée est le moyen le plus rapide d'être limité ou bloqué. Les pauses de deux secondes ci-dessus sont le minimum, pas le maximum ; élargissez-les pour les grands travaux et évitez de récupérer la même page selon un cycle rapide.
  • Misez sur la rotation. Un pool d'IP résidentielles répartit les requêtes sur de nombreuses adresses d'utilisateurs réels pour qu'aucune seule ne déclenche une limite de taux. La Crawling API s'en charge pour vous ; si vous montez votre propre stack, c'est la partie à maîtriser.
  • Lisez les codes de statut. Une exécution qui commence à retourner des valeurs cb_status non-200 vous indique que le taux actuel ou le niveau d'IP n'est plus suffisant. Traitez cela comme un signal pour ralentir, pas comme du bruit à ignorer.

Pour les crawls plus importants, le Crawler asynchrone met les requêtes en file d'attente et livre les résultats vers un webhook, ce qui convient pour exécuter de nombreuses pages de marché sans maintenir des connexions ouvertes. Pour le guide complet, voir comment scraper des sites sans être bloqué. Si vous voulez alimenter ces données dans un workflow de surveillance, la même approche s'applique à l'intelligence sur les prix, et un guide annexe couvre le scraping des cours crypto sur CoinMarketCap si vous souhaitez une deuxième source.

Est-il légal de scraper des données de marché crypto ?

Le fait de scraper un site de marché crypto est autorisé ou non selon les conditions d'utilisation de ce site, votre juridiction et ce que vous faites des données. Des sites comme CoinGecko publient leurs tableaux de marché en accès libre, et les chiffres eux-mêmes (cours, variation sur 24 heures, volume, capitalisation boursière) sont des données de marché publiques factuelles plutôt que des données personnelles, ce qui rend le jeu de champs de ce guide peu risqué sur le plan de la vie privée. Cela ne vous exempte pas des conditions d'utilisation du site pour autant : la plupart des sites de marché restreignent l'accès automatisé intensif dans leurs Conditions d'utilisation, alors lisez ces conditions ainsi que le robots.txt du site et traitez les deux comme la limite de ce que vous collectez et en quelle quantité.

Quelques lignes à respecter. Collectez uniquement des données de marché publiques, les chiffres que tout visiteur voit sans compte, et maintenez votre volume de requêtes suffisamment bas pour ne pas surcharger les serveurs du site. Ne scrapez rien derrière un login, un paywall ou un compte, et ne collectez pas ni ne construisez de profils autour de données personnelles, ce qui est hors périmètre ici et ferait entrer en jeu les obligations RGPD et CCPA. Respectez les droits d'auteur sur tout contenu éditorial qu'un site de marché publie à côté de ses tableaux : les chiffres de cours sont des faits, mais une analyse de marché rédigée ne vous appartient pas pour être republiée.

Pour un usage en production, la voie plus propre est l'API officielle. La plupart des sites de marché crypto, CoinGecko inclus, proposent une API publique qui retourne les mêmes champs de cours, volume et capitalisation boursière en JSON structuré avec des limites de taux et des conditions claires. Une API est plus stable que les sélecteurs HTML, elle ne se casse pas quand la mise en page change et vous maintient dans les règles d'utilisation autorisée du fournisseur. Scrapez la page rendue pour un usage ponctuel ou un champ que l'API n'expose pas ; préférez l'API officielle ou un flux de données sous licence quand vous construisez quelque chose de durable ou commercial.

Récapitulatif

Points clés

  • Les tableaux de marché sont rendus côté client. Une simple requête retourne une coquille vide avec un tableau vide, vous devez donc rendre la page avant de l'analyser.
  • Vous avez besoin du rendu et d'une IP de confiance ensemble. La Crawling API avec un token JS fait les deux en un seul appel ; ajax_wait et page_wait contrôlent le temps d'attente pour le contenu.
  • Analysez ligne par ligne. Lisez chaque tr comme un coin et mappez ses cellules sur le nom, le symbole, le cours, la variation sur 24 heures, le volume sur 24 heures et la capitalisation boursière, pour que chaque champ reste aligné sur le bon coin.
  • Paginez et exportez. Parcourez le paramètre ?page= jusqu'à un plafond, rythmez l'exécution avec de courtes pauses et écrivez les enregistrements en JSON et CSV.
  • Préférez l'API officielle pour la production. Restez sur les données de marché publiques, respectez les CGU et le robots.txt du site, et utilisez l'API publique du fournisseur ou un flux sous licence pour tout usage durable ou commercial.

Foire aux questions

Pourquoi une simple requête retourne-t-elle un tableau crypto vide ?

Parce que la page de marché charge ses lignes côté client avec JavaScript. Le HTML initial est une coquille qui ne se remplit qu'après l'exécution des scripts dans un navigateur, donc une requête HTTP brute retourne un statut 200 avec le tableau vide. Pour obtenir les lignes, vous devez d'abord rendre la page, ce que le token JS de la Crawling API gère pour vous.

Ai-je besoin du token normal ou du token JS ici ?

Le token JS. Le token normal récupère le HTML statique, qui sur une page de marché crypto est la même coquille avec tableau vide qu'une simple requête retourne. Le token JS rend d'abord la page dans un vrai navigateur, les lignes de coins sont donc présentes quand BeautifulSoup les analyse.

Quels champs puis-je extraire d'une page de marché ?

Les chiffres publics par coin : le nom et le symbole du ticker, le cours actuel, le pourcentage de variation sur 24 heures, le volume de trading sur 24 heures et la capitalisation boursière. Restez sur les données visibles par tout visiteur sans compte, et traitez les analyses de marché rédigées ou le contenu éditorial comme protégés par le droit d'auteur, pas comme quelque chose à republier.

Mes sélecteurs retournent None. Qu'est-ce qui a changé ?

Presque certainement le balisage du site. Les noms de classes générés et les attributs data-target (les hooks data-coin-table-target, les classes de cellules alignées à droite) changent sans préavis, donc des sélecteurs qui fonctionnaient le mois dernier peuvent se casser. Réinspectez une page en direct dans les outils de développement de votre navigateur et mettez à jour les sélecteurs. La maintenance périodique des sélecteurs est normale pour tout scraper en production.

Dois-je scraper la page ou utiliser l'API officielle ?

Pour tout usage durable ou commercial, préférez l'API officielle. La plupart des sites de marché crypto, y compris CoinGecko, exposent une API publique qui retourne les données de cours, volume et capitalisation boursière en JSON structuré selon des conditions et limites de taux claires, ce qui est plus stable que l'analyse HTML. Le scraping de la page rendue convient mieux pour un usage ponctuel ou pour un champ que l'API n'expose pas.

À quelle fréquence dois-je collecter des données de marché crypto ?

Cela dépend de votre cas d'usage. Pour un tableau de bord quasi-temps réel, vous pourriez récupérer toutes les quelques minutes ; pour une recherche sur les tendances, des instantanés horaires ou quotidiens suffisent généralement. Quelle que soit la cadence, rythmez vos requêtes et respectez les limites de taux du site pour qu'un calendrier fréquent ne devienne pas du trafic de scraping que le site bloque.

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