Crawler une page web consiste à écrire un logiciel qui parcourt un ensemble d'URLs, récupère chacune d'elles et extrait des champs structurés du HTML. C'est ainsi que vous transformez des pages conçues pour les yeux humains en données interrogeables : flux de prix pour la surveillance, archives d'articles pour la recherche, grilles d'annonces pour l'analyse de marché, ou un corpus d'entraînement pour un modèle. La plupart de ces données sont publiques et visibles, mais les lire en volume manuellement est impensable, donc vous avez recours à un crawler.
Ce guide vous montre comment crawler une page web avec Scrapy, le framework de crawling Python mature, tout en acheminant chaque requête via la Crawling API pour que la page revienne rendue et que la requête emprunte une IP de rotation approuvée plutôt que votre adresse datacenter. Vous construirez un petit spider Scrapy exécutable qui récupère une page de résultats de recherche, analyse un champ de chaque annonce et affiche des enregistrements propres. Le guide reste limité aux données d'annonces publiques, et une courte note sur le crawling responsable vers la fin mérite d'être lue avant de pointer ceci sur un vrai volume.
Ce que vous allez construire
Un spider Scrapy en un seul fichier qui récupère une page de résultats de recherche via la Crawling API et produit un enregistrement structuré par résultat. Nous utilisons une recherche Amazon comme exemple de référence, le même que celui utilisé dans la version originale de ce tutoriel, et extrayons deux champs de chaque fiche produit :
- Title le texte du titre du produit affiché sur la fiche de résultat.
- URL le lien depuis la fiche vers la page de détail de ce produit.
Deux champs maintiennent l'exemple lisible, et le schéma s'étend à tout sélecteur que vous souhaitez ajouter. La même structure de spider fonctionne pour tout site que vous avez le droit de crawler : remplacez l'URL de départ et les sélecteurs, et la boucle fetch-and-parse reste identique.
Pourquoi une requête directe est bloquée
Pointez une requête Scrapy brute vers un site commercial chargé et deux problèmes surviennent généralement. Premièrement, de nombreuses pages rendent leur contenu dans le navigateur : le HTML initial est une coquille légère, et les annonces n'apparaissent qu'après l'exécution du JavaScript de la page. Une récupération brute renvoie la coquille, donc il n'y a rien à analyser. Deuxièmement, les grands sites surveillent le trafic automatisé. Une IP datacenter effectuant des requêtes rapides et répétitives qui ne ressemblent pas à un vrai navigateur est challengée par un CAPTCHA ou bloquée, souvent avant de voir un seul produit.
Un crawler qui fonctionne réellement nécessite donc deux choses dans la même requête : un navigateur qui rend la page, et une IP que le site lit comme un vrai visiteur. Vous pouvez le construire vous-même avec un navigateur headless plus un pool de proxies résidentiels en rotation, mais assembler ces pièces et les maintenir en état représente l'essentiel du travail. La Crawling API intègre les deux dans un seul appel. Vous lui transmettez une URL, elle récupère la page derrière une IP résidentielle de confiance (et la rend dans un vrai navigateur quand vous le demandez), et elle renvoie le HTML terminé pour que Scrapy l'analyse. Votre spider parle à un seul point d'accès et ne touche jamais à une liste de proxies.
Au lieu de demander directement le site cible, votre spider demande https://api.crawlbase.com/?token=YOUR_CRAWLBASE_TOKEN&url=.... L'API récupère la cible pour vous via son pool d'IP et diffuse le corps de la réponse à Scrapy. Du point de vue de Scrapy, c'est simplement une réponse HTTP ordinaire, donc chaque sélecteur et pipeline que vous connaissez déjà fonctionne toujours.
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 le crawling en général, le guide plus large sur comment scraper un site web avec Python couvre les fondamentaux que ce tutoriel suppose.
Python 3.8 ou supérieur. Confirmez votre version avec python --version. Si vous ne l'avez pas, installez-le depuis python.org ou via une distribution comme Anaconda.
Un compte et un token Crawlbase. Inscrivez-vous, ouvrez votre tableau de bord et copiez votre token. Crawlbase vous en donne deux : un token normal pour le HTML statique et un token JavaScript pour les pages nécessitant un rendu. Nous utilisons le placeholder YOUR_CRAWLBASE_TOKEN tout au long. Traitez-le 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 isolé pour que les dépendances du projet n'entrent pas en conflit avec autre chose, puis installez les deux bibliothèques dont le spider a besoin.
python --version python -m venv crawler_env source crawler_env/bin/activate pip install scrapy crawlbase
Sur Windows, activez l'environnement avec crawler_env\Scripts\activate à la place de la ligne source. Deux dépendances font le travail. scrapy est le framework de crawling : il gère la file d'attente des requêtes, le téléchargeur et la boucle d'analyse. crawlbase est le client Python officiel de la Crawling API, et sa classe CrawlingAPI dispose d'un helper buildURL qui encapsule toute URL cible dans une requête API correcte, avec token et tout, pour que vous n'ayez pas à assembler cette chaîne de requête manuellement.
Scrapy exécute un seul spider directement depuis un fichier avec scrapy runspider, donc vous n'avez pas besoin d'un projet complet pour ce tutoriel. Créez un seul fichier pour contenir le spider :
touch myspider.py
Étape 1 : Récupérer une page via la Crawling API
Commencez avec un spider qui ne fait que prouver que le routage fonctionne. Sous-classez scrapy.Spider, donnez-lui un name et définissez start_urls. La seule astuce ici est que l'URL de départ n'est pas la cible directement : vous l'encapsulez avec api.buildURL pour que Scrapy demande le point d'accès de la Crawling API, et l'API récupère la cible pour vous.
import scrapy from crawlbase import CrawlingAPI # Replace YOUR_CRAWLBASE_TOKEN with the token from your dashboard api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) class AmazonSpider(scrapy.Spider): name = "amazonspider" # Target page to crawl, then route it through the Crawling API targets = ["https://www.amazon.com/s?k=cold+brew+coffee+maker"] start_urls = [api.buildURL(url, {}) for url in targets]
Le spider n'a pas encore de méthode parse, donc il récupérera la page et s'arrêtera. C'est intentionnel : vous voulez confirmer que la requête atteint la cible via l'API et revient avec un statut 200 avant d'écrire un seul sélecteur. Exécutez-le depuis le répertoire du projet :
scrapy runspider myspider.py
Dans le log, vous devriez voir une ligne Crawled (200) pour un GET contre api.crawlbase.com, avec votre URL cible dans le paramètre de requête url. Ce 200 est tout l'objet de cette étape : la requête est passée par la Crawling API, l'API a récupéré la page de recherche Amazon derrière une IP de confiance, et le HTML rendu est revenu à Scrapy. Comme il n'y a pas encore de parser, Scrapy enregistre que le callback parse par défaut n'est pas défini et ferme le spider. La plomberie fonctionne ; vous pouvez maintenant extraire des données.
Ce Crawled (200) sur une cible commerciale difficile est la partie sur laquelle la plupart des crawlers échouent. La Crawling API a pris l'URL que vous avez passée à buildURL, a récupéré la page derrière une IP résidentielle en rotation, l'a rendue dans un vrai navigateur quand nécessaire, et a donné à Scrapy le HTML terminé, pour que vous évitez de gérer vous-même une flotte de navigateurs headless et un pool de proxies. Pointez-la sur votre propre cible avec le niveau gratuit d'abord.
Étape 2 : Analyser les champs avec les sélecteurs CSS et XPath
Ajoutez maintenant une méthode parse. Scrapy l'appelle automatiquement avec la response pour chaque page récupérée, et la réponse expose les sélecteurs CSS et XPath sur le HTML. Pour chaque fiche produit sur la page de recherche, vous extrayez le titre et le lien et yield un petit dictionnaire. Scrapy collecte tout ce que vous produisez comme éléments scrappés.
def parse(self, response): for card in response.css("div[data-component-type='s-search-result']"): title = card.css("h2 a span::text").get() href = card.css("h2 a::attr(href)").get() if not title or not href: continue yield { "title": title.strip(), "url": response.urljoin(href), }
Quelques points méritent d'être soulignés. Le sélecteur de fiche cible un attribut data-component-type stable plutôt qu'une classe utilitaire fragile, ce qui est le type d'ancrage durable que vous devriez préférer sur tout site. response.css(...).get() renvoie la première correspondance sous forme de texte ou None quand rien ne correspond, donc le garde if not title or not href ignore les emplacements sponsorisés et les lignes de mise en page qui ne contiennent pas les deux champs. response.urljoin(href) transforme le lien relatif que la fiche vous donne en URL absolue. Si vous préférez XPath, les deux mêmes champs se lisent comme card.xpath(".//h2//a//span/text()").get() et card.xpath(".//h2/a/@href").get(). CSS et XPath sont interchangeables ici ; choisissez celui qui est le plus lisible pour un champ donné. La comparaison approfondie des deux se trouve dans le guide sur le web scraping avec XPath et les sélecteurs CSS.
Le balisage des sites change sans préavis, et les sélecteurs ci-dessus sont un modèle de départ, pas un contrat. Si title ou url revient None pour chaque fiche, ouvrez la page en direct dans les outils de développement de votre navigateur, réinspectez une fiche produit et mettez à jour le sélecteur. La maintenance périodique des sélecteurs est normale pour tout crawler en production, ce n'est pas le signe que quelque chose est cassé.
Étape 3 : Assembler et exécuter le spider complet
Assemblez les pièces dans un seul fichier. Voici le spider complet et exécutable : l'import, le client API, les URLs de départ acheminées via buildURL et la méthode parse.
import scrapy from crawlbase import CrawlingAPI # Replace YOUR_CRAWLBASE_TOKEN with the token from your dashboard api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) class AmazonSpider(scrapy.Spider): name = "amazonspider" targets = ["https://www.amazon.com/s?k=cold+brew+coffee+maker"] start_urls = [api.buildURL(url, {}) for url in targets] def parse(self, response): for card in response.css("div[data-component-type='s-search-result']"): title = card.css("h2 a span::text").get() href = card.css("h2 a::attr(href)").get() if not title or not href: continue yield { "title": title.strip(), "url": response.urljoin(href), }
Exécutez-le et écrivez les éléments directement dans un fichier avec l'export de flux intégré de Scrapy, qui sérialise tout ce que le spider produit :
scrapy runspider myspider.py -o products.json
L'option -o products.json indique à Scrapy de déposer chaque élément produit dans un fichier JSON. Omettez l'option et les éléments s'affichent dans votre console. Dans tous les cas, chaque ligne Scraped from dans le log correspond à un produit, et le rapport de statistiques final indique combien d'éléments l'exécution a collectés.
À quoi ressemble la sortie
Chaque élément est un petit enregistrement avec les deux champs que vous avez produits. Le fichier JSON est une liste de ces enregistrements, prête à charger dans une base de données, un notebook ou un pipeline en aval.
[ { "title": "Airtight Cold Brew Iced Coffee Maker and Tea Infuser with Spout, 1.0L", "url": "https://www.amazon.com/Airtight-Coffee-Maker-Infuser-Spout/dp/B01CTIYU60" }, { "title": "KitchenAid Cold Brew Coffee Maker, Brushed Stainless Steel", "url": "https://www.amazon.com/KitchenAid-KCM4212SX-Coffee-Brushed-Stainless/dp/B06XNVZDC7" } ]
Crawler plus d'une page
Une page de recherche est une démonstration. Un vrai crawl suit les liens que vous venez de collecter, ou parcourt les pages suivantes de résultats, et Scrapy est conçu exactement pour cela. Au lieu de produire un dictionnaire simple, produisez une scrapy.Request pour chaque URL que vous souhaitez suivre, acheminée via buildURL pour qu'elle repasse par la Crawling API, et pointez-la vers un callback qui analyse la page suivante.
def parse(self, response): for card in response.css("div[data-component-type='s-search-result']"): href = card.css("h2 a::attr(href)").get() if href: product_url = response.urljoin(href) yield scrapy.Request( api.buildURL(product_url, {}), callback=self.parse_product, ) def parse_product(self, response): yield { "title": response.css("#productTitle::text").get(default="").strip(), "url": response.url, }
Scrapy met en file d'attente chaque requête que vous produisez, les récupère via son téléchargeur et appelle le callback correspondant pour chaque réponse, donc un crawl à deux niveaux (page de recherche, puis chaque page produit) n'est que deux méthodes parse. Comme chaque requête de suivi est encapsulée avec buildURL, elle passe aussi par la Crawling API, ce qui maintient la rotation IP et le rendu cohérents sur l'ensemble du crawl. Limitez les crawls avec les paramètres Scrapy comme CLOSESPIDER_ITEMCOUNT pendant les tests, et ajoutez un délai poli avec DOWNLOAD_DELAY pour ne pas surcharger la cible. Pour les sites qui affichent leurs annonces avec JavaScript, le même routage les gère une fois que vous demandez le rendu ; le guide sur comment crawler les sites JavaScript explique quand vous en avez besoin.
Rester non bloqué
Le routage via la Crawling API gère les deux parties les plus difficiles, le rendu et une IP de confiance, mais quelques habitudes maintiennent en bonne santé tout crawl plus long.
-
Cadencez vos requêtes. Définissez un
DOWNLOAD_DELAYet laissez l'AutoThrottle de Scrapy adapter le rythme plutôt que d'envoyer des requêtes aussi vite que le framework le peut. La vitesse est ce qui fait remarquer un crawler. - 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 ne déclenche de limite de débit. La Crawling API le fait pour vous ; si vous construisez jamais votre propre pile, c'est la partie à bien faire.
- Lisez les codes de statut. Un crawl qui commence à renvoyer des réponses non-200 vous indique que le débit ou le palier d'IP actuel n'est plus suffisant. Traitez cela comme un signal pour ralentir, pas comme du bruit à ignorer.
Les mêmes schémas s'appliquent bien au-delà de Python. Si vous souhaitez comparer l'approche dans un autre langage, le guide sur comment construire un crawler web en Java suit la même forme fetch-via-API-puis-parse avec une chaîne d'outils différente.
Crawler de manière responsable
Tenez-vous aux données publiques, les titres d'annonces et les liens que tout le monde peut voir sans se connecter, et restez à l'écart de tout ce qui est derrière une authentification, des informations personnelles ou des médias protégés par le droit d'auteur que vous avez l'intention de redistribuer. Respectez le robots.txt et les conditions d'utilisation de chaque site, qui fixent la limite de ce que vous pouvez collecter et comment, et gardez votre taux de requêtes raisonnable pour ne pas surcharger les serveurs de quelqu'un d'autre. Quand un site propose une API officielle pour les données dont vous avez besoin, préférez-la : c'est le chemin approuvé et généralement le plus stable. Aucun des outils ici ne change ces obligations ; il rend seulement la partie technique fonctionnelle.
Points clés
-
Scrapy vous donne le framework de crawling. Une sous-classe de spider avec
start_urlset une méthodeparseest le coeur entier, etscrapy runspiderl'exécute depuis un seul fichier. -
Acheminez chaque requête via la Crawling API. Encapsulez chaque URL cible avec
api.buildURLpour que la requête emprunte une IP de rotation approuvée et revienne rendue, au lieu de frapper le site depuis votre adresse datacenter. -
Confirmez un 200 avant d'analyser. Exécutez le spider sans parser d'abord ; un
Crawled (200)contre le point d'accès API prouve que le routage fonctionne avant de toucher aux sélecteurs. - Extrayez avec CSS ou XPath. La réponse expose les deux ; associez chaque champ à un sélecteur durable, gardez-vous contre les correspondances manquantes et attendez-vous à ce que les sélecteurs dérivent dans le temps.
-
Crawlez de manière responsable. Restez sur les données publiques, respectez
robots.txtet les conditions d'utilisation, cadencez vos requêtes et préférez une API officielle quand elle existe.
Foire aux questions
Pourquoi acheminer Scrapy via la Crawling API plutôt que de récupérer directement ?
Parce qu'une requête Scrapy directe frappe la cible depuis votre propre IP et obtient le HTML brut, souvent non rendu. Sur les sites commerciaux chargés, cela signifie des CAPTCHA, des blocages ou une coquille JavaScript vide. Acheminer via la Crawling API récupère la page derrière une IP résidentielle en rotation et la rend quand nécessaire, de sorte que le HTML qui arrive à Scrapy est la page terminée que vous pouvez réellement analyser.
Que fait api.buildURL ?
Il prend une URL cible et retourne l'URL complète de requête de la Crawling API pour celle-ci, avec votre token et la cible attachés comme paramètres de requête. Vous pointez Scrapy sur l'URL que buildURL retourne, et l'API récupère la cible pour vous. Cela vous évite d'assembler https://api.crawlbase.com/?token=...&url=... manuellement et de vous tromper dans l'échappement.
Ai-je besoin du token normal ou du token JavaScript ?
Cela dépend de la cible. Si la page sert son contenu dans le HTML initial, le token normal suffit. Si les annonces n'apparaissent qu'après l'exécution du JavaScript de la page, vous avez besoin du token JavaScript pour que l'API rende la page dans un vrai navigateur avant de la retourner. Quand des champs que vous pouvez voir dans votre navigateur reviennent vides dans Scrapy, c'est généralement le signe que vous devriez passer au token JavaScript.
Puis-je utiliser les sélecteurs CSS et XPath dans le même spider ?
Oui. Chaque réponse Scrapy expose à la fois response.css(...) et response.xpath(...), et vous pouvez les mélanger librement, même champ par champ. CSS est généralement plus court pour les correspondances de classe et d'attribut, tandis que XPath est plus pratique pour remonter dans l'arbre ou correspondre sur le texte. Utilisez celui qui se lit le plus clairement pour le champ devant vous.
Comment crawler plusieurs pages ou suivre des liens ?
Produisez une scrapy.Request pour chaque URL que vous souhaitez suivre au lieu d'un élément simple, encapsulez cette URL avec api.buildURL pour qu'elle repasse par la Crawling API, et donnez-lui un callback qui analyse la page suivante. Scrapy met en file d'attente et récupère chaque requête que vous produisez, donc un crawl page-de-recherche-puis-page-produit n'est que deux méthodes parse. Limitez l'exécution avec des paramètres comme CLOSESPIDER_ITEMCOUNT pendant les tests.
Mes sélecteurs retournent None. Que s'est-il passé ?
C'est presque certainement le balisage du site. Les noms de classes et les attributs de conteneurs changent sans préavis, ce qui casse tout sélecteur qui leur est lié. Ouvrez une page en direct dans les outils de développement de votre navigateur, réinspectez l'élément, préférez des ancres durables comme des attributs data- stables quand vous le pouvez, et mettez à jour le sélecteur. La maintenance périodique des sélecteurs est normale pour tout crawler en production.
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.

