ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Fli 底层原理:如何从 AF_initDataCallback 数据块中解析 Google Flights 页面数据(完整指南)

Fli 底层原理:如何从 AF_initDataCallback 数据块中解析 Google Flights 页面数据(完整指南) Fli 底层原理如何从 AF_initDataCallback 数据块中解析 Google Flights 页面数据完整指南【免费下载链接】fliGoogle Flights MCP, CLI and Python Library项目地址: https://gitcode.com/gh_mirrors/fli2/fliFli是一个开源的 Google Flights 搜索工具提供 Python 库、CLI 和 MCP Server 三种使用方式。它的核心能力是绕过 HTML 爬虫直接解析 Google Flights 页面内嵌的AF_initDataCallback数据块ds:1payload把航班价格、时刻、机型等原始数据还原成结构化对象。本文带你完整走一遍这条解析链路 为什么不再直接调用 Google 的 RPC 接口Google Flights 背后有一个未公开的FlightsFrontendService服务GetShoppingResults、GetCalendarGraph等 RPC 端点早期工具直接 POST 到它拿数据。但自 2026-08 起这些端点要求携带一个x-goog-batchexecute-bgr请求头它只能由页面自身的 JavaScript 动态生成且签名与请求体严格绑定——任何普通 HTTP 客户端都会被拒返回 HTTP 200 加一个空的wrb.fr错误行gRPC error 13。Fli 的应对方案改走公开搜索页google.com/travel/flights。该页面把同样的航班结果内联在页面的AF_initDataCallback脚本块中key 为ds:1其中data[2]和data[3]就是原来 RPC 返回的航班行——于是旧的解析器几乎不用改动。这个决策记录在 fli/search/_tfs.py 的模块注释里。第一步构造 tfs 参数——用 protobuf 描述搜索条件公开搜索页不再接收结构化的 JSON 请求而是通过一个名为tfs的 URL 参数传递搜索条件。tfs是一个base64url 编码的 protobuf 消息字段布局由逆向工程得出例如见 fli/search/_proto.py字段 19行程类型1往返2单程字段 3航段重复内含出发/到达机场、日期、中转上限字段 8乘客类型1成人2儿童3/4两种婴儿票字段 9舱位等级fli/search/_tfs.py 中的build_tfs函数把FlightSearchFilters对象编码成tfs值再拼进 URLhttps://www.google.com/travel/flights?tfsbase64hlenglUScurrUSD值得注意的是多城市行程在此被明确拒绝——页面不为它内联任何航班行硬发请求会静默返回错误结果Fli 宁可直接报错fli/search/_tfs.py#L119-L131。第二步从 HTML 中精准抽取 ds:1 数据块请求返回后是一整页约 2.4MB 的 HTML其中包含多个AF_initDataCallback块地图数据、币种数据等。Fli 需要挑出 key 为ds:1的那一块。核心是三个正则fli/search/_tfs.py#L67-L70_DS_BLOB re.compile(rAF_initDataCallback\((\{.*?\})\);, re.S) _DS_KEY re.compile(rkey:\s*([^])) _DS_DATA re.compile(rdata:(.*?), sideChannel, re.S)extract_payload函数fli/search/_tfs.py#L180-L205逐个匹配脚本块、筛出ds:1、把data字段的 JSON 反序列化返回一个嵌套数组——这正是 RPC 时代同样的结构。仓库里有一份真实的抓取样本可以直观看到这个数据块的形态search_page_jfk_lhr_nonstop_ds1.htmlJFK→LHR 直飞、美元计价的完整 ds:1 载荷。第三步解码——从嵌套数组到 FlightResult 模型ds:1的data[2]/data[3]中每一行都是一条位置式数组数字下标即字段没有字段名。解码器 fli/search/_decoders.py 按固定下标逐层取值例如parse_flight_rowfli/search/_decoders.py#L39-L79下标位置含义row[8]预订 tokendetail[9]总时长分钟detail[2]各航段数组fl[3]/fl[6]出发 / 到达机场fl[20]/fl[21]出发 / 到达时间戳fl[22][1]航班号fl[17]机型fl[12]机上设施稀疏数组电源/视频/Wi-Fi解码后得到结构化的FlightResult价格、货币、时长、经停次数、每段航班的航空公司/航班号/机型/设施/碳排放等全部是强类型对象。解码器刻意不含任何 I/O因此可以对着抓取的 fixture 做确定性单元测试tests/search/test_parse_flights_data.py。第四步容错——拒绝、缺块与重试真实网络环境里Fli 处理三类异常错误信封wrb.fr行第 5 位携带 gRPC 状态码如 3参数无效、13拒绝服务且不是合法正整数就不算拒绝0是 gRPC 的 OK——逻辑见 fli/search/_wire.py#L225-L248。页面缺块大约 1/60 的页面会 200 但唯独没有ds:1块瞬态现象。fetch_payload对此精确重试 3 次、带 0.5s/1.5s 退避fli/search/_tfs.py#L208-L243——只重试这一种情况避免放大硬失败。稀疏乘客组合带儿童/婴儿的行程中Google 会在客户端计价页面内联行数大幅减少甚至为 0。Fli 用_RowCountTracker区分Google 没内联和被用户过滤器滤空前者会给出明确提示而不是空手而归fli/search/flights.py#L82-L113。传输层同样讲究fli/search/client.py 用curl_cffi模拟 Chrome 指纹、全局令牌桶限速 10 请求/秒、指数退避重试 3 次并为 EU 用户的同意拦截页预置 SOCS cookie。解析结果能做什么解析链路之上Fli 暴露三种界面Python APISearchFlights().search(...)、CLIfli flights search和 MCP Server后者可让 Claude 等 AI 助手直接调用search_flights/search_dates工具查航班、找最便宜日期关键文件清单文件职责fli/search/_tfs.py构造tfs参数、抽取ds:1块、页面重试fli/search/_proto.py手写 protobuf 编码器varint / 长度前缀字段fli/search/_decoders.py位置式数组 → 强类型航班模型fli/search/_wire.pywrb.fr多块流式读取与错误信封fli/search/client.py限速、重试、浏览器指纹 HTTP 客户端fli/search/flights.py搜索编排取页 → 解码 → 客户端过滤 → 排序小结Fli 的 Google Flights 数据解析链路 protobuf 编码请求tfs→ 正则定位AF_initDataCallback的ds:1块 → 按下标逐层解码 → 容错重试与过滤。理解这条链路你也能看懂大多数页面内联数据类解析方案的设计取舍。【免费下载链接】fliGoogle Flights MCP, CLI and Python Library项目地址: https://gitcode.com/gh_mirrors/fli2/fli创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表