跪拜 Guibai
← Back to the summary

Self-Hosted Flight Fare Monitor Pulls Real Data From 6 Platforms and 10 Channels

A self-hosted multi-channel flight price monitor: 6 platforms, 10 channels, collecting real flight details, supporting same-flight cross-source price comparison, price calendar/K-line, and alert notifications. Data stays on your machine, configuration is all in the web UI, Apache-2.0.

Why I built it

I always thought connecting flights were cheaper than direct ones. Then I checked Shanghai→Tokyo on 11/21:

Item Direct Connecting
Flight IJ004 GS7884 / GS7989
Time 17:30→21:30 (3h) 12h45
Price ¥975 ¥1414
Baggage No free checked luggage Includes 1 piece 23kg
Seats left 9 —

Looking only at price, direct ¥975 is ¥439 cheaper than connecting ¥1414; but the direct flight has no checked baggage, while the connecting flight includes one 23kg piece, so the two aren't directly comparable.

Worse, this information isn't on one page: calendar price ¥1005, detail price ¥975; different sources give different prices, baggage, cabin class, and seat availability; PC and App prices can also differ.

To avoid refreshing eight times a day, I wrote a web page that connects 6 platforms and 10 channels into one view. Later I open-sourced it.

Features overview

Console overview (demo data)

Channels and endpoints

Among the 6 platforms, Ctrip, Qunar, Fliggy, and Tongcheng have both web and App endpoints; Zhixing has only App; Tuniu currently only has web (the App won't start on MuMu).

App channels are optional: off by default, enabled only when you need App-exclusive prices or Zhixing. Enabling App channels requires local MuMu (Android, ~15GB, Windows, requires VT); when off, the framework never touches it.

For channel capabilities, the project maintains a matrix of 10 channels × 7 dimensions, each cell tri-state: supported / unsupported / unverified. Unverified is not treated as supported. The dimensions that App channels still lack compared to browser channels are listed separately, not mixed in to gloss over gaps.

Channel capability matrix (10 channels × 7 dimensions)

Technical implementation

Overall pipeline:

scheduler → channel collection (browser / App) → unified schema → SQLite(prices.db)
      → judgment / push / price calendar / K-line / deal radar

Several key points:

  1. Channel adaptation. Each of the 5 browser channels takes the most stable path: Qunar H5, Ctrip international PC/domestic H5, Tongcheng H5, Fliggy SSR, Tuniu HTTP; PC web services that are discontinued fall back to H5. Each channel's login slot is managed separately.
  2. App channels. MuMu Android emulator + adb; WebView results read via uiautomator2, canvas pages via OCR. Login happens on an embedded real phone screen; the login state is packaged into a snapshot and restored before collection; when a snapshot expires, the config page flags it, and it won't pretend to work.
  3. Unified schema. Price, flight number, times, stops, duration, terminal, cabin, aircraft, on-time rate, baggage; both raw rows and parsed rows are retained, and search details do a "parsed ⇄ mirror(raw) ⇄ RAW path" three-way alignment.
  4. Data model. Each scan writes every flight into flight_daily, independent of whether it's watched; watched flights are a subset of the configured route + date detail set. Thin calendar rows (no flight number/times) never trigger alert judgments and don't participate in same-flight price tiers.
  5. Scheduling and rate limiting. Multi-user same-route de-duplication, staggered queries; failures classified separately (login/captcha/soft block/timeout); no captcha bypass, stops and waits for human handling when a captcha or login appears.
  6. UI. A single-page console rendered with pure standard libraries, sub-views for workbench and panel-style configuration; hot-reload of config, mobile-friendly; Docker image includes Chromium and Chinese fonts.

Trend and calendar (demo data)

Test data

I ran a round with the project's active probe: Shanghai→Tokyo, 2026-11-21, collected at 2026-11-04 12:32.

That round pulled 282 real details: Ctrip 163, Tuniu 119; the other 3 sources didn't supply any this round, so they were left blank, no fake samples. Calendar price ¥1005, direct flight detail ¥975—calendar is for picking dates; always click into details before ordering.

Deployment

  1. No Python install: download the platform package from Releases, unzip and run, open http://127.0.0.1:8765 in a browser
  2. Source: pip install -r requirements.txt && python main.py
  3. Docker / NAS:
cp config.example.yaml config.yaml
docker compose up -d

Open http://NAS_IP:8765 in a browser and it's ready. Config, price database, browser session archives, and logs all land on local volumes; container upgrade/rebuild doesn't lose data; image includes Chromium and Chinese fonts, first startup doesn't need to download a kernel.

Known limitations

Feedback

The project is Apache-2.0, fully open source. Run into issues, want new channels/routes, feel free to open an issue or comment; I'll try to fix.

GitHub: https://github.com/dengmeiluan/ticket-monitoring

Prices change; actual order is final. Data in this article comes from real collection at 2026-11-04 12:32, only for explaining the monitoring methodology.