Was Sie aus Expedia extrahieren können und warum es wichtig ist
Wenn Sie die Hotelsuchergebnisse von Expedia scrapen, kann ein gut programmierter Scraper die folgenden Felder aus jeder Listungskarte extrahieren:
- Hotelname – der Anzeigename der Unterkunft, wie er in den Suchergebnissen angezeigt wird
- Preis pro Nacht – der Preis für die von Ihnen ausgewählten Daten, einschließlich etwaiger Sonderangebote
- Sternebewertung – die offizielle Sterneklassifizierung (1–5)
- Bewertung der Gäste – aggregierte Nutzerbewertung (z. B. 8,4/10)
- Anzahl der Bewertungen – die Anzahl der Bewertungen, auf denen die Punktzahl basiert
- Lage/Umgebung – nützlich für Geofilterung und Kartendarstellung
Der Datensatz kann um Aktionsbadges oder Miniaturbilder erweitert werden, um eine umfassendere nachgelagerte Analyse zu ermöglichen.
Anwendungsfälle in der Praxis umfassen Preisüberwachung (Verfolgung von Preisänderungen über verschiedene Daten und Reiseziele hinweg), Reisevergleichs-Apps (Zusammenfassung von Angeboten mehrerer Online-Reisebüros) und Wettbewerbsbenchmarking (Vergleich der Preisgestaltung einer Unterkunft mit benachbarten Hotels). Die gesammelten Expedia-Daten können auch in Empfehlungsmaschinen und kundenorientierte Reisetools einfließen.
Rechtliche und ethische Überlegungen, bevor Sie beginnen
Bevor Sie auch nur eine einzige Zeile Code schreiben, gehen Sie diese Checkliste durch:
- Überprüfen Sie robots.txt – Besuchen Sie https://www.expedia.com/robots.txt und beachten Sie unzulässige Pfade. (Überprüfen Sie dies zum Zeitpunkt der Veröffentlichung – Richtlinien können sich ändern.)
- Lesen Sie die Nutzungsbedingungen – Die Nutzungsbedingungen von Expedia schränken den automatisierten Zugriff ein. Persönliche Recherchen fallen in eine andere Risikokategorie als der kommerzielle Weiterverkauf. Konsultieren Sie einen Anwalt, wenn Sie sich unsicher sind.
- Scrapen Sie nur öffentliche Daten – Hotelauflistungen, die jedem anonymen Besucher angezeigt werden, sind öffentlich. Versuchen Sie nicht, auf kontengeschützte Inhalte zuzugreifen oder Formulare automatisch abzuschicken.
- Begrenzen Sie die Anzahl Ihrer Anfragen – Fügen Sie absichtliche Verzögerungen ein (mindestens 2–5 Sekunden zwischen den Anfragen). Einen Server zu überlasten ist sowohl ethisch verwerflich als auch ein schneller Weg, gesperrt zu werden.
- Speichern Sie Daten verantwortungsbewusst — Behalten Sie nur das, was Sie benötigen, und vermeiden Sie es, gescrapte Inhalte so wiederzuveröffentlichen, dass sie in direkter Konkurrenz zu Expedia-eigenen Produkten stehen.
Warum Expedia schwer zu scrapen ist
Expedia lädt seine Hotellisten dynamisch über JavaScript, was bedeutet, dass ein statischer Scraper, der reines HTML abruft, den eigentlichen Inhalt verpasst. Der Server sendet eine weitgehend leere Hülle; der Browser führt JavaScript aus, um die Hotelkarten abzurufen und darzustellen. Wenn Sie dieses JavaScript nicht ausführen, sehen Sie die Daten nicht. Das Rendern von JavaScript ist eine grundlegende Herausforderung beim Web-Scraping, und Expedia ist eines der aggressiveren Beispiele dafür.
Über das Rendern hinaus setzt Expedia IP-Blockierung ein (wiederholte Anfragen von derselben IP-Adresse lösen Sperren aus), Browser-Fingerprinting (Headless-Browser sind durch fehlende APIs und zeitliche Anomalien erkennbar) sowie dynamische Klassennamen (CSS-Klassen werden beim Erstellen generiert und ändern sich bei jeder Bereitstellung, wodurch fest codierte Selektoren ohne Vorwarnung unwirksam werden).
Ein einfacher Abruf liefert Navigation und Metadaten, aber keine Hotelauflistungen. Diese Lücke ist der Grund, warum Sie entweder einen Headless-Browser oder eine Scraping-API benötigen.
Die Wahl Ihres Ansatzes: DIY-Headless-Browser vs. Scraping-API
Der DIY-Weg bietet Ihnen maximale Flexibilität, erfordert jedoch, dass Sie einen Headless-Browser einrichten, einen Proxy-Pool verwalten und die Umgebung bei Änderungen der Browserversionen pflegen. Eine Scraping-API abstrahiert all das: Sie senden eine Anfrage mit Ihrer Ziel-URL und Extraktionsregeln; die API kümmert sich um das Rendering, die Proxy-Rotation und Wiederholungsversuche.
Für die meisten Expedia-Scraping-Anwendungsfälle – Preisüberwachung, regelmäßige Datenabfragen, Recherche – ist der API-Ansatz schneller zu implementieren und auf lange Sicht kostengünstiger zu warten. Sie vermeiden den Aufwand, Browser-Binärdateien auf dem neuesten Stand zu halten, zuverlässige Residential-Proxys zu beschaffen und umgebungsspezifische Rendering-Fehler zu beheben. Der Nachteil ist, dass Sie von einem externen Dienst abhängig sind; prüfen Sie daher Verfügbarkeitsgarantien und Preisstufen, bevor Sie sich für einen der beiden Wege entscheiden.
Umgebungs-Setup und Voraussetzungen
Sie benötigen Python 3.8 oder höher (überprüfen Sie dies mit `python --version`). Installieren Sie die erforderlichen Bibliotheken:
pip install webscrapingapi pandas
webscrapingapi ist der offizielle Python-Client für WebScrapingAPI – er umschließt die HTTP-Anforderungsschicht und übernimmt die Authentifizierung. pandas übernimmt die Datenbereinigung und den CSV-Export.
Rufen Sie Ihren API-Schlüssel über das WebScrapingAPI-Dashboard ab und speichern Sie ihn als Umgebungsvariable, anstatt ihn fest in Ihr Skript einzubinden:
export WSAPI_KEY="your_api_key_here"
Laden Sie ihn dann in Python mit os.environ.get("WSAPI_KEY"). Speichern Sie Ihre Skriptdatei (z. B. expedia.py) in einem eigenen Projektordner, damit relative Pfade für den CSV-Export bei allen Durchläufen konsistent funktionieren. Das in Python integrierte os-Modul ist alles, was Sie benötigen – es ist keine zusätzliche Installation erforderlich. Eine umfassendere Einführung in Python-basierte Scraping-Muster finden Sie in unserem Leitfaden zum Web-Scraping mit Python.
So identifizieren Sie die richtigen CSS-Selektoren auf Expedia
Dies ist der Schritt, den die meisten Tutorials überspringen. Hier ist eine konkrete Anleitung für DevTools.
- Öffnen Sie eine Expedia-Suchseite und lassen Sie sie vollständig laden.
- Klicken Sie mit der rechten Maustaste auf eine Hotelkarte → „Inspect“, um DevTools zu öffnen, wobei das Element markiert ist.
- Identifizieren Sie den Container der Eintragskarte – das sich wiederholende <div> oder <article>, das jedes Hotelergebnis umschließt. Dies ist Ihr Root-Selektor; er sollte einmal pro Eintrag erscheinen.
- Tief in die untergeordneten Elemente einsteigen – finde die Elemente, die den Hotelnamen, den Preis, die Bewertung und die Anzahl der Bewertungen enthalten. Klicke mit der rechten Maustaste auf jedes Element → „Kopieren > Selektor kopieren“.
- Überprüfen Sie die Eindeutigkeit – führen Sie document.querySelectorAll("YOUR_SELECTOR") in der DevTools-Konsole aus und vergewissern Sie sich, dass die Anzahl mit der Anzahl der Hotelkarten übereinstimmt.
- Verwenden Sie relative Selektoren – untergeordnete Selektoren sollten relativ zum Karten-Container sein, nicht absolut vom Dokument-Root aus.
Wichtig: CSS-Klassennamen auf Expedia werden dynamisch generiert und ändern sich mit den Website-Bereitstellungen. Überprüfen Sie Selektoren vor einem Produktionslauf immer anhand einer Live-Seite. Unser CSS-Selektor-Spickzettel behandelt die Selektorsyntax und -spezifität im Detail.
Erstellen des Expedia-Hotel-Such-Scrapers
Das Herzstück des Scrapers sind zwei Wörterbücher – extract_rules und js_scenario –, die als Parameter an den API-Client übergeben werden. Zusammen teilen sie der API mit, was extrahiert werden soll und wie die Seite vor Beginn der Extraktion gerendert werden muss. Die korrekte Einrichtung dieser beiden Objekte ist der wichtigste Schritt im gesamten Python-Workflow für das Expedia-Scraping, da jedes nachfolgende Ergebnis davon abhängt.
Definition von Extraktionsregeln und JS-Rendering-Anweisungen
extract_rules teilt der API mit, welche CSS-Selektoren verwendet werden sollen und was zurückgegeben werden soll. js_scenario liefert Anweisungen an den integrierten Headless-Browser: wait hält die Ausführung für eine bestimmte Anzahl von Millisekunden an; evaluate führt benutzerdefiniertes JavaScript im Seitenkontext aus (zum Scrollen, Klicken usw.).
import os, json
import pandas as pd
import webscrapingapi
API_KEY = os.environ.get("WSAPI_KEY")
client = webscrapingapi.WebScrapingAPIClient(API_KEY)
# Verify these selectors against a live Expedia page before use
CARD_SELECTOR = "[data-stid='lodging-card-responsive']"
extract_rules = {
"hotels": {
"selector": CARD_SELECTOR,
"type": "list",
"output": {
"name": {"selector": "[data-stid='content-hotel-title']", "output": "text"},
"price": {"selector": "[data-stid='price-summary']", "output": "text"},
"rating": {"selector": ".uitk-rating-medium", "output": "text"},
"reviews": {"selector": "[data-stid='reviews-summary']", "output": "text"},
"location": {"selector": "[data-stid='content-hotel-neighborhood']", "output": "text"},
}
}
}
# Wait 2 s → scroll to bottom → wait 2 s to trigger lazy-loaded cards
js_scenario = {"instructions": [
{"wait": 2000},
{"evaluate": "window.scrollTo(0, document.body.scrollHeight)"},
{"wait": 2000}
]}
Das zweistufige „wait“-Muster – Pause vor dem Scrollen, dann erneut Pause danach – ist bewusst gewählt. Expedia nutzt JavaScript-Rendering, um Hotelkarten verzögert zu laden, während sich der Viewport auf der Seite nach unten bewegt. Das Überspringen einer der beiden „wait“-Anweisungen birgt das Risiko, eine unvollständige Liste von Unterkünften zurückzugeben, insbesondere bei langsameren Verbindungen oder wenn das Reiseziel viele Ergebnisse liefert.
Durchführen der API-Anfrage und Verarbeiten der Antworten
Wichtige Parameter: „wait_for“ wartet, bis ein CSS-Selektor erscheint, bevor er extrahiert; „country_code“ legt das Proxy-Ausgangsland für die Preisanpassung fest; „premium_proxy“ aktiviert die Rotation von Residential-Proxys.
def scrape_expedia_hotels(destination, check_in, check_out, page=1):
q = destination.replace(" ", "+")
url = (f"https://www.expedia.com/Hotel-Search"
f"?destination={q}&startDate={check_in}&endDate={check_out}&page={page}")
try:
response = client.get(url, params={
"wait_for": CARD_SELECTOR,
"extract_rules": json.dumps(extract_rules),
"js_scenario": json.dumps(js_scenario),
"country_code": "us",
"premium_proxy": "true",
})
except Exception as e:
print(f"Request failed: {e}"); return []
if response.status_code == 401:
print("Invalid API key."); return []
if response.status_code == 500:
print(f"HTTP 500 on page {page} — retry with backoff."); return []
if response.status_code != 200:
print(f"Unexpected status {response.status_code}."); return []
try:
hotels = response.json().get("hotels", [])
except ValueError:
return []
if not hotels:
print(f"No results on page {page}. CSS selectors may have drifted.")
return hotels
Eine leere Hotelliste mit einem 200-Status bedeutet fast immer, dass sich Ihre CSS-Selektoren verschoben haben. Ein HTTP 500 von Expedia ist oft vorübergehend – erstellen Sie eine Wiederholungslogik mit exponentiellem Backoff an der Aufrufstelle. Beachten Sie, dass der Parameter „page“ bereits durch die Funktionssignatur geführt wird, was es einfach macht, diese Funktion innerhalb einer Paginierungsschleife im nächsten Abschnitt aufzurufen.
Scraping mehrerer Seiten mit Hotelergebnissen
Expedia verwendet einen vorhersehbaren Seitenabfrageparameter, was die Paginierung vereinfacht. Die folgende Schleife wird so lange wiederholt, bis sie einen leeren Ergebnissatz liefert oder das Seitenlimit erreicht:
import time
def scrape_all_pages(destination, check_in, check_out, max_pages=5, delay=3):
all_hotels = []
for page in range(1, max_pages + 1):
hotels = scrape_expedia_hotels(destination, check_in, check_out, page=page)
if not hotels:
print(f"No results on page {page}. Stopping."); break
all_hotels.extend(hotels)
print(f"Page {page}: {len(hotels)} hotels (total: {len(all_hotels)})")
if page < max_pages:
time.sleep(delay) # Respect rate limits
return all_hotels
results = scrape_all_pages("Rome, Italy", "2026-10-05", "2026-10-10", max_pages=5, delay=3)
Der Verzögerungsparameter ist wichtig. Schnell aufeinanderfolgende Anfragen lösen zuverlässig IP-Sperren aus. Eine Pause von 3 Sekunden ist ein vernünftiger Mindestwert; bei größeren Durchläufen sollten Sie innerhalb eines Bereichs von 2–5 Sekunden randomisieren, um vorhersehbare Zeitmuster zu vermeiden.
Die Suchergebnisse von Expedia variieren je nach Reiseziel und Datumsbereich in ihrer Tiefe. Anstatt von einer festen Seitenanzahl auszugehen, sorgt die Frühbeendigungsbedingung der Schleife (if not hotels: break) für eine saubere Beendigung – wenn die API eine leere Liste zurückgibt, haben Sie das Ende der Ergebnisse erreicht.
Bereinigen und Exportieren von Daten in CSV
Der Rohtext muss vor dem Export bereinigt werden – Preise, Bewertungen und die Anzahl der Bewertungen werden als typlose Zeichenfolgen geliefert. Normalisieren Sie diese zunächst:
import re
def clean_price(raw):
if not raw: return None
try: return float(re.sub(r"[^\d.]", "", raw.split()[0]))
except ValueError: return None
def clean_rating(raw):
if not raw: return None
m = re.search(r"(\d+\.?\d*)", raw)
return float(m.group(1)) if m else None
def clean_review_count(raw):
if not raw: return None
d = re.sub(r"[^\d]", "", raw)
return int(d) if d else None
def clean_and_export(hotels, filename="expedia_hotels.csv"):
df = pd.DataFrame([{
"name": h.get("name", "").strip(),
"price_usd": clean_price(h.get("price")),
"rating": clean_rating(h.get("rating")),
"review_count": clean_review_count(h.get("reviews")),
"location": h.get("location", "").strip(),
} for h in hotels])
df.dropna(subset=["name"], inplace=True)
df.to_csv(filename, index=False, encoding="utf-8")
print(f"Exported {len(df)} hotels to {filename}")
return df
df = clean_and_export(results)
Die CSV-Spalten sind typisiert – price_usd (float), rating (float), review_count (int) – und somit ohne manuelle Nachbearbeitung für die Analyse bereit.
Vollständige Skript-Referenz
Alle Funktionen (fetch, scrape, to_csv) wurden in den obigen Abschnitten definiert. Fassen Sie sie in einer einzigen Datei namens expedia.py zusammen, setzen Sie Ihre WSAPI_KEY-Umgebungsvariable und starten Sie den vollständigen Lauf mit dem folgenden Einstiegspunkt.
if __name__ == "__main__":
to_csv(scrape("Rome, Italy", "2026-10-05", "2026-10-10"))
Führen Sie das Skript mit python expedia.py aus. Die Ergebnisse werden in die Datei expedia_hotels.csv in Ihrem Arbeitsverzeichnis geschrieben, bereinigt und bereit für die sofortige Analyse.
Wartung Ihres Scrapers, wenn Expedia sein Layout ändert
Einer der häufigsten Gründe, warum ein Expedia-Scraper nicht mehr funktioniert, ist Selector-Drift – Expedia aktualisiert regelmäßig sein Frontend, Klassennamen ändern sich, Elementhierarchien verschieben sich und Selektoren, die letzten Monat noch funktionierten, liefern plötzlich keine Daten mehr.
So erkennen Sie Selektor-Drift: Ihr Scraper läuft ohne Fehler, gibt aber eine leere Liste zurück. In allen bereinigten Feldern erscheinen gleichzeitig „None“-Werte. Dies sind zuverlässige Anzeichen dafür, dass sich die Selektoren geändert haben.
Der Workflow zur Neidentifizierung:
- Öffnen Sie Expedia in einem Browser und führen Sie eine neue Suche durch.
- Klicken Sie mit der rechten Maustaste auf eine Hotelkarte → „Inspect“.
- Vergleichen Sie das aktuelle DOM mit Ihren „extract_rules“-Selektoren. Suchen Sie nach dem gleichen semantischen Element (Überschrift des Hotelnamens, Preis-Container), auch wenn sich die Klassennamen geändert haben.
- Aktualisieren Sie CARD_SELECTOR und die untergeordneten Selektoren und führen Sie dann einen Ein-Seiten-Test durch, bevor Sie die vollständige Schleife wieder aktivieren.
Leichte Überwachung: Planen Sie einen täglichen Canary-Lauf für ein festes Ziel ein. Lösen Sie bei null Ergebnissen eine Warnung aus, um noch am selben Tag Einblick in Selektor-Abweichungen zu erhalten. Weitere Informationen darüber, wie JavaScript-lastige Websites die Selektor-Stabilität beeinflussen, finden Sie in unserem Leitfaden zu den Auswirkungen von JavaScript auf das Web-Scraping.
Skalierung und Best Practices
- Drosseln Sie die Anfragen. Eine Wartezeit von 3–5 Sekunden zwischen den Seiten ist das Minimum; variieren Sie die Verzögerung, um vorhersehbare Zeitmuster zu vermeiden.
- Implementieren Sie einen exponentiellen Backoff. Verdoppeln Sie bei HTTP-500- oder 429-Antworten die Verzögerung bei jedem erneuten Versuch (5 s, 10 s, 20 s).
- Wechseln Sie den Ländercode. Passen Sie das Ausgangsland an Ihren Zielmarkt an, um eine genaue Preislokalisierung zu gewährleisten.
- Planen Sie wiederkehrende Durchläufe. Verwenden Sie Cron, Airflow oder eine Cloud-Funktion für die Preisüberwachung. Speichern Sie die Ergebnisse mit Zeitstempeln, um Änderungen im Laufe der Zeit zu verfolgen.
- Protokollieren Sie die Statuscodes und Ergebniszahlen pro Seite. Wenn etwas nicht funktioniert, möchten Sie genau wissen, welche Seite und welches Ziel den Fehler ausgelöst haben.
Weitere Informationen zur Vermeidung von IP-Sperren in großem Maßstab finden Sie in unserem Leitfaden zum Beseitigen von IP-Sperren beim Web-Scraping.
Wichtige Erkenntnisse
- JavaScript-Rendering ist für Expedia unverzichtbar. Eine statische HTTP-Anfrage liefert keine Hotellisten – Sie benötigen einen Headless-Browser oder eine Scraping-API, die JS für Sie rendert.
- CSS-Selektoren ändern sich. Expedia aktualisiert sein Frontend regelmäßig. Integrieren Sie die Erkennung von Selektoränderungen in Ihre Pipeline und lernen Sie, wie Sie Selektoren mit DevTools neu identifizieren können, wenn sie nicht mehr funktionieren.
- Die Paginierung erfordert eine Schleife. Verwenden Sie den Seitenabfrageparameter von Expedia und brechen Sie ab, wenn Sie einen leeren Ergebnissatz erhalten – gehen Sie nicht von einer festen Seitenanzahl aus.
- Bereinigen Sie Ihre Daten vor dem Export. Entfernen Sie Währungssymbole, analysieren Sie numerische Bewertungen und konvertieren Sie die Anzahl der Bewertungen bei der Extraktion in Ganzzahlen.
- Ratenbegrenzung und Drosselung. Bewusste Verzögerungen zwischen Anfragen sind sowohl ethisch korrekt als auch praktisch notwendig, um Sperren zu vermeiden.
FAQ
Wie erkenne ich, wenn mein Expedia-Scraper aufgrund einer Änderung der HTML-Struktur nicht mehr funktioniert?
Das deutlichste Anzeichen ist eine leere Ergebnisliste – der API-Aufruf ist erfolgreich (HTTP 200), gibt aber null Hoteleinträge zurück. Ein sekundäres Anzeichen sind None-Werte in allen bereinigten Feldern. Richten Sie einen täglichen Canary-Lauf für ein festes Ziel ein und lassen Sie sich bei null Ergebnissen benachrichtigen.
Was ist der Unterschied zwischen dem Scraping einer Expedia-Suchergebnisseite und einer Hotel-Detailseite?
Eine Suchergebnisseite liefert zusammenfassende Daten – Name, Preis, Bewertung, Lage – in einer paginierten Liste. Eine Hotel-Detailseite enthält umfangreichere Daten zu einer einzelnen Unterkunft: Ausstattungslisten, Aufschlüsselungen nach Zimmertypen, Stornierungsbedingungen und Bewertungstexte. Die Selektoren und Rendering-Anforderungen unterscheiden sich zwischen den beiden.
Wie vermeide ich es, beim Scraping großer Datensätze an die Ratenbegrenzungen von Expedia zu stoßen?
Verwenden Sie zufällige Verzögerungen anstelle fester Intervalle – ein gleichmäßiger Abstand ist für Anti-Bot-Systeme leichter zu erkennen. Verteilen Sie die Listen mit Reisezielen über mehrere Stunden oder Tage und wenden Sie bei 429- und 500-Antworten einen exponentiellen Backoff an.
Kann ich Expedia-Bewertungen und -Bewertungen zusammen mit Preisdaten in einer einzigen Anfrage scrapen?
Ja, wenn die Bewertungsnote und die Anzahl der Bewertungen auf der Suchergebnisseite angezeigt werden, fügen Sie Selektoren für beide Felder zu Ihrem „extract_rules“-Wörterbuch hinzu. Der vollständige Bewertungstext befindet sich auf der Hotel-Detailseite und erfordert eine separate Anfrage.
Fazit
Das Scrapen von Expedia-Hoteldaten in Python ist möglich, erfordert jedoch mehr als eine einfache HTTP-Anfrage. Sie benötigen JavaScript-Rendering, um die tatsächlichen Einträge anzuzeigen, eine zuverlässige Proxy-Rotation, um IP-Sperren zu vermeiden, sowie eine klare Strategie zur Identifizierung und Pflege von CSS-Selektoren, da sich das Frontend von Expedia weiterentwickelt.
Der in diesem Leitfaden beschriebene Ansatz – die Verwendung einer Scraping-API zur Verwaltung der Infrastrukturebene in Kombination mit expliziten „extract_rules“- und „js_scenario“-Parametern – führt schneller zu einem funktionierenden Scraper als die Einrichtung und Wartung eines lokalen Headless-Browser-Stacks. Die Paginierungsschleife, die Funktionen zur Datenbereinigung und die Strategie zur Überwachung von Selektor-Drift machen das Ergebnis produktionsreif und nicht nur zu einem Proof of Concept.
Wenn Sie den Infrastruktur-Overhead komplett umgehen möchten, übernimmt die Scraper-API von WebScrapingAPI das JavaScript-Rendering, die Proxy-Rotation und das Lösen von CAPTCHAs hinter einem einzigen Endpunkt – so können Sie sich auf die Daten konzentrieren, statt auf die technische Umsetzung. Entdecken Sie unsere Anwendungsfälle für das Scraping im Reise- und Gastgewerbe, um weitere Muster für die OTA-Datenerfassung zu finden, oder lesen Sie unsere verwandten Leitfäden zum Scraping von Booking.com und zum Scraping von Airbnb-Inseraten.




