本地优先的中国交通联合卡(T-Union)与日本 FeliCa(Suica / PASMO)交通档案、分析与地图应用。
一款 Windows 桌面工具(PyQt6):把交通卡里的余额、交易和行程读出来,长期本地归档, 并在内嵌地图上可视化你的通勤足迹——数据全部留在本机。
版本:v0.3 | 平台:Windows x64 | Python 3.12 | 界面语言:中文
仪表盘 —— 总趋数 / 里程 / 花费 / 站点、月度趋势、最常去站点、中日国别分布:
行程地图 —— 在真实铁路网上高亮每段行程,支持高德 / OSM 双底图与终端风格 CRT 效果:
- 读卡(核心已冻结)
- 中国交通联合卡:通过 PC/SC 读取余额、卡号、交易与行程。
- 日本 Suica / PASMO:使用 64 位 Sony
felica.dll读取 IDm、余额与历史(含 Apple Pay 卡)。 - 同卡按 IDm / 卡号累计,新记录合并、旧记录去重。
- 数据档案(v0.3):SQLite 长期归档、每日滚动备份、撤销最近一次读取、SQLite / JSON 导入导出。
- 连续采集:贴卡即读、自动合并、等待换卡,配声音与托盘通知。
- 档案 LAB:数据质量修复、路线频次、通勤候选、交通日历、铁路网络完成度, 以及“每次行程 / 唯一区间 / 频次热度”三种地图模式与持久化路线几何缓存。
- 导出与离线:交通年鉴 HTML、DPAPI 加密备份、离线地图缓存包。
- 可扩展:后处理插件、安全诊断、冻结核心完整性校验。
详细的档案 LAB、连续采集、插件与便携模式说明见文末「深入说明」。
需要 Python 3.12(64 位) 和 一台 PC/SC 读卡器(如 Sony PaSoRi RC-S380 作者目前只测试过这个)。
# 1. 克隆
git clone https://github.com/zheznanohana/NekoCardReader.git
cd NekoCardReader
# 2. 安装依赖
py -3.12 -m pip install -r requirements.txt
# 3.(可选,日本 FeliCa 才需要)放入 Sony felica.dll
# 从本机 Sony FeliCa Library 拷到 felica_runtime\felica.dll
# 4. 运行
py -3.12 main.py没有读卡器也可以先看界面:程序在无卡时会用内置 mock 数据渲染示例。
约 45 个 Python 模块,按「读卡核心 → 解码字典 → 数据档案 → 分析/地图 → UI」分层。
核心约束:读卡核心冻结且与上层完全解耦——分析、地图、UI 只消费已解析的 Transaction,
永不触碰卡片 I/O。完整分层图、模块职责表与设计决策见 ARCHITECTURE.md。
| 层 | 代表模块 | 职责 |
|---|---|---|
| UI (PyQt6) | main.py · archive_widget.py · web_map.py |
主窗口、档案 LAB、Leaflet 地图 |
| 读卡核心 | card_reader.py · felica64_reader.py · pboc_reader.py |
中/日读卡,进程锁串行 |
| 解码字典 | cn_lines/cn_coords/cn_trips · station_db · jp_network |
站码/坐标/换乘/铁路网 |
| 数据档案 | history_store.py · data_portability.py |
SQLite 档案、备份、DPAPI |
| 分析/导出 | trip_analytics.py · yearbook_export.py · plugin_registry.py |
纯分析、年鉴、插件沙箱 |
| 地图/几何 | map_pipeline.py · rail_route/rail_geom · offline_maps |
后台路由、铁轨几何、离线包 |
读卡器 → card_reader → felica64/pboc_reader → felica_suica/cn_trips
→ history_store(合并去重·SQLite·备份) → trip_analytics/map_pipeline(后台线程) → UI
设计亮点:读卡核心以 SHA-256 冻结防回归;读卡与分析彻底解耦(分析层可离线单测、可入后台线程); 单一读卡器进程锁并发安全;地图路由可取消 + 持久化缓存;本地优先零服务器;插件异常沙箱隔离。
- 数据默认全部留在本地:历史库
history_v3.sqlite3、backups/与个人足迹不会进入 Git, 也不会上传到任何服务器。仓库里看不到作者的历史,你的历史同样只在你自己机器上。 - 联网仅用于:下载线路 / 站点数据、地图瓦片、汇率——均可缓存到本地后离线使用。
- 冻结的读卡核心只做读取,不改写卡片。
稳定基线保存在 Git 标签 v0.2。v0.3 遵守「冻结读卡核心」原则,下列文件必须与 v0.2 的
SHA-256 一致(清单 .reader-core-v0.2.sha256):
felica64_reader.py · felica_suica.py · pboc_reader.py · card_reader.py · felica_reader.py
档案 LAB 的安全诊断不会打开读卡器。
python -m unittest discover -s tests -v覆盖 SQLite 迁移、累计去重、扫描撤销、站点修正、路线缓存、备份恢复、DPAPI、连续采集所依赖的 分析逻辑、年鉴、离线地图包与插件隔离。
- 首次运行将
history_v2.json无损迁移为history_v3.sqlite3;迁移前文件保留为history_v2.json.migrated-v0.3.bak。 - 每次读取保存解析快照、解析器版本、读到数量与新增数量。
raw_blocks表与archive_raw_blocks()接口已就位;冻结读卡层当前未暴露原始字节, 因此暂时只保存完整解析快照。- 每日滚动备份,支持撤销最近一次读取、SQLite / JSON 导出与恢复前自动备份。
在刷卡页勾选「连续采集」后开始:等待卡片 → 读取并合并新增 → 等待当前卡片移开 → 自动等待下一张。 同卡未移开不会重复写入;成功与失败会用系统提示音及托盘通知。
- 数据质量与未知站点修复(本地候选补全,修正永久覆盖后续扫描结果)。
- 路线频次、通勤候选、交通日历与日本铁路网络完成度。
- 地图「每次行程 / 唯一区间 / 频次热度」三种模式;路线几何持久化缓存,相同区间不重复计算 OSM 路由。
- 地图前处理在独立 Qt 线程执行;OSM 最短路与站序兜底并行,切卡时自动取消 / 丢弃旧任务。
- 历史表按 200 行分批填充,统计图与档案子页按需渲染,避免隐藏页面抢占主线程。
- 交通年鉴 HTML、DPAPI 加密备份、离线地图缓存包;安全诊断、冻结核心完整性校验、后处理插件管理。
插件目录:%LOCALAPPDATA%\NekoCardReader\plugins(便携模式为 data\plugins)。
PLUGIN_NAME = "example"
PLUGIN_VERSION = "1"
def postprocess(transactions, context):
# 仅处理已经解析完成的 Transaction; 不进入读卡核心。
return transactions插件异常会被隔离并显示在诊断页,不会中断读卡。

