Les pages de recherche et de produits de Best Buy sont une fenêtre publique sur l'un des plus grands catalogues d'électronique grand public d'Amérique du Nord. Chaque résultat de recherche et chaque page de produit porte les mêmes quelques champs visibles par tous : le nom du produit, son prix, le numéro de modèle et le SKU, une note en étoiles, et si l'article est en stock. Ce sont exactement les signaux que les analystes tarifaires, les chercheurs de marché et les acheteurs technologiques suivent lorsqu'ils veulent surveiller l'évolution des prix de l'électronique ou comparer la disponibilité dans une catégorie.
Ce guide vous montre comment extraire les données produits de Best Buy avec Python. Vous construisez un scraper simple et fonctionnel qui récupère les pages de recherche et de produits de Best Buy via la Crawling API, analyse un enregistrement propre pour chaque produit, gère la pagination sur plusieurs pages de résultats et exporte les résultats en JSON et CSV. L'ensemble du tutoriel se limite aux données de catalogue publiques : les titres, prix, modèles, notes et disponibilités que tout le monde peut lire sur Best Buy sans se connecter.
Ce que vous allez construire
Un script Python qui prend une URL de recherche Best Buy, récupère la page rendue via la Crawling API et extrait un enregistrement structuré par produit. Nous utilisons une recherche de "i phone" comme exemple, la même requête utilisée dans l'ancien tutoriel, et extrayons ces champs de chaque fiche produit :
- Titre le nom du produit affiché sur la fiche.
- Prix le prix client actuel, lorsque le produit en affiche un.
- Modèle / SKU le numéro de modèle du fabricant et le propre identifiant SKU de Best Buy.
- Note la note moyenne en étoiles, avec le nombre d'avis à côté.
- Disponibilité si l'article est en stock, épuisé ou disponible à la livraison.
- URL du produit le lien absolu vers la propre page de détail du produit.
Pourquoi une requête ordinaire échoue sur Best Buy
Si vous pointez un client HTTP brut vers une URL de recherche Best Buy, vous n'obtenez presque jamais la liste de produits souhaitée. Best Buy affiche ses résultats de recherche côté client : le serveur envoie une coquille légère et le JavaScript de la page remplit les fiches produit ensuite. Le HTML brut que vous récupérez d'un simple requests.get() est donc entièrement dépourvu de produits, et votre parseur ne trouve rien.
Le deuxième problème est la détection des robots. Best Buy signale rapidement le trafic automatisé. Les plages d'adresses IP de datacenter et les schémas de requêtes qui ne ressemblent pas à un vrai navigateur se heurtent à une limitation de débit, une page de défi ou un blocage pur et simple avant d'atteindre les produits. Un scraper Best Buy fonctionnel a donc besoin de deux choses en une seule requête : un navigateur qui affiche la page, et une adresse IP que Best Buy considère comme un vrai acheteur. Vous pouvez construire cela vous-même avec un navigateur sans interface graphique et un pool de proxies résidentiels rotatifs, mais maintenir ce stack représente l'essentiel du travail. La Crawling API combine les deux en un seul appel : vous lui envoyez l'URL de recherche, elle affiche la page depuis une adresse IP résidentielle fiable, gère la rotation et la résolution de CAPTCHA, et retourne le HTML final à analyser.
Prérequis
Vous avez besoin de quelques éléments en place avant d'écrire du code. Aucun ne prend beaucoup de temps.
Python de base. Vous devez être à l'aise pour écrire et exécuter un script Python et installer des paquets avec pip. Si vous êtes nouveau dans le langage, la documentation officielle de Python ou n'importe quel cours pour débutants couvre le niveau que ce tutoriel suppose.
Python 3.8 ou une version ultérieure. Vérifiez votre version avec python --version (ou python3 --version). Si vous ne l'avez pas, installez-le depuis python.org et assurez-vous que Python est dans votre PATH système.
Un compte Crawlbase et un token. Inscrivez-vous pour un compte gratuit, ouvrez votre tableau de bord et copiez votre token depuis la page de documentation du compte. Le niveau gratuit inclut jusqu'à 20 000 requêtes sans carte, ce qui est amplement suffisant pour construire et tester ce scraper. Best Buy est un site à rendu JavaScript, utilisez donc le token de requête JavaScript ici. Traitez le token comme un mot de passe et gardez-le hors du contrôle de version.
Configurer le projet
Créez un environnement virtuel pour que les dépendances du projet restent isolées, puis installez les bibliothèques dont le scraper a besoin. crawlbase est le client officiel pour la Crawling API, et beautifulsoup4 analyse le HTML retourné pour que vous puissiez extraire chaque champ des fiches produit par sélecteur CSS.
python --version python -m venv bestbuy_env source bestbuy_env/bin/activate pip install crawlbase beautifulsoup4
Sur Windows, activez l'environnement avec bestbuy_env\Scripts\activate au lieu de la ligne source. Avec les deux bibliothèques installées, créez le fichier de script que le reste du guide complète :
touch bestbuy_scraper.py
Comprendre la page de recherche Best Buy
Une recherche Best Buy se trouve à une URL stable sur le point de terminaison searchpage.jsp, avec votre requête dans le paramètre st. Une recherche de "i phone" est https://www.bestbuy.com/site/searchpage.jsp?st=i+phone. La page présente une liste ordonnée de fiches produit, une par article, chacune portant les mêmes champs : un titre, un prix, un modèle et SKU, une note en étoiles avec un nombre d'avis, et un état de disponibilité.
Avant d'écrire des sélecteurs, ouvrez une page de recherche dans votre navigateur, faites un clic droit sur une fiche produit et choisissez Inspecter. Best Buy enveloppe l'ensemble des résultats dans un ol.sku-item-list et chaque produit dans un conteneur li.sku-item, puis divise chaque fiche en un column-middle (titre, modèle, SKU, note) et un column-right (prix, disponibilité). Ce sont les éléments que vous ciblez. Les noms de classes de Best Buy évoluent dans le temps, traitez donc les sélecteurs ci-dessous comme un modèle de départ à vérifier par rapport à la page en direct, pas comme un contrat permanent.
Étape 1 : Récupérer la page de recherche rendue
Commencez par obtenir la page finale. Importez la classe CrawlingAPI, initialisez-la avec votre token, construisez l'URL de recherche et demandez-la. Vérifier le cb_status (legacy pc_status) de Crawlbase avant d'analyser rend les échecs visibles plutôt que silencieux.
from crawlbase import CrawlingAPI from urllib.parse import quote_plus api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) def crawl(page_url): options = {"ajax_wait": "true", "page_wait": 5000} response = api.get(page_url, options) if response["headers"]["cb_status"] == "200": return response["body"].decode("utf-8") print(f"Request failed. Crawlbase status: {response['headers']['cb_status']}") return None if __name__ == "__main__": search_term = "i phone" search_url = f"https://www.bestbuy.com/site/searchpage.jsp?st={quote_plus(search_term)}" html = crawl(search_url) print(html[:500] if html else "No HTML returned")
Les deux options d'attente sont importantes pour une liste qui se remplit après le chargement. ajax_wait demande à l'API d'attendre que la grille de produits asynchrone finisse de se charger, et page_wait attend 5 000 millisecondes fixes après le chargement pour que les fiches à affichage tardif apparaissent avant la capture de la page. Crawlbase retourne le code de succès amont dans l'en-tête cb_status, vous vérifiez donc celui-là plutôt qu'un champ de statut de premier niveau. Exécutez le script et vous devriez voir du vrai balisage de produit, pas une coquille de page de défi. Cela confirme que le rendu fonctionne avant d'écrire un seul sélecteur.
Best Buy remplit sa grille de recherche avec JavaScript et bloque le trafic qui ne ressemble pas à un navigateur, ce qui est exactement la raison pour laquelle la requête brute ci-dessus revient vide. La Crawling API prend votre token, exécute la page de recherche dans un vrai navigateur avec ajax_wait et page_wait pour que les fiches finissent de se charger, fait tourner les adresses IP résidentielles côté serveur et gère la résolution de CAPTCHA, puis vous transmet le HTML final. Vous n'avez pas besoin d'exécuter vous-même une flotte de navigateurs sans interface graphique ni un pool de proxies. Commencez avec le niveau gratuit de 20 000 requêtes.
Étape 2 : Analyser les fiches produit avec BeautifulSoup
Avec le HTML rendu en main, chargez-le dans BeautifulSoup, trouvez chaque fiche produit et extrayez chaque champ par son sélecteur. Best Buy liste chaque article comme un li.sku-item à l'intérieur du ol.sku-item-list, avec le titre et la note dans le column-middle et le prix et la disponibilité dans le column-right. Enveloppez chaque fiche dans un try/except pour qu'un produit malformé ne fasse pas planter toute l'exécution.
from bs4 import BeautifulSoup BASE = "https://www.bestbuy.com" def text_of(card, selector): el = card.select_one(selector) return el.get_text(strip=True) if el else None def parse_card(card): title_el = card.select_one("div.column-middle h4.sku-title > a") href = title_el["href"] if title_el and title_el.has_attr("href") else None return { "title": title_el.get_text(strip=True) if title_el else None, "price": text_of(card, 'div.column-right div.sku-list-item-price div[data-testid="customer-price"] > span'), "model": text_of(card, "div.column-middle div.sku-model span.sku-value"), "sku": card.get("data-sku-id"), "rating": text_of(card, "div.column-middle div.ratings-reviews div.c-ratings-reviews > p"), "review_count": text_of(card, "div.column-middle div.ratings-reviews span.c-reviews"), "availability": text_of(card, "div.column-right div.fulfillment-add-to-cart-button button"), "product_url": BASE + href if href else None, } def scrape_bestbuy_listing(html): soup = BeautifulSoup(html, "html.parser") cards = soup.select("ol.sku-item-list li.sku-item") results = [] for card in cards: try: results.append(parse_card(card)) except Exception as e: print(f"Skipped a card: {e}") return results
L'assistant text_of interroge un élément dans une fiche et retourne None lorsqu'il est manquant, au lieu de lever une exception sur un appel .get_text() sur rien. Cela rend l'extraction robuste lorsqu'un champ est absent, ce qui est courant car tous les produits n'affichent pas un prix ou une note. Le titre et le lien produit viennent tous deux de l'ancre h4.sku-title > a, le prix du span test-id customer-price, et le SKU de l'attribut data-sku-id de la fiche elle-même. La disponibilité est lue dans le texte du bouton de traitement, qui affiche "Add to Cart" pour un article en stock et "Sold Out" ou "Coming Soon" sinon, le libellé du bouton fait donc aussi office d'indicateur de stock.
Les noms de classes et les valeurs data-testid de Best Buy changent sans préavis. Les marqueurs structurels comme ol.sku-item-list, li.sku-item et le découpage column-middle / column-right ont tendance à être plus durables que les chaînes de classes profondes. Lorsqu'un champ revient à None pour chaque fiche, réinspectez la page de recherche en direct dans les outils de développement de votre navigateur et mettez à jour le sélecteur. Une maintenance périodique des sélecteurs est normale pour tout scraper en production.
Étape 3 : Assembler le script et exporter en JSON et CSV
Connectez maintenant la récupération et l'analyse dans un seul script exécutable, puis écrivez les enregistrements en JSON et CSV pour pouvoir les charger dans un notebook ou un tableur. Récupérez la page de recherche rendue, passez-la au parseur et exportez les lignes structurées.
import csv import json from urllib.parse import quote_plus from crawlbase import CrawlingAPI from bs4 import BeautifulSoup api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) BASE = "https://www.bestbuy.com" FIELDS = ["title", "price", "model", "sku", "rating", "review_count", "availability", "product_url"] def crawl(page_url): options = {"ajax_wait": "true", "page_wait": 5000} response = api.get(page_url, options) if response["headers"]["cb_status"] == "200": return response["body"].decode("utf-8") print(f"Request failed. Crawlbase status: {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_card(card): title_el = card.select_one("div.column-middle h4.sku-title > a") href = title_el["href"] if title_el and title_el.has_attr("href") else None return { "title": title_el.get_text(strip=True) if title_el else None, "price": text_of(card, 'div.column-right div.sku-list-item-price div[data-testid="customer-price"] > span'), "model": text_of(card, "div.column-middle div.sku-model span.sku-value"), "sku": card.get("data-sku-id"), "rating": text_of(card, "div.column-middle div.ratings-reviews div.c-ratings-reviews > p"), "review_count": text_of(card, "div.column-middle div.ratings-reviews span.c-reviews"), "availability": text_of(card, "div.column-right div.fulfillment-add-to-cart-button button"), "product_url": BASE + href if href else None, } def scrape_bestbuy_listing(html): soup = BeautifulSoup(html, "html.parser") cards = soup.select("ol.sku-item-list li.sku-item") results = [] for card in cards: try: results.append(parse_card(card)) except Exception as e: print(f"Skipped a card: {e}") return results def export(rows, name="bestbuy_products"): with open(f"{name}.json", "w", encoding="utf-8") as f: json.dump(rows, f, indent=2, ensure_ascii=False) with open(f"{name}.csv", "w", newline="", encoding="utf-8") as f: writer = csv.DictWriter(f, fieldnames=FIELDS) writer.writeheader() writer.writerows(rows) print(f"Saved {len(rows)} products to {name}.json and {name}.csv") def main(): search_term = "i phone" url = f"{BASE}/site/searchpage.jsp?st={quote_plus(search_term)}" html = crawl(url) if not html: return rows = scrape_bestbuy_listing(html) export(rows) if __name__ == "__main__": main()
Exécutez le script complet avec python bestbuy_scraper.py. Il récupère la page de recherche rendue, analyse une ligne par produit et écrit à la fois bestbuy_products.json et bestbuy_products.csv. La liste partagée FIELDS maintient l'ordre des colonnes CSV en phase avec les clés du dictionnaire, de sorte que les deux exports ne dérivent jamais l'un de l'autre.
À quoi ressemble la sortie
Vous obtenez une liste propre d'enregistrements produits, dans l'ordre de recherche, prête à écrire en JSON, CSV ou dans une base de données.
[ { "title": "Apple - iPhone 14 128GB (Unlocked) - Midnight", "price": "$729.99", "model": "MPUA3LL/A", "sku": "6507555", "rating": "Rating 4.9 out of 5 stars with 155 reviews", "review_count": "(155)", "availability": "Add to Cart", "product_url": "https://www.bestbuy.com/site/apple-iphone-14-128gb-unlocked-midnight/6507555.p?skuId=6507555" }, { "title": "Apple - iPhone SE (3rd Generation) 64GB (Unlocked)", "price": "$429.99", "model": "MMX73LL/A", "sku": "6507470", "rating": "Rating 4.5 out of 5 stars with 111 reviews", "review_count": "(111)", "availability": "Add to Cart", "product_url": "https://www.bestbuy.com/site/apple-iphone-se-3rd-generation-64gb-unlocked/6507470.p?skuId=6507470" } ]
Gérer la pagination sur plusieurs pages de résultats
Une page de recherche est une démo ; un vrai travail de recherche parcourt l'ensemble des résultats. Best Buy répartit les résultats de recherche sur plusieurs pages et suit la page actuelle avec le paramètre d'URL cp : &cp=1 est la première page, &cp=2 la deuxième, et ainsi de suite. Pour collecter un jeu de données complet, parcourez les pages dans l'ordre, arrêtez-vous lorsqu'une page ne retourne aucun produit, et cadencez les requêtes pour ne pas marteler Best Buy dans une boucle serrée.
import time def scrape_all_pages(search_term, max_pages=5): base_url = f"{BASE}/site/searchpage.jsp?st={quote_plus(search_term)}" all_rows = [] for page_number in range(1, max_pages + 1): page_url = f"{base_url}&cp={page_number}" html = crawl(page_url) if not html: break rows = scrape_bestbuy_listing(html) if not rows: print(f"No products on page {page_number}, stopping.") break all_rows.extend(rows) print(f"Page {page_number}: {len(rows)} products") time.sleep(2) return all_rows if __name__ == "__main__": rows = scrape_all_pages("i phone", max_pages=5) export(rows)
L'interruption sur résultats vides s'arrête tôt lorsqu'une recherche manque de pages, et le time.sleep(2) entre les requêtes cadence l'exécution pour ne pas être signalé pour un trafic rapide. Remplacez le terme de recherche par n'importe quelle requête souhaitée, pointez le même parseur sur une page de produit unique plutôt qu'une URL de recherche, et vous pouvez étendre cela en pipeline de suivi des prix. Pour une vue d'ensemble sur la transformation de ce type de flux en outil de surveillance, voir le scraping web pour l'intelligence tarifaire et le guide sur la construction d'un outil de comparaison de prix.
Rester non bloqué
Même avec le rendu géré, Best Buy surveille le trafic à l'allure d'un scraper. Quelques habitudes maintiennent la santé d'une exécution, et elles s'appliquent à toute cible commerciale difficile.
- Cadencez vos requêtes. Espacez les requêtes avec un délai entre les pages plutôt que de tout crawler à pleine vitesse. Planifiez les travaux plus importants pendant les heures creuses pour alléger la charge sur les serveurs de Best Buy.
- Misez sur la rotation. Un pool d'adresses IP résidentielles répartit les requêtes sur de nombreuses adresses d'utilisateurs réels afin qu'aucune ne déclenche une limite de débit. La Crawling API gère cela pour vous ; si vous construisez votre propre stack, c'est la partie à bien faire.
- Conservez uniquement ce dont vous avez besoin. Stockez les champs produits utilisés par votre projet et ignorez le reste. Vérifiez périodiquement vos sélecteurs pour que le scraper suive les changements de balisage.
Pour le guide plus complet, voir comment scraper des sites web sans être bloqué, et pour plus d'informations sur l'importance du rendu ici, comment crawler les sites JavaScript. Si votre projet s'inscrit dans un contexte de vente au détail plus large, l'aperçu du scraping web e-commerce couvre les schémas partagés entre des magasins comme Best Buy et les données produits Amazon.
Est-il légal de scraper Best Buy ?
La question de savoir si le scraping de Best Buy est autorisé dépend des Conditions générales de Best Buy, de votre juridiction et de ce que vous faites des données. Les conditions de Best Buy imposent des limites à l'accès automatisé, de sorte que le scraping peut aller à l'encontre de ces conditions quelle que soit la prudence de vos outils. Aucun code ici ne change cela ; il rend seulement la partie technique fonctionnelle. Lisez les Conditions générales de Best Buy et son robots.txt, et traitez les deux comme la limite de ce que vous collectez. Pour une utilisation commerciale ou concurrentielle, la situation juridique devient plus complexe, et consulter un expert juridique sur votre cas spécifique est la démarche prudente.
Quelques lignes à retenir. Collectez uniquement des données publiques : les titres de produits, les prix, les modèles, les SKUs, les notes et la disponibilité que tout le monde peut voir sur une page de recherche ou de produit Best Buy sans compte. Gardez votre volume de requêtes suffisamment bas pour ne pas surcharger les serveurs de Best Buy, et évitez les données personnelles, y compris tout ce qui est lié à des acheteurs, évaluateurs ou membres du personnel de magasin identifiables au-delà de ce qui est listé publiquement. Si vous prévoyez de réutiliser les données commercialement, obtenez une autorisation ou un accord officiel plutôt que de supposer que le silence vaut consentement.
Ce guide est délibérément limité aux pages de recherche et de produits publiques car c'est la ligne qui rend le travail défendable. Il ne couvre rien derrière une connexion, les données de compte ou de commande, les informations personnelles, ou toute tentative de contourner l'authentification ou un CAPTCHA que vous n'êtes pas autorisé à passer. Best Buy gère un programme d'affiliation et de partenariat avec des flux de produits officiels pour une utilisation sous licence, et c'est la bonne voie lorsque vous avez besoin de grands volumes, d'une structure garantie ou de droits commerciaux. Si votre projet a besoin de plus que des données de catalogue publiques, un flux officiel ou un accord de données est la bonne route, pas un scraper plus sophistiqué.
Points clés
- Best Buy est un catalogue public d'électronique. Ses pages de recherche et de produits exposent le titre, le prix, le modèle, le SKU, la note et la disponibilité, ce qui les rend utiles pour le suivi des prix et la recherche de marché.
-
Vous avez besoin du rendu et d'une adresse IP fiable ensemble. Best Buy remplit sa grille de recherche côté client et bloque le trafic de robots, la Crawling API affiche donc la page derrière une adresse IP résidentielle en un seul appel avec
ajax_waitetpage_wait. -
BeautifulSoup fait l'extraction. Parcourez en boucle les fiches
ol.sku-item-list li.sku-itemet mappez chaque champ sur son sélecteur, en prévoyant que ces sélecteurs dérivent au fur et à mesure que le balisage de Best Buy change. -
Paginez avec le paramètre
cp. Parcourez les pages avec&cp=N, arrêtez-vous sur une page vide et cadencez les requêtes avec un délai court entre les pages. - Restez sur les données publiques. Respectez les Conditions générales et le robots.txt de Best Buy, préférez un flux officiel pour les données sous licence ou en masse, et ne touchez jamais aux comptes, commandes ou informations personnelles.
Foire aux questions
Pourquoi une requête ordinaire ne retourne-t-elle aucun produit de Best Buy ?
Best Buy affiche sa grille de recherche côté client, donc un requests.get() brut récupère une coquille sans fiches produit, ce qui explique pourquoi un parseur ordinaire retourne une liste vide. En plus de cela, Best Buy met au défi ou bloque le trafic qui ne ressemble pas à un vrai navigateur. Afficher la page via la Crawling API depuis une adresse IP fiable résout les deux, c'est pourquoi le scraper ici route sa requête via celle-ci avec les options ajax_wait et page_wait définies.
Quels champs puis-je extraire d'un produit Best Buy ?
De chaque fiche de résultat de recherche, vous pouvez lire le titre du produit, le prix client actuel, le numéro de modèle du fabricant, le SKU de Best Buy, la note en étoiles et le nombre d'avis, un état de disponibilité du bouton de traitement, et le lien vers la page de détail du produit. Le scraper dans ce guide rassemble tous ces éléments en un enregistrement par produit, puis les écrit en JSON et CSV.
Comment gérer la pagination sur Best Buy ?
Best Buy suit la page de recherche actuelle avec le paramètre d'URL cp, donc &cp=2 demande la deuxième page et ainsi de suite. Parcourez les numéros de pages en boucle, ajoutez &cp=N à l'URL de recherche à chaque fois, et arrêtez-vous lorsqu'une page ne retourne aucun produit. Ajoutez un délai court entre les requêtes pour cadencer l'exécution plutôt que d'envoyer les pages en rafale.
Comment la Crawling API gère-t-elle le contenu JavaScript de Best Buy ?
La Crawling API affiche la page dans un vrai navigateur avant de la retourner, et les options ajax_wait et page_wait contrôlent combien de temps elle attend le contenu asynchrone. Définir ajax_wait sur true attend que la grille de produits asynchrone se termine, et page_wait attend un nombre fixe de millisecondes après le chargement pour que les fiches à affichage tardif apparaissent dans le HTML retourné.
Comment éviter d'être bloqué lors du scraping de Best Buy ?
Gardez votre taux de requêtes par adresse IP bas, ajoutez un délai entre les pages et routez via des adresses IP résidentielles rotatives afin qu'aucune adresse unique ne déclenche une limite de débit. La Crawling API gère la rotation, un pool d'adresses IP fiables et la gestion des CAPTCHA pour vous ; si vous construisez votre propre stack, c'est la partie sur laquelle investir. Surveillez les valeurs cb_status et ralentissez lorsque vous commencez à voir des défis.
Puis-je suivre les changements de prix de Best Buy dans le temps ?
Oui. Exécutez le scraper selon un calendrier, horodatez chaque export et stockez les instantanés. La comparaison d'exécutions successives montre quels produits ont changé de prix ou sont entrés ou sortis du stock, ce qui est la base de la surveillance des prix et de l'analyse concurrentielle. Le même parseur fonctionne sur une seule page de produit, vous pouvez donc réduire un tracker aux SKUs exacts qui vous intéressent.
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.
