当前位置:首页 > 汽车 > 正文

用Go语言折腾CX365飞机座位图,从视频到代码的实践笔记

  • 汽车
  • 2026-09-02 09:11:46
  • 64
摘要: 为什么突然对CX365飞机座位图感兴趣?前几天刷视频,刷到一条国泰航空CX365航班的飞行Vlog,评论区吵翻了天——有人说这趟...

为什么突然对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/httpencoding/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识别屏幕上的座位号倒是条路子),不过那些都得等周末有空再折腾了,毕竟写代码归写代码,真正坐飞机时,靠窗还是靠过道,还是得看当天的缘分和登机口排队速度。

用Go语言折腾CX365飞机座位图,从视频到代码的实践笔记