ARTICLE DETAIL

资讯详情

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

Python 扫一遍港铁全线:270 次查询里,24% 的站台此刻正有列车进站

Python 扫一遍港铁全线:270 次查询里,24% 的站台此刻正有列车进站 文章目录1. 结论先行2. 环境信息3. 数据与口径码表和 API 说的是两套方言4. 核心代码5. 运行结果195 个站方向的等待分层6. 可视化分层与样本量7. 为什么横截面比单站轮询有信息量8. 踩坑与避坑9. 总结1. 结论先行港铁班次好不好广告说了不算API 说了算。这篇用港铁官方码表 实时到站接口对全网络270 个站方向逐一查询195 个成功返回抓下了一个周五上午的完整横截面24% 的站台此刻正有列车进站下一班 0 分钟市区线港岛/荃湾/观塘的中位等待只有1 分钟而机场快线沿线是3.5 分钟——同一家公司、同一张八达通等待体验差了 3 倍多。这条1 分钟的城市3.5 分钟的机场的分界线就是这篇用 270 次 API 查询画出来的东西。2. 环境信息Python 3.13只用标准库urllib / csv / json / statistics matplotlib零第三方依赖数据源一MTR 官方线路站点码表opendata.mtr.com.hk/data/mtr_lines_and_stations.csv10 条线、273 行、含每站双方向序号数据源二Next Train 实时接口rt.data.gov.hk/v1/transport/mtr/getSchedule.php?line{线}sta{站}零鉴权返回未来 3 班车的到站分钟数 ttnt诚实边界横截面采样约需 40 秒0.15s 间隔 × 270 次非严格同一毫秒75 个站方向无数据终点站折返方向、迪士尼线单站等不参与统计3. 数据与口径码表和 API 说的是两套方言最大的坑在这里先讲清楚。码表 CSV 的方向字段是DTDown Track/UTUp Track按它发查询、再按它取结果270 个响应全部解析失败——因为 API 返回的 JSON 里方向键是DOWN/UP。同一个东西码表和接口用了两套词表中间需要一次{DT: DOWN, UT: UP}的映射。这个坑没有任何文档标注是 270 次 no-data 逼出来的。第二个口径ttntminutes to next train只取valid Y且为数字的行ttnt 0表示列车正在进站——这个占比本身就是班次密度的直观指标。4. 核心代码importcsv,io,json,time,urllib.requestfromcollectionsimportdefaultdict CAThttps://opendata.mtr.com.hk/data/mtr_lines_and_stations.csvAPIhttps://rt.data.gov.hk/v1/transport/mtr/getSchedule.php?line{}sta{}DIR_MAP{DT:DOWN,UT:UP}# catalogue dialect - API dialectdeffetch_wait(line,sta,direction):urlAPI.format(line,sta)djson.loads(urllib.request.urlopen(urllib.request.Request(url,headers{Accept:application/json}),timeout10).read().decode())entryd.get(data,{}).get(f{line}-{sta})ifnotentry:return[]depsentry.get(DIR_MAP.get(direction,direction))or[]return[int(x[ttnt])forxindepsifx.get(valid)Yandstr(x.get(ttnt,)).isdigit()]requrllib.request.Request(CAT,headers{User-Agent:Mozilla/5.0})rowslist(csv.DictReader(io.StringIO(urllib.request.urlopen(req,timeout30).read().decode(utf-8-sig))))LINE_CODES{AEL,EAL,TCL,TML,TKL,ISL,TWL,KTL,SIL,DRL}# 10 urban linesline_waits{}seenset()forrinrows:line,direction,star[Line Code],r[Direction],r[Station Code]key(line,sta,direction)ifkeyinseenorlinenotinLINE_CODES:continueseen.add(key)ttntsfetch_wait(line,sta,direction)ifttnts:line_waits.setdefault(line,[]).append(min(ttnts))time.sleep(0.15)# be polite to the public gateway两处纪律(line, station, direction)三元组去重换乘站在码表里出现多次每次查询 sleep 0.15s公共网关不打.cluster。这段「码表驱动 方言映射 限速扫描」的套路可复用到任何按站发查询的实时接口建议收藏备用。另外提醒一句码表本身也是数据同样要验证——273 行里混着缆线如 AEL 机场快线与重铁若不做LINE_CODES白名单过滤轻铁和缆线的站码发进重铁接口只会白跑。先过滤再发查询270 次才是一次性把全网扫完的准确数字。5. 运行结果195 个站方向的等待分层queried 270 station-directions: ok 195, no-data 75 line n min median max mean Airport Express 8 0 3.5 7 3.6 Tung Chung 14 0 3.5 6 2.7 Disneyland 2 3 3.0 3 3.0 South Island 8 0 3.0 4 2.6 Tseung Kwan O 9 0 3.0 5 2.6 Tuen Ma 46 0 2.0 6 2.5 East Rail 26 0 2.0 4 1.7 Kwun Tong 25 0 1.0 4 1.3 Island 32 0 1.0 4 1.2 Tsuen Wan 25 0 1.0 3 1.1 ttnt0 (train pulling in now): 46/195 (24%)分层一目了然市区三线港岛/荃湾/观塘中位 1 分钟——不用看屏走到站台车就快来了东铁/屯马 2 分钟——新界大动脉的骨干节奏机场快线/东涌线 3.5 分钟——用班距换运距的取舍。24% 的站台 ttnt0意味着随手挑四个站台就有一个正有列车进站。把 75 个无数据的站方向单独看一眼也有价值它们集中在线路两端的折返站和迪士尼线的单站结构——API 对下一班还没排班的方向不返回任何行这与线路停摆完全不同。做实时数据监控时把接口没给和给了但等很久分成两类告警才不会两边乱响。6. 可视化分层与样本量第一张双面板左边每条线的 min–median–max 区间红点为中位右边是采样量屯马线 46 个站方向最大。第二张把均值排成等待体验排行榜绿色 1 分钟档、红色 3.5 分钟档网络均值 2.0 分钟画在同一张图里做基准。这套「横截面快照 分层排行」的组合值得收藏评估任何实时系统先抓一个横截面。7. 为什么横截面比单站轮询有信息量盯一个站的到站屏只能知道下一班几分钟扫全网才能回答结构性问题等待体验的分界线画在哪、谁在被区别对待。机场快线的 3.5 分钟不是班次差——它是低频高容量的定价逻辑屯马线 46 个站方向全部有数据回传说明这条全网最长的线覆盖完整。横截面还能做时间序列同一脚本每天跑三次早高峰/平峰/晚高峰一周就是完整的班次画像——复跑成本低正是这个玩法的好处。唯一的纪律是别并发0.15 秒间隔是实测稳定的节奏270 个请求排队四十秒跑完比压垮公共网关然后被限流便宜得多。8. 踩坑与避坑踩坑后果避开姿势按码表的 DT/UT 取 API 结果270 次查询全部 no-data映射 DT→DOWN / UT→UP无间隔猛发 270 请求公共网关限流随机失败每次 sleep 0.15s异常按站容错换乘站重复查询同站重复计数(line, station, direction) 三元组去重ttnt 字符串直接 int“-” 或空值崩溃validY isdigit 双重过滤把 75 个无数据站当 0 等待统计被稀释无数据单独归类不进分布这张表建议收藏——第一行的方言映射没有任何文档记载纯靠实测对出来。9. 总结270 次查询换一张全网络等待地图市区线 1 分钟、机场线 3.5 分钟、24% 的站台正有车进站。这个玩法最值钱的地方是可复现——脚本每天跑三次横截面就变成时间序列换个城市、换个运营商改一个 URL 和一张码表就能迁移。实时数据的价值不在单次快照在快照可以便宜地重复。代码、码表、方言映射全部可复现——把 LINE_CODES 换成轻铁的一组站码同一个脚本立刻变成轻铁版。数据来自 MTR 官方码表与资料一线通实时网关2026-09-04 快照。本文为原创技术实践数据来自 MTR 官方开放码表与资料一线通实时接口零鉴权快照时点为 2026-09-04 上午横截面非官方班次承诺出行请以车站实时信息为准。
返回列表