From a53d49e3a00f99cff51bc49e32def52b5af4e693 Mon Sep 17 00:00:00 2001 From: PinkClaw Date: Sat, 23 May 2026 00:17:56 -0400 Subject: [PATCH] feat: add FlightHub domain skill for flight search automation Field-tested domain skill covering: - Cloudflare anti-bot protection requirements - Direct search URL format (the only reliable approach) - UI form interaction (airport POI autocomplete) - Datepicker blocking investigation (custom click-resistant component) - Results page extraction patterns - Key lessons from extensive field testing The direct URL approach bypasses the unautomatable custom datepicker and works reliably with a real browser session. --- .../domain-skills/flighthub/flights-search.md | 207 ++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 agent-workspace/domain-skills/flighthub/flights-search.md diff --git a/agent-workspace/domain-skills/flighthub/flights-search.md b/agent-workspace/domain-skills/flighthub/flights-search.md new file mode 100644 index 00000000..fba0e670 --- /dev/null +++ b/agent-workspace/domain-skills/flighthub/flights-search.md @@ -0,0 +1,207 @@ +# FlightHub.com — Flight Search Automation + +Field-tested 2026-05-22 using browser-harness + Mac Chrome CDP. +No anti-bot protections encountered beyond standard Cloudflare JS challenge +(handled automatically by a real browser session). + +--- + +## Anti-Bot Protection + +**FlightHub uses Cloudflare.** Key facts: + +- Blocks all non-browser HTTP requests with **403 "Just a moment..."** JS + challenge page — `curl`, `web_extract`, and plain HTTP clients cannot + retrieve any page, including the direct search URL +- The JS challenge requires a real browser environment (JavaScript engine, + proper TLS fingerprint, cookie management) +- **Solution:** Use a real browser (local Chrome via CDP, cloud browser with + residential proxy, or Playwright with stealth) — Cloudflare passes the + challenge without captchas for legitimate residential IPs + +--- + +## Search URL Format + +FlightHub search can be initiated via a **direct URL** — this avoids the +fragile datepicker and airport autocomplete: + +``` +https://www.flighthub.com/flight/search? + seg0_from={ORIGIN}&seg0_to={DEST}& + seg1_to={ORIGIN}&seg1_from={DEST}& + seg0_date={YYYY-MM-DD}&seg1_date={YYYY-MM-DD}& + order_by=cheapest¤cy=cad& + num_adults=1&num_children=0&num_infants=0&num_infants_lap=0& + type=roundtrip&seat_class=Economy +``` + +| Parameter | Description | +|-----------|-------------| +| `seg0_from` | Origin IATA code (e.g., YYZ) | +| `seg0_to` | Destination IATA code (e.g., ICN) | +| `seg1_to` | Return origin (same as seg0_from) | +| `seg1_from` | Return destination (same as seg0_to) | +| `seg0_date` | Outbound departure date (YYYY-MM-DD) | +| `seg1_date` | Return departure date (YYYY-MM-DD) | +| `order_by` | Sort: cheapest, fastest, best | +| `currency` | Currency: usd, cad | +| `num_adults` | Adult passengers | +| `seat_class` | Economy, Premium, Business, First | + +### Example + +``` +https://www.flighthub.com/flight/search? + seg0_from=YYZ&seg0_to=ICN& + seg1_to=YYZ&seg1_from=ICN& + seg0_date=2026-07-03&seg1_date=2026-07-25& + order_by=cheapest¤cy=cad& + num_adults=1&seat_class=Economy +``` + +--- + +## UI Search Flow (when URL approach fails) + +When navigating to `https://www.flighthub.com/` directly, the page has an +SPA flight search form. This form is **automation-hostile** due to the +custom datepicker component, but the airport POI autocomplete works. + +### Step 1: Airport Autocomplete + +The departure and destination inputs are `#seg0_from_display` and +`#seg0_to_display`. `fill_input()` with real CDP keyboard events works: + +```python +fill_input("#seg0_from_display", "YYZ") +time.sleep(2) +press_key("Tab") # dismiss POI dropdown +fill_input("#seg0_to_display", "ICN") +time.sleep(2) +press_key("Tab") +``` + +**Gotcha:** The departure POI dropdown may block the destination input. +After filling departure, press Tab/Enter before filling destination. + +### Step 2: Datepicker (FAILS — custom click-resistant component) + +FlightHub uses a **custom JavaScript datepicker** (not `react-date-range` +as initially suspected). Standard click methods do NOT register: + +| Method | Result | +|--------|--------| +| `element.click()` (JS) | ❌ No response | +| CDP `Input.dispatchMouseEvent` via `click_at_xy()` | ❌ No response | +| MouseEvent dispatch (`mousedown` + `mouseup` + `click`) | ❌ No response | +| `fill_input()` on date fields | ❌ No date input exists | + +**Status: NOT automatable through the datepicker.** If a direct URL +approach exists (see above), use it instead. The datepicker behavior is +specific to FlightHub's implementation and was confirmed with screenshot +verification after each attempted click method. + +### Step 3: Search Button + +Selector: `.home-search-form-submit.search-form-submit.flights.fh` + +This is a `
`, not a `