告别网页抓取:Fli如何逆向Google Flights API实现零爬虫机票搜索
【免费下载链接】fliGoogle Flights MCP, CLI and Python Library项目地址: https://gitcode.com/gh_mirrors/fli2/fli
Fli是一个 Google Flights MCP、CLI 与 Python 库三合一的机票搜索工具:它通过逆向工程直接对接 Google Flights API,实现零爬虫、零 HTML 解析的航班搜索——不启动浏览器、不抓取网页,只需一个标准 HTTP 请求就能拿到结构化机票数据。本文带你拆解它的逆向原理,并用 30 秒跑通第一个搜索。
为什么网页抓取该退役了?
做过机票抓取的朋友都有切身体会:
- 脆弱:Google 换个 CSS 类名、调个 DOM 结构,XPath 选择器就集体失效
- 笨重:浏览器自动化方案要维护一堆无头浏览器进程,慢且占内存
- 低效:解析大段 HTML 只为了抠出几个价格字段
Fli 的思路完全不同——既然 Google Flights 网页本身就是从内部 API 渲染出来的,那直接逆向出这个 API 的通信协议,绕开整个页面去说话。
Fli 零爬虫机票搜索的 4 步逆向原理 🛠️
整个传输层只有几百行代码,集中在 fli/search/ 目录下,流程清晰可复现:
第 1 步:逆向tfsprotobuf 参数
Google Flights 搜索页的 URL 长这样:https://www.google.com/trights?tfs=<一串base64>。这个tfs是一个 protobuf 二进制编码,里面装着行程类型、出发/到达机场、日期、舱位、乘客、中转偏好等全部搜索条件。Fli 用仅 60 行的最小白板协议编码器(fli/search/_proto.py)手工实现了 varint 和 length-delimited 字段编码,把搜索条件序列化成tfs值——完全不需要 protobuf 运行时依赖。
第 2 步:拼接搜索页 URL
fli/search/_tfs.py 中的build_tfs()把过滤器对象编码成tfs参数,page_url()再拼上语言(hl=)、国家(gl=)、货币(curr=)等本地化参数。
第 3 步:从页面中抽取ds:1数据块
Google 的搜索页把完整结果内联在一段AF_initDataCallback({key: 'ds:1', ..., data:[...]})的 JavaScript 回调里。extract_payload()用正则精准定位这个数据块并反序列化成 JSON——这一步拿到的是和内部 RPC 完全相同的结果结构。
第 4 步:解码为类型化模型
fli/search/_decoders.py 按逆向出的字段位置图(行内[2]、[3]是航班列表,价格、航段、中转、排放值各在固定下标)把原始 JSON 解码成FlightResult这类结构清晰的对象,业务代码从此不用碰任何下标魔法。
为什么要走搜索页而不是 RPC?
2026-08 起,Google 给FlightsFrontendService的 RPC 接口加上了只有页面自身 JavaScript 才能生成的x-goog-batchexecute-bgr签名头,普通 HTTP 客户端一律拿到空响应。而公开搜索页没有这道门——结果同样内联在页面里,只是换了tfs参数格式。Fli 顺势切换到这条通道,保持了纯 HTTP 的轻量架构。
30 秒上手:安装与第一次搜索 ⚡
零爬虫架构意味着零额外依赖,一条命令安装:
pip install flightsCLI 一行命令搜索 JFK 到伦敦的商务舱直飞航班:
fli flights JFK LHR 2026-10-25 --class BUSINESS --stops NON_STOP想找最便宜的出行日期?fli dates JFK LHR --from 2026-01-01 --to 2026-02-01即可在日期区间里扫描票价。
Python 库同样简洁,核心模型定义在 fli/models/:
from fli.models import Airport, FlightSearchFilters, FlightSegment, PassengerInfo, SeatType from fli.search import SearchFlights filters = FlightSearchFilters( passenger_info=PassengerInfo(adults=1), flight_segments=[FlightSegment( departure_airport=[[Airport.JFK, 0]], arrival_airport=[[Airport.LAX, 0]], travel_date="2026-12-25", )], seat_type=SeatType.ECONOMY, ) for f in SearchFlights().search(filters) or []: print(f"${f.price} — {f.duration} 分钟 — {f.stops} 次中转")MCP Server:让 AI 助手一句话查机票 🤖
Fli 内置了基于 FastMCP 的 MCP 服务器(fli/mcp/server.py),把search_flights(指定日期搜索)和search_dates(区间找最低价)两个工具暴露给 AI 客户端:
fli-mcp # STDIO 模式,供 Claude Desktop 等客户端使用 fli-mcp-http # HTTP 模式,默认服务在 127.0.0.1:8000/mcp/在 Claude Desktop 配置里登记fli-mcp后,直接用自然语言提问即可:“帮我查 12 月 25 日从纽约 JFK 到洛杉矶的非直飞航班”——AI 会通过 MCP 协议调用底层同一个零爬虫搜索通道。完整配置见 docs/guides/mcp.md。
内置防护:限流、重试与错误分类 🛡️
逆向接口最怕打崩服务方,fli/search/client.py 内置了三重保护:
| 机制 | 实现 |
|---|---|
| 全局限流 | 令牌桶算法,所有线程共享 10 请求/秒预算 |
| 自动重试 | 指数退避,最多 3 次;瞬时空页面(约 1/60 概率)单独再试 |
| 类型化错误 | 超时、连接、证书、HTTP、解析失败各自独立异常类,错误信息直接给出修复建议 |
实用边界:这些限制要知道 📌
- 多城市行程:结果由 Google 客户端侧通过受限 RPC 加载,页面内联不出数据,需分段搜索
- 日期扫描:每天消耗一次页面抓取,单次最多 93 天
- 三个过滤器(
emissions、bags、exclude_basic_economy)无tfs字段,会被丢弃并给出警告 - 更多示例可运行 examples/python/basic_one_way_search.py,TypeScript 移植版在 fli-js/
关键源码地图 📂
| 模块 | 职责 |
|---|---|
| fli/search/_proto.py | 极简 protobuf 编码器,生成tfs令牌 |
| fli/search/_tfs.py | 搜索页传输层:构建 URL、抽取ds:1、客户端过滤 |
| fli/search/_decoders.py | 把原始 JSON 解码为类型化航班模型 |
| fli/search/_wire.py | 线格式分块与协议帧处理 |
| fli/search/client.py | 限流、重试、浏览器指纹模拟的 HTTP 客户端 |
| fli/models/ | 机场、航司枚举与搜索过滤器模型 |
| fli/cli/ | 命令行入口(fli/fli-mcp) |
总结
Fli 证明了逆向工程不需要重型武器:逆向一个tfsprotobuf 参数 + 一段页面内联数据,就能用纯 HTTP打通 Google Flights API,比爬虫方案更快、更稳、更抗 UI 变动。无论你想要 CLI 一行查询、Python 库深度定制,还是让 AI 助手直接查机票,这套零爬虫架构都能直接复用。
【免费下载链接】fliGoogle Flights MCP, CLI and Python Library项目地址: https://gitcode.com/gh_mirrors/fli2/fli
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考