Google Hotels est l'endroit où la plupart des voyageurs comparent les hébergements avant de réserver : prix, notes, photos et disponibilités se trouvent côte à côte en un seul endroit. Pour quiconque travaille sur la surveillance des prix, l'analyse concurrentielle ou les modèles de demande touristique, cette surface est une source riche de données structurées. Le problème est que Google Hotels rend ses annonces côté client et se défend fortement contre le trafic automatisé, si bien qu'une simple requête HTTP vous remet une page quasi vide au lieu des hôtels recherchés.

Ce guide vous montre comment scraper Google Hotels avec Python de manière fiable. Vous construirez un petit scraper fonctionnel qui récupère les résultats rendus via la Crawling API, les analyse avec BeautifulSoup, et extrait pour chaque hôtel : nom, prix, note et lien. L'ensemble du tutoriel se limite aux données de résultats publics, et la section sur la légalité à la fin n'est pas un simple formulaire, alors lisez-la avant de l'utiliser à grande échelle.

Ce que vous allez construire

Un script Python qui prend une URL de recherche Google Hotels, récupère le HTML rendu via la Crawling API, et extrait un enregistrement structuré pour chaque hôtel sur la page. Nous utiliserons une recherche par ville comme exemple fil rouge et extrairons ces champs :

  • Nom le nom de l'hôtel tel qu'il apparaît sur la carte.
  • Prix le prix par nuit pour les dates sélectionnées.
  • Note la note moyenne des clients, quand elle est affichée.
  • Lien l'URL vers le résultat de cet hôtel sur Google.

Pourquoi une simple requête échoue sur Google Hotels

Demandez une URL de recherche Google Hotels avec un client HTTP basique et vous obtenez une réponse avec le statut 200 et presque aucune donnée d'annonce dans le corps. Deux facteurs jouent contre vous. D'abord, Google Hotels construit ses cartes de résultats dans le navigateur avec JavaScript, donc le HTML initial est une coquille qui ne se remplit qu'après l'exécution des scripts de la page. Ensuite, Google signale rapidement le trafic automatisé : les IP de datacenter et les patterns de requêtes qui ne ressemblent pas à un vrai navigateur sont challengés ou bloqués avant d'atteindre le contenu rendu.

Un scraper Google Hotels fonctionnel a donc besoin de deux choses en une seule requête : un navigateur qui rend réellement la page, et une IP que la plateforme considère 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 bonne santé représente l'essentiel du travail. La Crawling API regroupe les deux en un seul appel : envoyez-lui l'URL avec un token JavaScript, elle rend la page derrière une IP de confiance, et vous remet le HTML finalisé à analyser.

Pourquoi le token JS

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. Google Hotels est rendu côté client, donc vous avez besoin du token JS ici. Le token normal renvoie la même coquille vide qu'une simple requête, et il n'y a rien à en extraire.

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ébutez avec le langage, la documentation officielle Python et tout cours pour débutants vous amènera au niveau requis par 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.

Un compte Crawlbase et un token JS. Inscrivez-vous, ouvrez votre tableau de bord, et copiez votre token JavaScript (JS) depuis la page de documentation du compte. Les nouveaux comptes incluent des requêtes gratuites sans carte requise. Traitez le token comme un mot de passe : il authentifie vos requêtes, alors ne le mettez pas dans le contrôle de version.

Configurer le projet

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

bash
python --version

python -m venv hotels_env
source hotels_env/bin/activate

pip install crawlbase beautifulsoup4

Sur Windows, activez l'environnement avec hotels_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.

Étape 1 : Récupérer les résultats rendus

Commencez par obtenir la page finalisée. Importez la classe CrawlingAPI, initialisez-la avec votre token JS, et demandez l'URL de recherche. Lire le code de statut avant d'analyser permet de garder les échecs bien visibles plutôt que silencieux, ce qui compte beaucoup sur une cible qui limite le débit.

python
from crawlbase import CrawlingAPI

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

def crawl(page_url):
    options = {"ajax_wait": "true", "page_wait": 5000}
    response = api.get(page_url, options)
    status = response["headers"].get("pc_status")
    if status == "200":
        return response["body"].decode("utf-8")
    print(f"Request failed: {status}")
    return None

if __name__ == "__main__":
    page_url = "https://www.google.com/travel/search?q=hotels+in+New+York&currency=USD"
    html = crawl(page_url)
    print(html[:500] if html else "No HTML returned")

Les deux options d'attente sont importantes pour une cible rendue côté client comme celle-ci. ajax_wait indique à l'API d'attendre que le contenu asynchrone ait fini de se charger, et page_wait maintient un nombre fixe de millisecondes après le chargement pour que les cartes à rendu tardif apparaissent avant la capture de la page. Cinq secondes est un bon point de départ ; augmentez si la liste de résultats revient courte ou vide. Notez l'en-tête pc_status : c'est le statut propre à Crawlbase pour la requête sous-jacente, et c'est la valeur à laquelle se fier plutôt qu'au code HTTP externe pour décider si une récupération a réussi. Exécutez le script et vous devriez voir le vrai balisage des annonces, pas la coquille vide qu'une simple requête renvoie.

Crawlbase Crawling API

Google Hotels a besoin d'une page rendue derrière une IP de confiance, en un seul appel. La Crawling API prend un token JS, exécute la page dans un vrai navigateur, effectue une rotation des IP résidentielles côté serveur, et vous remet le HTML finalisé, vous évitant de gérer vous-même une flotte headless et un pool de proxies. Pointez-la sur une recherche publique avec le niveau gratuit d'abord.

Étape 2 : Analyser les cartes d'hôtel avec BeautifulSoup

Avec le HTML rendu en main, chargez-le dans BeautifulSoup et extrayez chaque hôtel de sa carte de résultat. Google dispose les annonces sous forme d'éléments de carte répétitifs, vous trouvez donc toutes les cartes, puis lisez nom, prix, note et lien dans chacune. Protégez chaque champ pour qu'une note ou un prix manquant ne fasse pas planter l'exécution.

python
from bs4 import BeautifulSoup

def parse_hotels(html):
    soup = BeautifulSoup(html, "html.parser")
    hotels = []

    for card in soup.find_all("div", class_="BcKagd"):
        name = card.find("h2", class_="BgYkof")
        price = card.find("span", class_="qQOQpe prxS3d")
        rating = card.find("span", class_="KFi5wf lA0BZ")
        link = card.find("a", class_="PVOOXe")

        hotels.append({
            "name": name.text.strip() if name else None,
            "price": price.text.strip() if price else None,
            "rating": rating.text.strip() if rating else None,
            "link": "https://www.google.com" + link["href"] if link else None,
        })

    return hotels

Chaque garde if name else None fait le même travail : il renvoie None quand un élément est absent au lieu de planter sur un appel .text vers rien. Cela rend l'extraction résistante quand une carte n'a pas de prix ou n'a pas encore de note, ce qui est courant sur une page de résultats. Le lien est lu depuis le href de l'ancre et préfixé avec le host Google, car le balisage utilise des chemins relatifs.

Les sélecteurs dérivent

Les noms de classes de Google (BcKagd, BgYkof, qQOQpe prxS3d, et les autres) sont obfusqués et changent sans préavis. Traitez les sélecteurs ci-dessus comme un modèle de départ, pas comme un contrat. Quand un champ revient à None sur toutes les cartes, 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 tout

Maintenant, reliez la récupération et l'analyse en un seul script fonctionnel. Récupérez le HTML rendu, passez-le au parseur, et écrivez les enregistrements structurés dans un fichier JSON.

python
import json
from crawlbase import CrawlingAPI
from bs4 import BeautifulSoup

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

def crawl(page_url):
    options = {"ajax_wait": "true", "page_wait": 5000}
    response = api.get(page_url, options)
    status = response["headers"].get("pc_status")
    if status == "200":
        return response["body"].decode("utf-8")
    print(f"Request failed: {status}")
    return None

def parse_hotels(html):
    soup = BeautifulSoup(html, "html.parser")
    hotels = []
    for card in soup.find_all("div", class_="BcKagd"):
        name = card.find("h2", class_="BgYkof")
        price = card.find("span", class_="qQOQpe prxS3d")
        rating = card.find("span", class_="KFi5wf lA0BZ")
        link = card.find("a", class_="PVOOXe")
        hotels.append({
            "name": name.text.strip() if name else None,
            "price": price.text.strip() if price else None,
            "rating": rating.text.strip() if rating else None,
            "link": "https://www.google.com" + link["href"] if link else None,
        })
    return hotels

def main():
    page_url = "https://www.google.com/travel/search?q=hotels+in+New+York&currency=USD"
    html = crawl(page_url)
    if not html:
        return
    hotels = parse_hotels(html)
    with open("google_hotels.json", "w", encoding="utf-8") as f:
        json.dump(hotels, f, ensure_ascii=False, indent=2)
    print(f"Saved {len(hotels)} hotels to google_hotels.json")

if __name__ == "__main__":
    main()

À quoi ressemble la sortie

Exécutez le script complet et vous obtenez une liste propre d'enregistrements structurés, prête à écrire en CSV ou dans une base de données ou à alimenter un travail de suivi des prix.

json
[
  {
    "name": "The One Boutique Hotel",
    "price": "$90",
    "rating": "3.3",
    "link": "https://www.google.com/travel/search?q=New+York&..."
  },
  {
    "name": "Ly New York Hotel",
    "price": "$153",
    "rating": "4.4",
    "link": "https://www.google.com/travel/search?q=New+York&..."
  }
]

Charger plus de résultats

Une seule page de recherche affiche un échantillon limité d'hôtels ; Google révèle les autres derrière un bouton "more results" qui charge d'autres cartes en place. La Crawling API peut piloter cette interaction pour vous. Passez un css_click_selector pour le bouton et définissez ajax_wait pour que l'API clique, attende que les nouvelles cartes se rendent, puis renvoie le HTML étendu. La même fonction parse_hotels lit la page plus longue sans aucune modification.

python
def crawl_expanded(page_url, click_selector):
    options = {
        "ajax_wait": "true",
        "page_wait": 5000,
        "css_click_selector": click_selector,
    }
    response = api.get(page_url, options)
    if response["headers"].get("pc_status") == "200":
        return response["body"].decode("utf-8")
    return None

Le sélecteur de ce bouton est lui-même une valeur obfusquée que Google fait tourner, alors inspectez la page en direct et confirmez-le avant de vous y fier. Gardez le nombre d'expansions modeste. Chaque clic est une requête rendue supplémentaire contre une cible sensible, et en empiler plusieurs dans une boucle serrée est exactement le pattern qui fait limiter l'exécution.

Rester non bloqué

Même avec le rendu géré, Google surveille le trafic de type scraper plus durement que presque toute autre cible. Quelques habitudes maintiennent une exécution en bonne santé, et elles s'appliquent à tout site commercial agressif.

  • Cadencez vos requêtes. Marteler les recherches dans une boucle serrée est le moyen le plus rapide d'attirer un challenge. Étalez les requêtes et variez vos requêtes plutôt que de crawler une localisation à pleine vitesse.
  • 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 une limite de débit. La Crawling API s'en charge pour vous ; si vous construisez votre propre stack, c'est la partie à bien faire.
  • Lisez les codes de statut. Une exécution qui commence à renvoyer un pc_status non-200 ou un balisage de challenge visible vous indique que le débit ou le niveau d'IP actuels ne sont plus suffisants. Traitez cela comme un signal pour ralentir, pas comme du bruit à ignorer.

Pour le guide complet, consultez comment contourner les captchas lors du scraping de Google et comment faire tourner les proxies pour scraper les résultats de recherche Google. Si vous préférez router votre propre trafic via un pool rotatif plutôt qu'utiliser l'API gérée, le Smart AI Proxy (également appelé AI Proxy) vous donne la même rotation d'IP résidentielles sous forme d'endpoint proxy de substitution. Pour un guide approfondi sur la gestion des challenges, le guide sur comment contourner les captchas lors du web scraping couvre le cas général.

Est-il légal de scraper Google Hotels ?

La question de savoir si le scraping de Google Hotels est autorisé dépend des conditions d'utilisation de Google, de votre juridiction et de ce que vous faites avec les données. Les conditions de Google restreignent l'accès automatisé, donc le scraping peut aller à l'encontre de ces conditions quelle que soit la prudence de vos outils. Aucun code ici ne change cela ; il fait seulement fonctionner la partie technique. Lisez les Conditions d'utilisation de Google et le robots.txt pour la surface Travel, et traitez les deux comme la limite de ce que vous collectez.

Quelques lignes à tenir. Collectez uniquement les données de résultats publics : le nom de l'hôtel, le prix, la note et le lien que tout le monde voit sur une recherche sans se connecter. Respectez les attentes de débit indiquées par Google et maintenez votre volume de requêtes suffisamment bas pour ne pas solliciter ses serveurs. Ne scrapez rien derrière une connexion, rien de personnalisé pour un compte connecté, ni aucune donnée gardée par authentification, et ne tentez jamais de contourner l'authentification pour l'atteindre. Évitez les données personnelles, y compris tout ce qui est lié à des personnes identifiables au-delà de ce qui est listé publiquement.

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. Résultats publics uniquement, volume raisonnable. Si votre projet a besoin de plus que la surface publique, un flux de données touristiques sous licence ou un partenariat officiel est la bonne voie, pas un scraper plus habile.

Récapitulatif

Points clés

  • Google Hotels est rendu côté client. Une simple requête renvoie une coquille 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 du chargement du contenu.
  • BeautifulSoup fait l'extraction. Bouclez sur les cartes de résultats et lisez nom, prix, note et lien dans chacune, avec une garde sur chaque champ, et attendez-vous à ce que les sélecteurs obfusqués dérivent.
  • Cadencez et faites tourner. Google limite fort, alors étalez les requêtes, faites tourner les IP résidentielles, et lisez l'en-tête pc_status pour savoir quand ralentir.
  • Restez sur les données publiques. Respectez les CGU et robots.txt de Google, collectez uniquement les résultats publics, maintenez un volume raisonnable, et ne touchez jamais aux données derrière une connexion, personnalisées ou authentifiées.

Foire aux questions

Pourquoi une simple requête ne renvoie-t-elle pas d'hôtels de Google Hotels ?

Parce que Google Hotels construit ses cartes de résultats côté client avec JavaScript. Le HTML initial est une coquille qui ne se remplit qu'après l'exécution des scripts de la page dans un navigateur, donc une requête HTTP brute renvoie le statut 200 avec les annonces vides. Pour obtenir de vraies données, 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 pour Google Hotels ?

Le token JS. Le token normal récupère le HTML statique, qui sur Google Hotels est la même coquille vide qu'une simple requête renvoie. Le token JS rend la page dans un vrai navigateur avant de restituer le HTML, donc les cartes d'hôtel sont présentes quand BeautifulSoup les analyse.

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

Presque certainement le balisage de Google. Les noms de classes sur les cartes (BcKagd, BgYkof, et les autres) sont obfusqués et tournent sans préavis, donc les sélecteurs qui fonctionnaient le mois dernier peuvent casser. Réinspectez une page de résultats 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 obtenir plus d'une page de résultats ?

Google révèle des hôtels supplémentaires derrière un bouton "more results" plutôt que par une pagination classique. Passez le sélecteur de ce bouton à la Crawling API avec css_click_selector et définissez ajax_wait pour que l'API le clique, attende que les nouvelles cartes se rendent, et renvoie le HTML étendu. Gardez le nombre d'expansions modeste pour ne pas attirer un challenge.

Comment éviter d'être bloqué lors du scraping de Google Hotels ?

Maintenez un faible taux de requêtes par IP, variez vos requêtes plutôt que de boucler sur une localisation, et routez via des IP résidentielles rotatives pour qu'aucune adresse ne déclenche une limite de débit. La Crawling API gère la rotation et un pool d'IP de confiance pour vous ; si vous construisez votre propre stack, le Smart AI Proxy vous donne cette rotation sous forme d'endpoint proxy de substitution. Surveillez l'en-tête pc_status et ralentissez quand vous commencez à voir des réponses non-200.

Puis-je scraper des données de réservation ou de compte depuis Google Hotels ?

Non, et ce guide ne le couvre pas. Tout ce qui est lié à un compte connecté, un flux de réservation ou une tarification personnalisée se trouve derrière une authentification, donc ce ne sont pas des données de résultats publics. Scraper du contenu derrière une connexion ou personnalisé, ou contourner l'authentification pour l'atteindre, sort du cadre ici et va à l'encontre des conditions de Google. Restez sur la surface de recherche publique et maintenez un volume raisonnable.

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