用Go语言折腾CX365飞机座位图,从视频到代码的实践笔记
- 汽车
- 2026-09-02 09:11:46
- 32
为什么突然对CX365飞机座位图感兴趣?
前几天刷视频,刷到一条国泰航空CX365航班的飞行Vlog,评论区吵翻了天——有人说这趟上海浦东飞香港的航班座椅间距感人,有人晒出自己靠窗座位拍到的云海,我盯着那条视频里一闪而过的座位图,突然想:要是能用Go语言写个小工具,把座位图数据和舱位视频信息整合一下,是不是挺酷?
说干就干,但一开始就碰到个麻烦——网上能找到的CX365座位图格式乱七八糟,有PDF、有图片、甚至有Excel表格,更烦人的是,不同航司官网的座位图数据接口完全不一样。
第一步:视频里的座位图,到底藏着什么信息?
那条视频里,博主展示了经济舱第43排靠过道位置的腿部空间,我暂停画面,仔细看了下屏幕上的座位图:
- 左侧是窗(A、K列)
- 中间四列(C、D、G、H)
- 右侧靠窗(B、J列,有时候国泰用B/K组合)
这就是典型的空客A350-1000布局,CX365这条航线,国泰常飞A350-1000,座位图长这样:
| 区域 | 排数范围 | 座位列 | 特点 |
|---|---|---|---|
| 公务舱 | 1-6排 | 1-2-1布局 | 全平躺座椅 |
| 特选经济 | 11-15排 | 2-3-2布局 | 腿部空间加大 |
| 经济舱 | 21-43排 | 3-3-3布局 | 标准间距 |
但视频里没拍全,我只看到第43排附近的情况,这就暴露了第一个问题:纯靠视频截图,获取不了完整座位图数据。
第二步:用Go写代码前,先解决数据源问题
我翻了半天,发现国泰官网有个座位图服务,但接口藏在航班查询页面里,返回的是JSON格式,正好,Go标准库的net/http和encoding/json就能搞定。
写代码套路很简单:
// 伪代码,示意思路
type SeatMap struct {
Flights []Flight `json:"flights"`
}
type Flight struct {
CabinClasses []Cabin `json:"cabin_classes"`
}
func fetchSeatMap(flightNo string) (*SeatMap, error) {
resp, err := http.Get("https://api.cathaypacific.com/seatmap/" + flightNo)
// 解析JSON...
}
但问题来了——官网接口有反爬,而且返回的座位图数据里,每个座位都带一堆属性(是否靠窗、是否紧急出口、是否倾斜受限),直接解析没问题,但要把座位图画出来,还得做坐标映射。
第三步:把座位图转成可视化数据
这一段我想了很久,视频里的座位图是动态渲染的,但静态数据是固定的,我决定写个命令行工具,输出ASCII字符画:
A B C D E F G H J K
21 . . . . . . . . . .
22 . . . . . . . . . .
...
43 . . . . . . . . . .
用Go的strings.Builder拼接字符串,再配合tabwriter对齐列,关键代码长这样:
func drawSeatMap(rows map[int][]Seat) string {
var b strings.Builder
writer := tabwriter.NewWriter(&b, 0, 4, 2, ' ', 0)
for row := 21; row <= 43; row++ {
seats := rows[row]
// 每行输出座位状态,'X'表示已占,'.'表示可选,'E'表示紧急出口
fmt.Fprintf(writer, "%d\t%s\t%s\t%s\n", row,
formatSeats(seats[0:3]), // 左侧窗+中间
formatSeats(seats[3:7]), // 中间四列
formatSeats(seats[7:10])) // 右侧
}
writer.Flush()
return b.String()
}
顺便说一句,紧急出口那排的座位间距通常会大15%左右,视频里博主提到的“伸腿神器”第21排就是,但国泰的紧急出口座位有年龄限制,登机时会被地勤检查。
第四步:视频和座位图的联动逻辑
光有静态图不够,我想把视频里的关键帧和座位图关联起来,比如视频第3分24秒拍到了第28排的窗户视角,那就可以在座位图上标注:
- 第28排A座:视频时间戳 03:24,窗外视野无遮挡
- 第43排J座:视频时间戳 08:07,靠过道,腿部空间正常但座椅底部有金属盒
这需要看视频时手动记录时间戳,但用Go读取视频帧太麻烦(得调ffmpeg库),所以我的方案是让用户提供注释文件,然后生成一个带时间戳的座位图JSON,格式像这样:
{
"flight": "CX365",
"aircraft": "A350-1000",
"notes": [
{"row": 28, "seat": "A", "time": "03:24", "content": "窗外视野无遮挡"},
{"row": 43, "seat": "J", "time": "08:07", "content": "过道座位,储物盒凸起"}
]
}
然后写个函数,根据座位坐标和时间戳,在终端里高亮显示对应的座位,虽然要手动输入,但至少不用反复暂停视频对照截图了。
第五步:踩过的坑和解决办法
坑1:座位号不一定是连续的
国泰A350-1000经济舱,有时候第39排会少一个座位(因为机翼结构),我一开始按固定31行遍历,结果发现有些行只有9个座位,后来改成从JSON数据里动态读取每排的座位列表。
坑2:视频里的座位图是动态渲染的,但静态数据不变
视频里如果镜头移动,座位图上某些位置会显示“已选”状态,但那只是当时查询的座位占用情况,不代表实际航班。真实座位状态只有购票后选座时才准确。
坑3:终端宽度不够
ASCII画的座位图,列多了会换行,我后来改成紧凑模式,删掉两列之间的空格,用分隔符隔开:
21|A B C|D E F G|H J K|
22|. . .|. . . .|. . .|
这样在窄终端里也能完整显示。
最后看看效果
跑完程序后,终端输出大概是这样的:
CX365 座位图 (A350-1000)
=========================
A B C | D E F G | H J K
21 . . . | . . . . | . . . <- 紧急出口,腿部空间大
22 . . . | . . . . | . . .
...
43 . . . | . . . X | . . . <- 第43排J座已被占,视频里博主坐的A座
配合视频备注,就能在起飞前把哪个位置能看到什么景色、哪个位置靠近洗手间(第40排附近)、哪个位置头顶有出风口异响都摸清楚,虽然这工具没法直接替代航司官方选座界面,但至少让我这种爱看飞行视频的人,不用每次开网页选座都要来回切换对比。
下一步,我打算给这个程序加个GUI,把ASCII图换成真正的图形界面,顺便支持从视频里自动提取座位号(用OCR识别屏幕上的座位号倒是条路子),不过那些都得等周末有空再折腾了,毕竟写代码归写代码,真正坐飞机时,靠窗还是靠过道,还是得看当天的缘分和登机口排队速度。
