Agoda référence des millions d'hôtels et de propriétés de courte durée en Asie et dans le reste du monde, et chaque résultat de recherche porte exactement les données structurées qui alimentent le suivi des prix, la recherche de voyages et l'analyse concurrentielle : le nom de l'hôtel, le prix par nuit, le score d'avis des clients, la localisation et un lien vers la fiche complète. Pour quiconque surveille un marché ou construit un outil de comparaison de voyages, ces données de listing publiques sont la matière première, et les collecter à la main sur une page de résultats est lent et rapidement obsolète.
Ce guide vous montre comment scraper des données hôtelières depuis Agoda avec Python de manière fiable. Vous construisez un petit scraper exécutable qui récupère une page de recherche Agoda rendue via la Crawling API, gère le chargement par défilement d'Agoda pour que l'ensemble complet de résultats apparaisse, analyse les champs souhaités avec BeautifulSoup, et stocke des enregistrements propres en JSON. L'ensemble du tutoriel se limite aux données de listing publiques, et la section sur la légalité vers la fin n'est pas un texte générique, lisez-la avant de viser un volume réel.
Ce que vous allez construire
Un script Python qui prend une URL de recherche Agoda publique pour une ville, récupère la page de résultats rendue via la Crawling API, la fait défiler pour que chaque carte de propriété se charge, et extrait un enregistrement structuré par hôtel. L'exemple fil conducteur est les hôtels à Kuala Lumpur. Nous extrayons ces champs :
- Nom de l'hôtel le nom de la propriété tel qu'affiché sur la carte.
- Prix le prix par nuit affiché pour les dates sélectionnées.
- Note le score d'avis des clients qui signale la qualité et la popularité.
- Localisation la ville ou zone pour laquelle la recherche a été effectuée.
- Lien l'URL complète de la page de listing de l'hôtel.
Pourquoi une requête simple échoue sur Agoda
Si vous demandez une URL de recherche Agoda avec un client HTTP brut, vous obtenez une réponse avec le statut 200 et presque aucun listing dans le corps. Deux obstacles se dressent contre vous. Premièrement, Agoda construit ses résultats de recherche dans le navigateur via JavaScript, et ne charge les cartes de propriétés supplémentaires qu'au fur et à mesure que vous faites défiler, donc le HTML initial est une fine coquille qui se remplit après l'exécution des scripts de la page et le défilement de l'utilisateur. Analyser cette première réponse vous donne quelques cartes au lieu de la page complète. Deuxièmement, Agoda détecte rapidement le trafic automatisé : les IP de datacenter et les patterns de requête qui ne ressemblent pas à un vrai navigateur sont soumis à des limites de débit, des blocages IP ou des défis avant d'atteindre le contenu rendu.
Un scraper Agoda fonctionnel a donc besoin de trois choses en une seule requête : un navigateur qui rend la page, un moyen de déclencher le défilement pour que les cartes chargées en lazy apparaissent, et une IP que la plateforme lit comme un vrai visiteur. Vous pouvez assembler cela vous-même avec un navigateur sans interface graphique, une routine de défilement et un pool de proxies résidentiels rotatifs, mais maintenir cette pile en bonne santé représente l'essentiel du travail. La Crawling API combine tout cela en un seul appel : vous envoyez l'URL avec un token JavaScript et des options de défilement, elle rend et fait défiler la page derrière une IP de confiance, et renvoie le HTML final à analyser.
Crawlbase propose deux types de token. Le token normal récupère le HTML statique ; le token JavaScript (JS) rend d'abord la page dans un vrai navigateur. Agoda remplit ses résultats de recherche côté client et les charge au défilement, vous avez donc besoin du token JS ici. Le token normal renvoie la même fine coquille qu'une récupération simple, et il y a peu d'utile à en analyser.
Prérequis
Vous avez besoin de quelques éléments 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 paquets avec pip. Si vous découvrez le côté analyse, le guide BeautifulSoup est un bon complément à ce tutoriel.
Python 3.8 ou version ultérieure. Confirmez 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. Inscrivez-vous, ouvrez votre tableau de bord et copiez votre token JavaScript (JS) depuis la page docs du compte. Crawlbase inclut jusqu'à 20 000 requêtes gratuites pour commencer, ce qui est largement suffisant pour travailler sur ce guide. Traitez le token comme un mot de passe : il authentifie vos requêtes, gardez-le hors du contrôle de version.
Configurer le projet
Créez un environnement virtuel pour garder les dépendances du projet isolées, puis installez les bibliothèques dont le scraper a besoin.
python --version python -m venv agoda_env source agoda_env/bin/activate pip install crawlbase beautifulsoup4
Sous Windows, activez l'environnement avec agoda_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 renvoyé pour que vous puissiez extraire des champs individuels par sélecteur CSS. Le module json est fourni avec 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 Agoda rendue
Commencez par obtenir une page finale. Importez la classe CrawlingAPI, initialisez-la avec votre token JS, et demandez une URL de recherche Agoda. Agoda charge les cartes au défilement, donc passez les options scroll et scroll_interval pour que l'API fasse défiler la page avant qu'elle soit capturée. Vérifier le cb_status (legacy pc_status) Crawlbase avant d'analyser rend les échecs visibles plutôt que silencieux.
from crawlbase import CrawlingAPI api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) OPTIONS = { "scroll": "true", "scroll_interval": "20", } def fetch_agoda_page(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__": search_url = "https://www.agoda.com/search?city=14524&adults=2&rooms=1" html = fetch_agoda_page(search_url) print(html[:500] if html else "No HTML returned")
Les deux options de défilement sont importantes pour une cible à chargement paresseux comme Agoda. scroll indique à l'API de faire défiler la page plutôt que de la capturer immédiatement, et scroll_interval définit combien de secondes continuer à défiler pour que les cartes à rendu tardif apparaissent avant la capture. Vingt secondes est le maximum documenté et un point de départ raisonnable pour une page de résultats chargée. Lancez le script avec python agoda_scraper.py et vous devriez voir de vrais balisages de recherche Agoda, pas la coquille qu'une requête simple renvoie. Cela confirme que le rendu et le défilement fonctionnent avant d'écrire un seul sélecteur.
Agoda nécessite une page rendue qui a été défilée, derrière une IP de confiance, en un seul appel, ce que les options scroll et scroll_interval ci-dessus configurent exactement. La Crawling API prend un token JS, exécute la page dans un vrai navigateur, la fait défiler pour déclencher les cartes chargées en lazy, fait tourner les IP résidentielles côté serveur, et vous remet le HTML final, vous évitant de gérer vous-même une flotte sans interface graphique et un pool de proxies. Pointez-la vers une page de recherche publique sur le niveau gratuit d'abord.
Étape 2 : Inspecter la page et analyser les cartes hôtelières
Avant d'écrire des sélecteurs, ouvrez la page de recherche Agoda dans votre navigateur, faites un clic droit sur une carte hôtelière et choisissez Inspecter pour lire sa structure HTML. Sur la page de résultats de Kuala Lumpur, chaque listing se trouve dans une carte de propriété avec quelques hooks stables que vous pouvez cibler :
-
Nom de l'hôtel se trouve dans un
<h3>avecdata-selenium="hotel-name". -
Prix est dans un
<div>avecdata-element-name="final-price". -
Note est dans un
<p>avecdata-element-name="review-score". -
Lien du listing est le
hrefde l'ancrea.PropertyCard__Link.
Chargez le HTML rendu dans BeautifulSoup, bouclez sur chaque carte de propriété, et extrayez ces quatre champs. Chaque recherche est gardée pour qu'une carte manquant un champ renvoie une chaîne vide au lieu de faire planter la boucle, et le lien relatif est joint au domaine d'Agoda pour former une URL complète.
from bs4 import BeautifulSoup CARD_SELECTOR = "div#contentContainer ol.hotel-list-container > li.PropertyCard" def text_of(card, selector): el = card.select_one(selector) return el.get_text(strip=True) if el else "" def extract_agoda_data(html, location): soup = BeautifulSoup(html, "html.parser") hotels = [] for card in soup.select(CARD_SELECTOR): link_el = card.select_one("a.PropertyCard__Link") href = link_el["href"] if link_el and link_el.get("href") else "" hotels.append({ "name": text_of(card, 'h3[data-selenium="hotel-name"]'), "price": text_of(card, 'div[data-element-name="final-price"]'), "rating": text_of(card, 'p[data-element-name="review-score"]'), "location": location, "link": f"https://www.agoda.com{href}" if href else "", }) return hotels
L'assistant text_of interroge un élément dans une carte et renvoie son texte nettoyé, ou une chaîne vide quand l'élément est absent, pour qu'un listing omettant un champ ne casse pas la boucle. Le sélecteur de carte descend depuis le conteneur de contenu de la page jusqu'à chaque li.PropertyCard, et les quatre sélecteurs de champs viennent directement du balisage d'Agoda. Lancez cela contre le HTML défilé de l'étape 1 et vous obtenez un enregistrement par hôtel sur la page.
Les hooks data-selenium et data-element-name d'Agoda et ses noms de classes générés changent sans préavis. Traitez les sélecteurs ici comme un modèle de départ, pas un contrat. Quand une liste revient vide, 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, pas le signe que quelque chose est cassé.
Étape 3 : Assembler le script complet
Maintenant câblez les pièces dans un script exécutable unique : récupérez la page de recherche défilée, analysez chaque carte hôtelière, et exportez les enregistrements dans un fichier JSON.
import json from crawlbase import CrawlingAPI from bs4 import BeautifulSoup api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) OPTIONS = { "scroll": "true", "scroll_interval": "20", } CARD_SELECTOR = "div#contentContainer ol.hotel-list-container > li.PropertyCard" def fetch_agoda_page(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 text_of(card, selector): el = card.select_one(selector) return el.get_text(strip=True) if el else "" def extract_agoda_data(html, location): soup = BeautifulSoup(html, "html.parser") hotels = [] for card in soup.select(CARD_SELECTOR): link_el = card.select_one("a.PropertyCard__Link") href = link_el["href"] if link_el and link_el.get("href") else "" hotels.append({ "name": text_of(card, 'h3[data-selenium="hotel-name"]'), "price": text_of(card, 'div[data-element-name="final-price"]'), "rating": text_of(card, 'p[data-element-name="review-score"]'), "location": location, "link": f"https://www.agoda.com{href}" if href else "", }) return hotels def save_to_json(data, filename="agoda_hotels.json"): with open(filename, "w") as f: json.dump(data, f, indent=2) print(f"Saved {len(data)} hotels to {filename}") def main(): location = "Kuala Lumpur" search_url = "https://www.agoda.com/search?city=14524&adults=2&rooms=1" html = fetch_agoda_page(search_url) if html: hotels = extract_agoda_data(html, location) save_to_json(hotels) if __name__ == "__main__": main()
Le script récupère la page de recherche défilée, analyse chaque carte de propriété dans un enregistrement, et écrit la liste dans agoda_hotels.json avec une indentation de deux espaces. Le paramètre city=14524 est l'identifiant interne d'Agoda pour Kuala Lumpur ; échangez-le contre un autre identifiant de ville, et ajoutez vos propres paramètres d'arrivée, de départ et d'occupation, pour pointer le scraper vers un marché différent. Comme le libellé de localisation est passé en paramètre plutôt qu'analysé, chaque enregistrement porte la ville que vous avez recherchée.
À quoi ressemble la sortie
Lancez le script complet avec python agoda_scraper.py et vous obtenez un enregistrement structuré propre par hôtel, prêt pour l'analyse, une base de données ou un tableur. Les valeurs de prix et de note sont telles qu'Agoda les formate sur la carte.
[ { "name": "Summer Suites KLCC By Castle Classy", "price": "USD34", "rating": "8.4", "location": "Kuala Lumpur", "link": "https://www.agoda.com/summer-suites-klcc-by-castle-classy/hotel/kuala-lumpur-my.html" }, { "name": "Riveria City Kuala Lumpur by Guestonic", "price": "USD20", "rating": "9.2", "location": "Kuala Lumpur", "link": "https://www.agoda.com/riveria-city-kuala-lumpur-by-guestonic/hotel/kuala-lumpur-my.html" } ]
Si vous voulez les mêmes données dans un tableur, remplacez save_to_json par le csv.DictWriter de Python en utilisant les clés du premier enregistrement comme en-tête. La forme de l'enregistrement reste la même, elle s'intègre donc directement dans pandas pour filtrer par tranche de prix ou trier par score d'avis.
Passer à l'échelle sur plusieurs villes et rester non bloqué
La page de recherche unique ci-dessus est le bloc de construction. Pour couvrir davantage d'un marché, bouclez sur une liste d'identifiants de villes Agoda et appelez fetch_agoda_page pour chacun, en étiquetant chaque lot avec sa localisation. Agoda utilisant le chargement par défilement plutôt que les pages numérotées, scroll_interval contrôle quelle part d'un ensemble de résultats vous capturez ; augmentez-le vers le maximum sur les pages de villes denses où les cartes continuent de se charger.
Même avec le rendu et le défilement gérés, Agoda surveille le trafic à l'allure d'un scraper. Quelques habitudes maintiennent une exécution plus longue en bonne santé, et elles s'appliquent à toute cible commerciale difficile.
- Espacez vos requêtes. Récupérer de nombreuses pages de ville dans une boucle serrée est le moyen le plus rapide d'être ralenti ou mis au défi. Ajoutez un court délai entre les requêtes et variez vos cibles au lieu de crawler un chemin à plein régime.
- 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 débit. La Crawling API s'en charge pour vous ; si vous gérez votre propre infrastructure, c'est la partie à bien configurer.
-
Lisez les codes de statut. Une exécution qui commence à renvoyer des valeurs
cb_statusnon-200 vous indique que le débit ou le niveau d'IP actuel n'est plus suffisant. Traitez cela comme un signal à ralentir, pas du bruit à ignorer.
Pour les crawls plus importants, le Crawler async 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 ville sans maintenir des connexions ouvertes. Pour le guide complet, consultez comment scraper des sites web sans être bloqué et le guide sur le crawling de sites web JavaScript. Si vous voulez comparer les données hôtelières entre portails, la même approche s'applique au scraping d'Expedia, de Tripadvisor et de Google Hotels.
Est-il légal de scraper Agoda ?
La question de savoir si le scraping d'Agoda est autorisé dépend des conditions d'utilisation d'Agoda, de votre juridiction et de ce que vous faites des données. Les conditions d'Agoda restreignent l'accès automatisé et la collecte de données en masse, donc le scraping peut aller à l'encontre de ces conditions quelle que soit la prudence de votre outillage. Rien dans ce code ne change cela ; il rend simplement la partie technique fonctionnelle. Lisez les conditions d'utilisation d'Agoda et son robots.txt, maintenez votre volume de requêtes modéré pour ne pas mettre à rude épreuve ses serveurs, et traitez les deux documents comme la limite de ce que vous collectez. Le scraping web se situe dans une zone juridique grise, et la posture la plus sûre est de ne collecter que ce qui est publiquement visible et de rester bien dans des limites de débit raisonnables.
Quelques lignes à respecter. Ne collectez que les champs de listing publics : le nom de l'hôtel, le prix par nuit, le score d'avis des clients, la localisation et le lien de listing que tout le monde peut voir sans compte. Évitez tout ce qui est lié à des individus identifiables, y compris les noms de clients associés aux avis ou les coordonnées d'hôtes ou de clients, qui sont des données personnelles et sortent du cadre du listing public. Les lois sur la vie privée comme le RGPD et la CCPA s'appliquent dès que des données personnelles entrent en jeu, donc gardez le jeu de données aux informations factuelles sur les propriétés. Ne redistribuez pas le contenu protégé par le droit d'auteur d'Agoda comme les photos ou le texte complet des avis, et n'essayez pas d'atteindre quoi que ce soit derrière une connexion, une réservation sauvegardée ou un compte.
Ce guide est délibérément limité aux résultats de recherche publics car c'est la ligne qui rend le travail défendable. Si votre projet nécessite plus que cela, ou si vous construisez quelque chose de commercial sur la base de données hôtelières, la bonne voie est un accord de licence : Agoda gère un programme officiel de partenariat et d'affiliation avec une API sanctionnée pour les cas d'usage permis, ce qui est la bonne route pour l'utilisation en masse ou en production, pas un scraper plus astucieux.
Points clés
- Agoda est rendu côté client et chargé au défilement. Une requête simple renvoie une fine coquille avec seulement quelques cartes, vous devez donc rendre et faire défiler la page avant de l'analyser.
-
Vous avez besoin du rendu, du défilement et d'une IP de confiance ensemble. La Crawling API avec un token JS fait les trois en un seul appel ;
scrolletscroll_intervalcontrôlent quelle part de l'ensemble de résultats se charge. -
Ciblez les hooks stables d'Agoda. Lisez le nom de l'hôtel depuis
data-selenium="hotel-name", le prix depuisdata-element-name="final-price", la note depuisdata-element-name="review-score", et le lien depuisa.PropertyCard__Link. - Exportez des enregistrements structurés. Bouclez les cartes de propriété en nom, prix, note, localisation et lien, puis écrivez-les en JSON (ou CSV) pour analyse.
- Restez sur les données publiques. Respectez les CGU et le robots.txt d'Agoda, gardez les données personnelles et les médias protégés par le droit d'auteur hors du jeu de données, et utilisez l'API officielle partenaire d'Agoda pour l'utilisation commerciale ou en masse.
Foire aux questions
Pourquoi une requête simple ne renvoie-t-elle que quelques hôtels Agoda ?
Parce qu'Agoda construit ses résultats de recherche côté client avec JavaScript et ne charge les cartes de propriétés supplémentaires qu'au fur et à mesure que vous faites défiler. Le HTML initial est une coquille qui se remplit après l'exécution des scripts de la page et le défilement de la page, donc une requête HTTP brute renvoie le statut 200 avec la plupart des cartes manquantes. Pour obtenir la page complète, vous devez d'abord la rendre et la faire défiler, ce que le token JS et les options scroll de la Crawling API gèrent pour vous.
Ai-je besoin du token normal ou du token JS pour Agoda ?
Le token JS. Le token normal récupère le HTML statique, qui sur Agoda est la même fine coquille qu'une récupération simple renvoie. Le token JS rend la page dans un vrai navigateur et, avec les options scroll définies, la fait défiler avant de renvoyer le HTML, donc les cartes de propriétés sont présentes quand BeautifulSoup les analyse.
Quelles données puis-je scraper depuis un listing Agoda ?
Les champs de listing publics : le nom de l'hôtel, le prix par nuit, le score d'avis des clients, la localisation et le lien de listing. Restez sur les données visibles par tout visiteur sans compte, et évitez les noms de clients liés aux avis ou les coordonnées d'hôtes ou de clients, qui sont des données personnelles et sortent du cadre du listing public couvert par ce guide.
Comment scraper les hôtels d'une ville différente ?
Agoda identifie chaque ville avec un paramètre city numérique dans l'URL de recherche (par exemple, city=14524 pour Kuala Lumpur). Trouvez l'identifiant en lançant la recherche dans votre navigateur et en le lisant depuis l'URL, puis échangez-le dans search_url avec vos propres paramètres d'arrivée, de départ et d'occupation. Pour couvrir plusieurs villes, bouclez sur une liste d'identifiants et appelez fetch_agoda_page pour chacun.
Mes sélecteurs renvoient des chaînes vides. Qu'est-ce qui a changé ?
Très probablement le balisage d'Agoda. Ses hooks data-selenium et data-element-name et ses noms de classes générés changent sans préavis, donc les sélecteurs qui fonctionnaient le mois dernier peuvent être cassés. 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.
Comment gérer les CAPTCHA et les blocages sur Agoda ?
Agoda utilise des CAPTCHA et d'autres techniques de détection de bots sur le trafic automatisé. La Crawling API gère cela pour vous avec le rendu basé sur navigateur et la rotation d'IP côté serveur, donc la plupart des défis sont résolus avant que le HTML atteigne votre code. Au-delà, espacez vos requêtes, variez vos cibles, et ralentissez quand vous commencez à voir des valeurs cb_status non-200 plutôt que de réessayer en forçant.
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.
