Excel reste l'espace de travail où une grande partie de l'analyse se déroule réellement. Une fois qu'un jeu de données atterrit dans un tableur, vous pouvez le trier, le filtrer, en faire des graphiques et le transmettre à un collègue qui n'aura jamais à toucher un terminal. Le hic, c'est d'abord d'y faire entrer des données propres et structurées, et copier des lignes depuis une page web à la main est lent, sujet aux erreurs et impossible à répéter selon un calendrier.
Ce guide vous montre comment scraper des données d'un site web vers Excel avec Python. Vous construisez un petit script exécutable qui récupère une page rendue via la Crawling API, analyse les enregistrements qui vous intéressent avec BeautifulSoup, et écrit un fichier .xlsx propre avec une ligne d'en-tête, un enregistrement par ligne et une mise en forme de base à l'aide d'openpyxl. Le guide reste sur une page d'exemple neutre et des données publiques, de sorte que vous pouvez exécuter chaque étape de bout en bout avant de le pointer sur quelque chose qui vous appartient.
Ce que vous allez construire
Un script Python qui récupère une page de liste publique via la Crawling API, extrait un enregistrement structuré par élément et enregistre l'ensemble dans un classeur Excel mis en forme. L'exemple courant utilise une page de catalogue public générique à une URL d'espace réservé, alors remplacez-la par votre propre cible une fois que le flux fonctionne. Nous extrayons ces champs :
- Titre le nom ou l'intitulé de chaque élément.
- Prix le prix affiché tel qu'il apparaît sur la page.
- Disponibilité l'étiquette de stock ou de statut.
- Note le score d'avis lorsque la page en expose un.
- Lien l'URL canonique de la page propre à l'élément.
La sortie est un seul tableur avec ces colonnes, une ligne d'en-tête en gras et figée, et des colonnes dimensionnées automatiquement, prêt à trier, filtrer ou représenter graphiquement dans Excel ou Google Sheets.
Pourquoi une simple requête échoue souvent
L'ancienne façon de faire entrer des données web dans Excel était la requête intégrée À partir du Web : collez une URL, laissez Excel extraire les tableaux et actualisez selon un minuteur. Elle existe encore, mais elle casse sur la plupart des sites modernes pour deux raisons, et ces deux mêmes raisons font trébucher une requête Python naïve.
D'abord, beaucoup de pages rendent leur contenu dans le navigateur avec JavaScript. Le HTML initial qu'un client HTTP nu reçoit est une coquille mince, et les prix, les titres et les étiquettes de stock n'apparaissent qu'après l'exécution des scripts de la page. Extrayez les données de cette première réponse et vous capturez un modèle vide au lieu des vraies lignes. Ensuite, les sites surveillent le trafic automatisé. 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, bloqués par IP ou se voient présenter un CAPTCHA avant même d'atteindre le contenu, ce qui est exactement ce qui arrive quand une actualisation automatique d'Excel frappe un site trop souvent depuis une seule adresse.
Un scraper fiable a donc besoin de deux choses dans une seule requête : un navigateur qui rend réellement la page, et une IP que le site interprète comme un vrai visiteur. Vous pouvez construire cela vous-même avec un navigateur headless plus un pool de proxys résidentiels rotatifs, mais maintenir cette pile en bonne santé représente l'essentiel du travail. La Crawling API regroupe les deux en un seul appel : vous lui envoyez l'URL, elle rend la page derrière une IP de confiance, et elle renvoie un HTML fini que vous pouvez analyser.
Crawlbase vous donne deux types de token. Le token normal récupère le HTML statique et est le bon choix quand les données sont déjà dans le code source de la page. Le token JavaScript (JS) rend d'abord la page dans un vrai navigateur, ce dont vous avez besoin quand le contenu se charge côté client. Commencez par le token normal ; passez au token JS seulement si les champs reviennent vides.
Prérequis
Il vous faut quelques éléments en place avant d'écrire le moindre code. Aucun ne prend longtemps.
Python de base. Vous devez être à l'aise pour écrire et lancer un script et installer des paquets avec pip. Si le volet analyse est nouveau pour vous, le guide BeautifulSoup est un bon compagnon, et le guide plus large sur le scraping avec Python couvre les fondamentaux.
Python 3.8 ou ultérieur. 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. Inscrivez-vous, ouvrez votre dashboard et copiez votre token depuis la page de documentation du compte. Crawlbase inclut jusqu'à 20 000 requêtes gratuites pour démarrer, ce qui est largement suffisant pour suivre ce guide, et vous ne payez que pour les requêtes réussies. Traitez le token comme un mot de passe et gardez-le hors du contrôle de version.
Mettre en place le projet
Créez un environnement virtuel pour que les dépendances du projet restent isolées, puis installez les trois bibliothèques dont le script a besoin.
python --version python -m venv excel_env source excel_env/bin/activate pip install crawlbase beautifulsoup4 openpyxl
Sur Windows, activez l'environnement avec excel_env\Scripts\activate au lieu de la ligne source. Trois dépendances font le travail : crawlbase est le client officiel de la Crawling API, beautifulsoup4 analyse le HTML renvoyé pour que vous puissiez extraire les champs individuels par sélecteur CSS, et openpyxl écrit le fichier .xlsx avec la mise en forme. Si vous préférez travailler en DataFrames, pandas peut écrire de l'Excel aussi, et il y a une courte note à ce sujet vers la fin.
Étape 1 : Récupérer une page via Crawlbase
Commencez par obtenir une page finie. Importez la classe CrawlingAPI, initialisez-la avec votre token et demandez l'URL cible. Vérifier le cb_status (legacy pc_status) de Crawlbase avant d'analyser garde les échecs bruyants plutôt que silencieux, pour que vous n'essayiez jamais de scraper une page d'erreur.
from crawlbase import CrawlingAPI api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) def crawl(page_url): response = api.get(page_url) 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__": catalog_url = "https://example.com/products" html = crawl(catalog_url) print(html[:500] if html else "No HTML returned")
Lancez ceci avec python excel_scraper.py et vous devriez voir les 500 premiers caractères du véritable balisage de la page, ce qui confirme que la requête fonctionne avant d'écrire le moindre sélecteur. Si la page rend ses données côté client, le corps ressemblera à un modèle vide ; dans ce cas, ajoutez le token JS en passant {"token": "YOUR_CRAWLBASE_TOKEN", "javascript": "true"} lorsque vous créez le client, et l'API la rendra d'abord dans un navigateur. Pour l'exemple de catalogue neutre ici, le token normal suffit.
L'étape de récupération ci-dessus est la partie qui casse discrètement la propre requête À partir du Web d'Excel à tout volume : une seule IP qui actualise un site se fait limiter, et les pages rendues côté client renvoient une coquille vide. La Crawling API prend votre token, rend la page quand c'est nécessaire et fait tourner des IP résidentielles côté serveur, puis vous remet un HTML fini, ce qui vous évite d'exploiter une flotte de navigateurs headless et un pool de proxys vous-même. Pointez-la d'abord vers une page publique sur le palier gratuit.
Étape 2 : Analyser les enregistrements voulus
Une page de catalogue est une grille de cartes d'éléments, chacune avec un titre, un prix, une étiquette de stock et un lien. Chargez le HTML rendu dans BeautifulSoup, sélectionnez chaque carte et lisez les champs de chacune. Protéger chaque recherche signifie qu'une carte à laquelle il manque un champ renvoie None au lieu de faire planter la boucle.
from bs4 import BeautifulSoup def text_of(card, selector): el = card.select_one(selector) return el.get_text(strip=True) if el else None def parse_records(html, base_url): soup = BeautifulSoup(html, "html.parser") records = [] for card in soup.select("article.product"): link_el = card.select_one("a.product-link") href = link_el["href"] if link_el else None records.append({ "title": text_of(card, "h2.product-title"), "price": text_of(card, "span.price"), "availability": text_of(card, "span.stock"), "rating": text_of(card, "span.rating"), "link": urljoin(base_url, href) if href else None, }) return records
L'utilitaire text_of interroge un élément à l'intérieur d'une carte et renvoie son texte nettoyé, ou None quand l'élément est absent. L'appel select("article.product") renvoie chaque carte d'élément, et la boucle lit le titre, le prix, la disponibilité et la note de chacune. urljoin transforme un href relatif en URL complète pour que la colonne de lien soit utilisable telle quelle. Les sélecteurs ici (article.product, h2.product-title, span.price) sont illustratifs ; sur une vraie cible, vous inspectez la page dans les outils de développement de votre navigateur et les remplacez par les noms de classes réels.
Les noms de classes générés et le balisage de mise en page changent sans préavis sur les sites de production. Traitez tout sélecteur comme un modèle de départ, pas comme un contrat. Quand les enregistrements reviennent vides, ré-inspectez la page en direct dans les outils de développement et mettez à jour le sélecteur. La maintenance périodique des sélecteurs est normale pour tout scraper, et non le signe que quelque chose est cassé.
Étape 3 : Écrire les enregistrements dans Excel avec openpyxl
Transformez maintenant la liste d'enregistrements en tableur. openpyxl construit un classeur en mémoire : vous créez une feuille, écrivez une ligne d'en-tête en gras, ajoutez une ligne par enregistrement, figez l'en-tête, dimensionnez les colonnes selon leur contenu, puis enregistrez. La fonction ci-dessous prend les enregistrements et un nom de fichier et fait tout cela.
from openpyxl import Workbook from openpyxl.styles import Font from openpyxl.utils import get_column_letter HEADERS = ["Title", "Price", "Availability", "Rating", "Link"] KEYS = ["title", "price", "availability", "rating", "link"] def save_to_excel(records, filename="products.xlsx"): wb = Workbook() ws = wb.active ws.title = "Products" ws.append(HEADERS) for cell in ws[1]: cell.font = Font(bold=True) for record in records: ws.append([record.get(key) for key in KEYS]) ws.freeze_panes = "A2" for i, header in enumerate(HEADERS, start=1): column = ws[get_column_letter(i)] width = max(len(str(c.value)) for c in column if c.value) ws.column_dimensions[get_column_letter(i)].width = width + 2 wb.save(filename) print(f"Saved {len(records)} rows to {filename}")
Quelques détails rendent la feuille agréable à utiliser. ws.append(HEADERS) écrit les titres de colonnes, et la boucle sur ws[1] met cette première ligne en gras. freeze_panes = "A2" épingle l'en-tête pour qu'il reste visible pendant que vous faites défiler. La boucle de largeur de colonne mesure la valeur la plus longue de chaque colonne et règle la largeur pour qu'elle s'y adapte, avec un peu de marge, pour que rien ne soit coupé. Lire les valeurs via record.get(key) signifie qu'un enregistrement auquel il manque un champ écrit une cellule vide au lieu de lever une erreur. Le résultat est un classeur soigné que vous pouvez ouvrir dans Excel, Numbers ou Google Sheets.
Étape 4 : Assembler le script complet
Reliez maintenant les trois pièces en un seul fichier exécutable : récupérer la page, analyser les enregistrements et enregistrer le tableur.
from urllib.parse import urljoin from crawlbase import CrawlingAPI from bs4 import BeautifulSoup from openpyxl import Workbook from openpyxl.styles import Font from openpyxl.utils import get_column_letter api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) HEADERS = ["Title", "Price", "Availability", "Rating", "Link"] KEYS = ["title", "price", "availability", "rating", "link"] def crawl(page_url): response = api.get(page_url) if response["headers"]["cb_status"] == "200": return response["body"].decode("utf-8") print(f"Request failed: {response['headers']['cb_status']}") return None def text_of(card, selector): el = card.select_one(selector) return el.get_text(strip=True) if el else None def parse_records(html, base_url): soup = BeautifulSoup(html, "html.parser") records = [] for card in soup.select("article.product"): link_el = card.select_one("a.product-link") href = link_el["href"] if link_el else None records.append({ "title": text_of(card, "h2.product-title"), "price": text_of(card, "span.price"), "availability": text_of(card, "span.stock"), "rating": text_of(card, "span.rating"), "link": urljoin(base_url, href) if href else None, }) return records def save_to_excel(records, filename="products.xlsx"): wb = Workbook() ws = wb.active ws.title = "Products" ws.append(HEADERS) for cell in ws[1]: cell.font = Font(bold=True) for record in records: ws.append([record.get(key) for key in KEYS]) ws.freeze_panes = "A2" for i, header in enumerate(HEADERS, start=1): column = ws[get_column_letter(i)] width = max(len(str(c.value)) for c in column if c.value) ws.column_dimensions[get_column_letter(i)].width = width + 2 wb.save(filename) print(f"Saved {len(records)} rows to {filename}") def main(): catalog_url = "https://example.com/products" html = crawl(catalog_url) if not html: return records = parse_records(html, catalog_url) save_to_excel(records) if __name__ == "__main__": main()
La fonction main récupère la page de catalogue, l'analyse en une liste d'enregistrements et enregistre le tableur. Sortir tôt quand la récupération échoue empêche l'exécution d'écrire un fichier vide sur une mauvaise réponse. Ajustez le catalog_url et les sélecteurs dans parse_records pour qu'ils correspondent à votre propre cible, et le reste du script reste le même.
À quoi ressemble la sortie
Lancez le script complet avec python excel_scraper.py et vous obtenez un fichier products.xlsx avec une ligne d'en-tête en gras, une ligne par élément et des colonnes dimensionnées selon leur contenu. Conceptuellement, les données atterrissent ainsi :
Title,Price,Availability,Rating,Link Wireless Mouse,$24.99,In stock,4.5,https://example.com/products/wireless-mouse Mechanical Keyboard,$79.00,In stock,4.7,https://example.com/products/mechanical-keyboard USB-C Hub,$39.50,Out of stock,4.2,https://example.com/products/usb-c-hub Laptop Stand,$32.00,In stock,4.6,https://example.com/products/laptop-stand
Le tableur porte ces mêmes cinq colonnes avec l'en-tête figé, donc vous pouvez trier par prix, filtrer sur la disponibilité ou représenter les notes en graphique sans aucun nettoyage supplémentaire. À partir d'ici, les données sont du simple contenu tabulaire, ce qui signifie qu'elles se déplacent aussi proprement vers d'autres formats ; pour les compromis entre les formes adaptées aux tableurs et celles adaptées au code, voyez JSON vs CSV.
Passer à l'échelle sur plusieurs pages
Une seule page de catalogue est généralement une tranche d'un ensemble plus large. La plupart des listes paginent avec un paramètre de requête ou un segment de chemin, donc vous récupérez chaque page, l'analysez et collectez les enregistrements dans une seule liste avant d'écrire le classeur. Une courte pause entre les requêtes garde l'exécution polie.
import time def collect_all(base_url, max_pages): all_records = [] for page in range(1, max_pages + 1): page_url = f"{base_url}?page={page}" html = crawl(page_url) if not html: break records = parse_records(html, page_url) if not records: break all_records.extend(records) time.sleep(2) return all_records
Remplacez l'unique appel crawl dans main par collect_all(catalog_url, max_pages=5), puis passez la liste combinée à save_to_excel. La boucle s'arrête tôt quand une page ne renvoie rien ou aucun enregistrement, donc vous n'avez pas à connaître le nombre exact de pages à l'avance. Le time.sleep(2) entre les requêtes rythme l'exécution. Pour des travaux bien plus volumineux, le Crawler asynchrone met les requêtes en file d'attente et livre les résultats à un webhook, ce qui convient au crawl de nombreuses pages sans maintenir des connexions ouvertes.
Si vous travaillez déjà en DataFrames, vous pouvez sauter la construction manuelle de feuille d'openpyxl : pandas.DataFrame(records).to_excel("products.xlsx", index=False) écrit les mêmes colonnes en une ligne (il utilise openpyxl en interne). Vous perdez la mise en forme par colonne de l'Étape 3 mais gagnez tout ce que pandas offre pour le nettoyage et l'analyse. Voyez le guide d'analyse pandas pour la suite.
Scraper de façon responsable
Faire entrer des données dans un tableur est la partie facile ; les collecter de façon responsable est la partie qui garde votre projet défendable. Tenez-vous à quelques règles quelle que soit la cible. Ne scrapez que des données publiques que n'importe quel visiteur peut voir sans se connecter, et restez à l'écart de tout ce qui est derrière une authentification. Lisez les conditions d'utilisation du site et son robots.txt, et traitez les deux comme la limite de ce que vous collectez. Gardez votre débit de requêtes raisonnable pour ne pas surcharger les serveurs du site ; les courts sleeps de la boucle de pagination ci-dessus sont un plancher sensé, pas un plafond.
Quand les données concernent des personnes, la barre est plus haute. Les données personnelles sont réglementées par des cadres comme le RGPD et le CCPA, alors évitez de collecter des noms, des coordonnées ou quoi que ce soit lié à des individus identifiables à moins d'avoir une base légale claire et un besoin réel. Pour la plupart des travaux d'analyse, vous n'en avez pas, et un catalogue de champs de produits publics comme celui de ce guide reste bien à l'écart de cette ligne. Utilisé de cette façon, le scraping vers Excel est un moyen routinier et à faible risque de garder un jeu de données à jour.
Points clés
- La propre requête À partir du Web d'Excel casse à grande échelle. Une seule IP qui actualise un site se fait limiter et les pages rendues côté client renvoient une coquille vide, c'est pourquoi un scraper piloté par le code est plus fiable.
-
Récupérez via la Crawling API. Un seul appel rend la page quand c'est nécessaire et fait tourner les IP côté serveur, en renvoyant un HTML fini ; vérifiez
cb_statusavant d'analyser pour que les échecs restent bruyants. -
Analysez de façon défensive. Sélectionnez chaque carte, lisez les champs avec un utilitaire protégé qui renvoie
Noneen cas d'absence, et attendez-vous à mettre à jour les sélecteurs quand le balisage d'un site dérive. -
Écrivez un classeur propre avec openpyxl. Un en-tête en gras et figé, une ligne par enregistrement et des colonnes dimensionnées automatiquement vous donnent une feuille prête à trier, filtrer ou représenter en graphique, ou utilisez le
to_excelde pandas pour une seule ligne. - Scrapez de façon responsable. Restez sur les données publiques, respectez les CGU et le robots.txt, rythmez vos requêtes et appliquez la prudence RGPD ou CCPA dès que des données personnelles sont en jeu.
Foire aux questions
Puis-je scraper un site web directement dans Excel sans écrire de code ?
La requête intégrée À partir du Web d'Excel (sous le ruban Données) peut extraire des tableaux depuis une URL sans code, et elle fonctionne pour des pages simples, statiques et basées sur des tableaux. Elle peine sur les sites modernes qui rendent le contenu avec JavaScript, et une actualisation automatique planifiée depuis une seule IP a tendance à se faire limiter ou bloquer. Pour tout ce qui dépasse les tableaux statiques simples, un petit script Python qui récupère via la Crawling API et écrit le classeur est bien plus fiable.
Faut-il utiliser openpyxl ou pandas pour écrire le fichier Excel ?
Les deux fonctionnent, et pandas utilise openpyxl en interne. Utilisez openpyxl directement quand vous voulez le contrôle de la mise en forme comme les en-têtes en gras, les volets figés et les largeurs de colonnes, comme montré à l'Étape 3. Utilisez pandas.to_excel quand vous travaillez déjà en DataFrames et voulez un export en une ligne ; vous abandonnez la mise en forme manuelle mais gagnez tout ce que pandas offre pour le nettoyage et l'analyse.
Ai-je besoin du token normal ou du token JS ?
Commencez par le token normal. Il récupère le HTML statique et suffit dès que les données sont déjà dans le code source de la page, ce qui couvre de nombreuses pages de catalogue et de liste. Passez au token JS seulement quand les champs reviennent vides, ce qui signifie que la page rend son contenu côté client et a besoin d'un vrai navigateur. Le token JS rend d'abord la page, puis renvoie le HTML fini.
Mes enregistrements analysés sont vides. Qu'est-ce qui n'a pas marché ?
Généralement l'une de deux choses. Soit les sélecteurs ne correspondent pas à la page en direct, auquel cas vous la ré-inspectez dans les outils de développement de votre navigateur et les mettez à jour, soit la page rend côté client et le token normal a renvoyé une coquille vide, auquel cas vous passez au token JS. Affichez les premières centaines de caractères du HTML pour voir dans quel cas vous êtes avant de changer quoi que ce soit d'autre.
Comment scraper plus d'une page de résultats dans le même tableur ?
Bouclez sur les pages, analysez chacune et collectez les enregistrements dans une seule liste avant d'écrire le classeur. La fonction collect_all de la section sur la montée en charge montre le schéma : elle parcourt les pages jusqu'à ce que l'une ne renvoie aucun enregistrement, avec un court sleep entre les requêtes, puis vous passez la liste combinée à save_to_excel une seule fois.
Est-il légal de scraper des données vers Excel ?
Scraper des données publiques pour votre propre analyse est généralement acceptable, mais cela dépend des conditions d'utilisation du site, de votre juridiction et de ce que vous faites des données. Restez sur les pages publiques, respectez les conditions du site et son robots.txt, gardez votre débit de requêtes raisonnable, et appliquez la prudence RGPD ou CCPA dès que les données concernent des personnes identifiables. Pour un usage en masse ou commercial, vérifiez si le site propose une API officielle ou une licence de données.
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.
