feat: trip.com Scanner hinzufügen (Premium Economy, gut für Asia-IPs)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
5b5cf38bd6
commit
d4a94465b7
1 changed files with 63 additions and 0 deletions
|
|
@ -8,6 +8,7 @@ def scrape(scanner, von, nach, tage=30):
|
||||||
"google_flights": scrape_google_flights,
|
"google_flights": scrape_google_flights,
|
||||||
"kayak": scrape_kayak,
|
"kayak": scrape_kayak,
|
||||||
"skyscanner": scrape_skyscanner,
|
"skyscanner": scrape_skyscanner,
|
||||||
|
"trip": scrape_trip,
|
||||||
}
|
}
|
||||||
fn = dispatcher.get(scanner)
|
fn = dispatcher.get(scanner)
|
||||||
if not fn:
|
if not fn:
|
||||||
|
|
@ -187,3 +188,65 @@ def scrape_skyscanner(von, nach, tage=30):
|
||||||
"""Skyscanner hat starken Bot-Schutz — für jetzt übersprungen."""
|
"""Skyscanner hat starken Bot-Schutz — für jetzt übersprungen."""
|
||||||
print("[SS] Skyscanner übersprungen (Bot-Detection)")
|
print("[SS] Skyscanner übersprungen (Bot-Detection)")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def scrape_trip(von, nach, tage=30):
|
||||||
|
"""trip.com — gut von Asia-IPs, oft günstigere Asien-Preise."""
|
||||||
|
abflug = (datetime.now() + timedelta(days=tage)).strftime("%Y%m%d")
|
||||||
|
abflug_iso = (datetime.now() + timedelta(days=tage)).strftime("%Y-%m-%d")
|
||||||
|
# W = Premium Economy bei trip.com
|
||||||
|
url = (f"https://www.trip.com/flights/{von.lower()}-to-{nach.lower()}/"
|
||||||
|
f"tickets-{von.lower()}-{nach.lower()}/"
|
||||||
|
f"?DDate1={abflug}&class=W&curr=EUR")
|
||||||
|
|
||||||
|
log = []
|
||||||
|
results = []
|
||||||
|
|
||||||
|
with SB(uc=True, headless=True, chromium_arg="--no-sandbox --disable-dev-shm-usage") as sb:
|
||||||
|
sb.open(url)
|
||||||
|
sb.sleep(12)
|
||||||
|
|
||||||
|
title = sb.get_title()
|
||||||
|
body = sb.get_text("body")
|
||||||
|
log.append(f"[TR] title={title[:60]}")
|
||||||
|
log.append(f"[TR] body-länge={len(body)}")
|
||||||
|
|
||||||
|
# Cookie-Banner
|
||||||
|
for sel in ['button[id*="accept"]', 'button[class*="accept"]',
|
||||||
|
'button[aria-label*="Accept"]', '.cookie-accept']:
|
||||||
|
try:
|
||||||
|
sb.click(sel, timeout=2)
|
||||||
|
sb.sleep(2)
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# CSS-Selektoren trip.com
|
||||||
|
for sel in ['.price-box .price', '.flight-price', 'span[class*="price"]',
|
||||||
|
'div[class*="price-num"]', '.price-content span', 'em[class*="price"]']:
|
||||||
|
try:
|
||||||
|
elems = sb.find_elements(sel, timeout=2)
|
||||||
|
if elems:
|
||||||
|
log.append(f"[TR] Selector '{sel}': {len(elems)} Elemente")
|
||||||
|
for e in elems[:10]:
|
||||||
|
p = _parse_preis(e.text)
|
||||||
|
if p:
|
||||||
|
results.append({
|
||||||
|
"scanner": "trip", "preis": p,
|
||||||
|
"waehrung": "EUR", "airline": "",
|
||||||
|
"abflug": abflug_iso, "ankunft": ""
|
||||||
|
})
|
||||||
|
if results:
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Fallback Regex
|
||||||
|
if not results:
|
||||||
|
results = _preise_aus_body(body, "trip", abflug_iso)
|
||||||
|
log.append(f"[TR] Regex-Fallback: {len(results)} Preise")
|
||||||
|
|
||||||
|
log.append(f"[TR] Ergebnis: {[r['preis'] for r in results]}")
|
||||||
|
|
||||||
|
print('\n'.join(log))
|
||||||
|
return results[:10]
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue