Google Hotels ist der Ort, an dem die meisten Reisenden Unterkünfte vergleichen, bevor sie buchen: Preise, Bewertungen, Fotos und Verfügbarkeit nebeneinander an einem Ort. Für jeden, der an Preisüberwachung, Wettbewerbsanalyse oder Reisennachfragemodellen arbeitet, ist diese Oberfläche eine reiche Quelle strukturierter Daten. Das Problem ist, dass Google Hotels seine Einträge clientseitig rendert und sich hart gegen automatisierten Traffic verteidigt, sodass eine einfache HTTP-Anfrage eine nahezu leere Seite statt der gesuchten Hotels liefert.

Dieser Leitfaden zeigt Ihnen, wie Sie Google Hotels mit Python zuverlässig scrapen. Sie bauen ein kleines, lauffähiges Skript, das die gerenderten Ergebnisse über die Crawling API abruft, sie mit BeautifulSoup parst und pro Hotel extrahiert: Name, Preis, Bewertung und Link. Die gesamte Anleitung beschränkt sich auf öffentliche Ergebnisdaten, und der Abschnitt zur Rechtslage gegen Ende ist kein Boilerplate, also lesen Sie ihn, bevor Sie das auf echtes Volumen ansetzen.

Was Sie bauen werden

Ein Python-Skript, das eine Google-Hotels-Such-URL entgegennimmt, das gerenderte HTML über die Crawling API abruft und einen strukturierten Datensatz für jedes Hotel auf der Seite extrahiert. Wir verwenden eine Stadtsuche als laufendes Beispiel und holen diese Felder:

  • Name der Hotelname wie auf der Karte angezeigt.
  • Preis der Übernachtungspreis für die ausgewählten Daten.
  • Bewertung die durchschnittliche Gastbewertung, sofern eine angezeigt wird.
  • Link die URL zum Ergebnis dieses Hotels auf Google.

Warum ein einfacher Fetch bei Google Hotels scheitert

Fordern Sie eine Google-Hotels-Such-URL mit einem einfachen HTTP-Client an, erhalten Sie eine Antwort mit Status 200 und fast keine der Listungsdaten im Body. Zwei Kräfte arbeiten gegen Sie. Erstens baut Google Hotels seine Ergebniskarten im Browser mit JavaScript auf, sodass das initiale HTML eine Hülle ist, die sich erst füllt, nachdem die Skripte der Seite ausgeführt wurden. Zweitens kennzeichnet Google automatisierten Traffic schnell: Datacenter-IPs und Anfragemuster, die nicht wie ein echter Browser aussehen, werden herausgefordert oder blockiert, bevor sie jemals den gerenderten Inhalt erreichen.

Ein funktionierender Google-Hotels-Scraper benötigt also zwei Dinge in einer Anfrage: einen Browser, der die Seite tatsächlich rendert, und eine IP, die die Plattform als echten Besucher liest. Sie können das selbst mit einem Headless-Browser plus einem Pool von rotierenden Residential Proxies zusammensetzen, aber diese zusammenzuhalten und gesund zu halten ist der Großteil der Arbeit. Die Crawling API faltet beides in einen einzigen Aufruf: Sie senden ihr die URL mit einem JavaScript-Token, sie rendert die Seite hinter einer vertrauenswürdigen IP und gibt fertiges HTML zum Parsen zurück.

Warum das JS-Token

Crawlbase bietet zwei Token-Typen. Das normale Token ruft statisches HTML ab; das JavaScript-Token (JS-Token) rendert die Seite zuerst in einem echten Browser. Google Hotels wird clientseitig gerendert, also benötigen Sie hier das JS-Token. Das normale Token gibt die gleiche leere Hülle zurück wie ein einfacher Fetch, und es ist nichts daraus zu parsen.

Voraussetzungen

Sie benötigen einige Dinge, bevor Sie Code schreiben. Keines davon dauert lange.

Grundlegendes Python. Sie sollten in der Lage sein, ein Python-Skript zu schreiben und auszuführen sowie Pakete mit pip zu installieren. Wenn Sie neu in der Sprache sind, bringen die offiziellen Python-Docs und jeder Einsteigerkurs Sie auf das Niveau, das dieses Tutorial voraussetzt.

Python 3.8 oder neuer. Bestätigen Sie Ihre Version mit python --version. Wenn Sie es nicht haben, installieren Sie es von python.org oder über eine Distribution wie Anaconda.

Ein Crawlbase-Konto und JS-Token. Registrieren Sie sich, öffnen Sie Ihr Dashboard und kopieren Sie Ihr JavaScript-Token (JS-Token) von der Konto-Docs-Seite. Neue Konten beinhalten kostenlose Anfragen ohne Kreditkarte. Behandeln Sie das Token wie ein Passwort: Es authentifiziert Ihre Anfragen, also halten Sie es aus der Versionskontrolle heraus.

Das Projekt einrichten

Erstellen Sie eine virtuelle Umgebung, damit Projektabhängigkeiten isoliert bleiben, und installieren Sie dann die zwei Bibliotheken, die der Scraper benötigt.

bash
python --version

python -m venv hotels_env
source hotels_env/bin/activate

pip install crawlbase beautifulsoup4

Unter Windows aktivieren Sie die Umgebung mit hotels_env\Scripts\activate statt der source-Zeile. Zwei Abhängigkeiten erledigen die Arbeit: crawlbase ist der offizielle Client für die Crawling API, und beautifulsoup4 parst das zurückgegebene HTML, damit Sie einzelne Felder per CSS-Selektor herausziehen können.

Schritt 1: Die gerenderten Ergebnisse abrufen

Beginnen Sie damit, die fertige Seite zu holen. Importieren Sie die CrawlingAPI-Klasse, initialisieren Sie sie mit Ihrem JS-Token und fordern Sie die Such-URL an. Den Status-Code vor dem Parsen zu lesen hält Fehler laut statt still, was bei einem Ziel, das drosselt, sehr wichtig ist.

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("cb_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")

Die zwei Warte-Optionen sind wichtig für ein clientseitig gerendertes Ziel wie dieses. ajax_wait weist die API an, auf das Laden asynchroner Inhalte zu warten, und page_wait hält eine feste Anzahl von Millisekunden nach dem Laden an, damit spät-rendernde Karten erscheinen, bevor die Seite erfasst wird. Fünf Sekunden sind ein vernünftiger Ausgangspunkt; erhöhen Sie den Wert, wenn die Ergebnisliste kurz oder leer zurückkommt. Beachten Sie den cb_status (legacy pc_status)-Header: Das ist Crawlbase's eigener Status für die zugrundeliegende Anfrage, und er ist der Wert, dem Sie über den äußeren HTTP-Code trauen sollten, wenn Sie entscheiden, ob ein Fetch erfolgreich war. Führen Sie das Skript aus und Sie sollten echtes Listing-Markup sehen, nicht die leere Hülle, die ein einfacher Fetch zurückgibt.

Crawlbase Crawling API

Google Hotels benötigt eine gerenderte Seite hinter einer vertrauenswürdigen IP, in einem einzigen Aufruf. Die Crawling API nimmt ein JS-Token, führt die Seite in einem echten Browser aus, rotiert serverseitig durch Residential IPs und gibt Ihnen fertiges HTML zurück, sodass Sie keinen eigenen Headless-Fleet und keinen Proxy-Pool betreiben müssen. Zeigen Sie es zuerst auf eine öffentliche Suche im kostenlosen Kontingent.

Schritt 2: Die Hotelkarten mit BeautifulSoup parsen

Mit gerendertem HTML in der Hand laden Sie es in BeautifulSoup und ziehen jedes Hotel aus seiner Ergebniskarte. Google legt die Einträge als sich wiederholende Kartenelemente an, also finden Sie alle Karten und lesen dann Name, Preis, Bewertung und Link aus jeder einzelnen. Sichern Sie jedes Feld ab, damit eine fehlende Bewertung oder ein fehlender Preis den Lauf nicht zum Absturz bringt.

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

Jede if name else None-Absicherung erledigt dasselbe: Sie gibt None zurück, wenn ein Element fehlt, statt bei einem .text-Aufruf auf nichts zu scheitern. Das hält die Extraktion widerstandsfähig, wenn einer Karte ein Preis fehlt oder noch keine Bewertung hat, was auf einer Ergebnisseite häufig vorkommt. Der Link wird aus dem href des Ankers gelesen und mit dem Google-Host vorangestellt, da das Markup relative Pfade verwendet.

Selektoren driften

Googles Klassennamen (BcKagd, BgYkof, qQOQpe prxS3d und der Rest) sind obfuskiert und ändern sich ohne Vorankündigung. Behandeln Sie die Selektoren oben als Startvorlage, nicht als Vertrag. Wenn ein Feld bei jeder Karte als None zurückkommt, untersuchen Sie die Live-Seite in den Entwicklertools Ihres Browsers erneut und aktualisieren Sie den Selektor. Periodische Selektor-Wartung ist bei jedem Produktions-Scraper normal, kein Zeichen dafür, dass etwas kaputt ist.

Schritt 3: Alles zusammensetzen

Verbinden Sie nun Fetch und Parse in einem lauffähigen Skript. Das gerenderte HTML abrufen, es dem Parser übergeben und die strukturierten Datensätze in eine JSON-Datei schreiben.

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("cb_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()

Wie die Ausgabe aussieht

Führen Sie das vollständige Skript aus und Sie erhalten eine saubere Liste strukturierter Datensätze, bereit zum Schreiben in CSV oder eine Datenbank oder zum Speisen eines Price-Tracking-Jobs.

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&..."
  }
]

Mehr Ergebnisse laden

Eine Suchseite zeigt nur einen begrenzten Ausschnitt von Hotels; Google enthüllt den Rest hinter einer Schaltfläche "Mehr Ergebnisse", die weitere Karten direkt lädt. Die Crawling API kann diese Interaktion für Sie steuern. Übergeben Sie einen css_click_selector für die Schaltfläche und setzen Sie ajax_wait, damit die API klickt, auf das Rendern der neuen Karten wartet und dann das erweiterte HTML zurückgibt. Die gleiche parse_hotels-Funktion liest die längere Seite ohne Änderungen.

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("cb_status") == "200":
        return response["body"].decode("utf-8")
    return None

Der Selektor für diese Schaltfläche ist selbst ein obfuskierter Wert, den Google rotiert, also untersuchen Sie die Live-Seite und bestätigen Sie ihn, bevor Sie sich darauf verlassen. Halten Sie die Anzahl der Erweiterungen bescheiden. Jeder Klick ist eine weitere gerenderte Anfrage gegen ein empfindliches Ziel, und das Stapeln von vielen davon in einer engen Schleife ist genau das Muster, das einen Lauf drosselt.

Nicht geblockt werden

Auch mit behandeltem Rendering beobachtet Google scraper-förmigen Traffic härter als fast jedes andere Ziel. Einige Gewohnheiten halten einen Lauf gesund, und sie gelten für jede aggressive kommerzielle Site.

  • Anfragen steuern. Suchen in einer engen Schleife zu hämmern ist der schnellste Weg zu einer Herausforderung. Verteilen Sie Anfragen und variieren Sie Ihre Anfragen statt einen Ort mit voller Geschwindigkeit zu crawlen.
  • Auf Rotation setzen. Ein Pool von Residential IPs verteilt Anfragen über viele reale Benutzeradressen, sodass keine einzelne ein Ratenlimit auslöst. Die Crawling API erledigt das für Sie; wenn Sie Ihren eigenen Stack aufbauen, ist das der Teil, den Sie richtig machen müssen.
  • Status-Codes lesen. Ein Lauf, der beginnt, Nicht-200-cb_status-Werte oder sichtbares Challenge-Markup zurückzugeben, sagt Ihnen, dass die aktuelle Rate oder IP-Stufe nicht mehr ausreicht. Behandeln Sie das als Signal zum Zurückrudern, nicht als Rauschen zum Ignorieren.

Für das breitere Playbook lesen Sie, wie man CAPTCHAs beim Scrapen von Google umgeht, und wie man Proxies für das Scrapen von Google-Suchergebnissen rotiert. Wenn Sie lieber Ihren eigenen Traffic durch einen rotierenden Pool statt die verwaltete API leiten möchten, bietet der Smart AI Proxy (auch als AI Proxy bezeichnet) die gleiche Residential-IP-Rotation als Drop-in-Proxy-Endpunkt. Für einen tieferen Einblick in die Challenge-Behandlung behandelt der Leitfaden zu wie man CAPTCHAs beim Web-Scraping umgeht den allgemeinen Fall.

Ob das Scrapen von Google Hotels erlaubt ist, hängt von Googles Nutzungsbedingungen, Ihrer Rechtsordnung und dem ab, was Sie mit den Daten machen. Googles Bedingungen schränken automatisierten Zugriff ein, sodass Scraping gegen diese Bedingungen verstoßen kann, unabhängig davon, wie sorgfältig Ihr Tooling ist. Kein Code hier ändert das; er lässt nur den technischen Teil funktionieren. Lesen Sie Googles Nutzungsbedingungen und die robots.txt für die Travel-Oberfläche und behandeln Sie beides als Grenze dessen, was Sie sammeln.

Einige Linien, an denen man festhalten sollte. Sammeln Sie nur öffentliche Ergebnisdaten: den Hotelnamen, Preis, Bewertung und Link, die jeder ohne Anmeldung bei einer Suche sieht. Respektieren Sie Googles angegebene Ratenerwartungen und halten Sie Ihr Anfragevolumen niedrig genug, dass Sie Googles Server nicht belasten. Scrapen Sie nichts hinter einem Login, nichts für ein angemeldetes Konto Personalisiertes oder Daten, die durch Authentifizierung gesperrt sind, und versuchen Sie niemals, Authentifizierung zu umgehen, um es zu erreichen. Vermeiden Sie persönliche Daten, einschließlich allem, was mit identifizierbaren Personen über das öffentlich Gelistete hinaus verbunden ist.

Dieser Leitfaden ist bewusst auf öffentliche Suchergebnisse beschränkt, weil das die Linie ist, die die Arbeit vertretbar hält. Nur öffentliche Ergebnisse, vernünftiges Volumen. Wenn Ihr Projekt mehr als die öffentliche Oberfläche benötigt, ist ein lizenzierter Reisedaten-Feed oder eine offizielle Partnerschaft der richtige Weg, kein clevererer Scraper.

Zusammenfassung

Wichtigste Erkenntnisse

  • Google Hotels wird clientseitig gerendert. Ein einfacher Fetch gibt eine leere Hülle zurück, also müssen Sie die Seite rendern, bevor Sie sie parsen.
  • Sie benötigen Rendering und eine vertrauenswürdige IP zusammen. Die Crawling API mit einem JS-Token erledigt beides in einem Aufruf; ajax_wait und page_wait steuern, wie lange es auf Inhalte wartet.
  • BeautifulSoup erledigt die Extraktion. Durchlaufen Sie die Ergebniskarten und lesen Sie Name, Preis, Bewertung und Link aus jeder, mit einer Absicherung bei jedem Feld, und erwarten Sie, dass die obfuskierten Selektoren driften.
  • Steuern und rotieren. Google drosselt hart, also verteilen Sie Anfragen, rotieren Sie Residential IPs und lesen Sie den cb_status-Header, um zu wissen, wann Sie zurückrudern müssen.
  • Bei öffentlichen Daten bleiben. Respektieren Sie Googles AGB und robots.txt, sammeln Sie nur öffentliche Ergebnisse, halten Sie das Volumen vernünftig und berühren Sie niemals durch Login gesperrte, personalisierte oder authentifizierungsgeschützte Daten.

Häufig gestellte Fragen

Warum gibt ein einfacher Fetch keine Hotels von Google Hotels zurück?

Weil Google Hotels seine Ergebniskarten clientseitig mit JavaScript aufbaut. Das initiale HTML ist eine Hülle, die sich erst füllt, nachdem die Skripte der Seite in einem Browser ausgeführt wurden, sodass eine rohe HTTP-Anfrage Status 200 mit leeren Listings zurückgibt. Um echte Daten zu erhalten, müssen Sie die Seite zuerst rendern, was das JS-Token der Crawling API für Sie übernimmt.

Brauche ich das normale Token oder das JS-Token für Google Hotels?

Das JS-Token. Das normale Token ruft statisches HTML ab, das bei Google Hotels die gleiche leere Hülle wie ein einfacher Fetch ist. Das JS-Token rendert die Seite in einem echten Browser, bevor es das HTML zurückgibt, sodass die Hotelkarten vorhanden sind, wenn BeautifulSoup sie parst.

Meine Selektoren geben bei jeder Karte None zurück. Was hat sich geändert?

Mit ziemlicher Sicherheit Googles Markup. Die Klassennamen auf den Karten (BcKagd, BgYkof und der Rest) sind obfuskiert und rotieren ohne Vorankündigung, sodass Selektoren, die letzten Monat funktionierten, brechen können. Untersuchen Sie eine Live-Ergebnisseite in den Entwicklertools Ihres Browsers erneut und aktualisieren Sie die Selektoren. Periodische Selektor-Wartung ist bei jedem Produktions-Scraper normal.

Wie erhalte ich mehr als eine Seite mit Ergebnissen?

Google enthüllt weitere Hotels hinter einer Schaltfläche "Mehr Ergebnisse" statt klassischer Paginierung. Übergeben Sie den Selektor dieser Schaltfläche mit css_click_selector an die Crawling API und setzen Sie ajax_wait, damit die API darauf klickt, auf das Rendern der neuen Karten wartet und das erweiterte HTML zurückgibt. Halten Sie die Anzahl der Erweiterungen bescheiden, damit Sie keine Herausforderung auslösen.

Wie vermeide ich das Blockieren beim Scrapen von Google Hotels?

Halten Sie Ihre Per-IP-Anfragerate niedrig, variieren Sie Ihre Anfragen statt einen Ort zu durchlaufen, und leiten Sie den Traffic durch rotierende Residential IPs, damit keine einzelne Adresse ein Ratenlimit auslöst. Die Crawling API verwaltet Rotation und einen vertrauenswürdigen IP-Pool für Sie; wenn Sie Ihren eigenen Stack aufbauen, bietet der Smart AI Proxy diese Rotation als Drop-in-Endpunkt. Beobachten Sie den cb_status-Header und rudern Sie zurück, wenn Sie beginnen, Nicht-200-Antworten zu sehen.

Kann ich Buchungs- oder Kontodaten von Google Hotels scrapen?

Nein, und dieser Leitfaden deckt das nicht ab. Alles, was mit einem angemeldeten Konto, einem Buchungsablauf oder personalisierten Preisen verbunden ist, liegt hinter Authentifizierung, sodass es keine öffentlichen Ergebnisdaten sind. Das Scrapen von durch Login gesperrten oder personalisierten Inhalten oder das Umgehen von Authentifizierung, um sie zu erreichen, liegt außerhalb des Geltungsbereichs hier und verstößt gegen Googles Bedingungen. Bleiben Sie bei der öffentlichen Suchoberfläche und halten Sie das Volumen vernünftig.

Jetzt loslegen

Crawlen Sie jede Website im großen Maßstab, ohne gegen die Infrastruktur zu kämpfen.

Crawlbase übernimmt Proxys, Fingerprints und CAPTCHAs, damit Ihr Team Datenpipelines ausliefert, statt Crawl-Infrastruktur zu pflegen. 1.000 Anfragen kostenlos, keine Karte erforderlich.

Self-Service · Kein Verkaufsgespräch erforderlich · Enterprise-Crawl-Volumen verfügbar