⬇️ 下载最新版 exe / 安装包(不用装 Python)
⚠️ 风险提示(必读)
- 本工具违反 12306 服务条款,使用即承担账号被封、订单被取消的风险。
- 12306 风控会识别高频请求;即使做了指数退避和熔断,也无法保证不被封。
- 官方候补功能是更稳妥、且合规的选择,本程序的候补模式走的就是官方渠道,优先于脚本硬抢。
- 账号密码由使用者自行提供;本程序不存储明文(登录态加密落盘、日志全局脱敏)。
- 本文档不构成法律建议,合规性由使用者自行确认。
一个能直接双击运行的 Windows 桌面程序:界面看板 + 后台抢票引擎 + 可选 Web 面板。 不需要 Docker、不需要 Redis、不需要额外服务。
到 Releases 发布页 下载:
| 文件 | 说明 |
|---|---|
py12306-Setup-vX.Y.Z.exe |
安装版(推荐):中文向导、开始菜单/桌面快捷方式、可卸载 |
py12306-vX.Y.Z-windows-x64.zip |
便携版:解压即用,不写注册表 |
第一次运行未签名的程序会出现 SmartScreen 蓝色提示,点「更多信息 → 仍要运行」即可。
1. 双击「安装环境.bat」 —— 自动创建 .venv 并安装依赖(只需一次)
2. 双击「启动py12306.bat」 —— 打开程序窗口
第一次启动后:把 .env(参考 .env.example)放到数据目录(默认 文档\py12306,
程序「设置」页会显示具体路径),填好账号与任务,再点「开始抢票」。
没有界面/不想用界面时,同一个 app.py 也支持命令行:
python app.py # 启动桌面窗口(默认)
python app.py -t # 自检,退出码 0/1,结果写到 数据目录/logs/selfcheck.txt
python app.py serve # 只启动 Web 面板
python app.py waitlist # 候补模式
python app.py -h # 全部参数参照 host_app 的分层:薄入口 + core(无界面业务层)+ ui(Qt 界面)+ packaging(打包)。
core 里没有任何 Qt/Flask 依赖,所以它能被单独测试、也能被命令行直接复用。
app.py 程序入口(98 行级薄壳)
· 参数分发(GUI / -t / serve / waitlist)
· 崩溃处理器:写 数据目录/logs/崩溃日志_*.txt + 弹窗
· --selfcheck:起来后自动退出,供无人值守验证
core/ 业务层(不 import Qt / Flask)
paths.py 数据目录管理(文档\py12306,可用 PY12306_DATA_DIR 覆盖)
version.py APP_NAME / __version__ 单一来源
logging_setup.py 日志初始化(轮转 + 脱敏 + 崩溃日志)
settings.py 界面可改的设置(settings.json 落盘,含密钥的一律不写)
config.py .env 读取与启动校验(字段错就报错,静默失效是大忌)
uplink.py 上游桥接:账号/任务推给 py12306,状态取回给界面
engine.py 抢票引擎(后台线程,可安全停止)
monitor.py 状态门面:把指标整理成界面要用的 Snapshot
metrics.py 指标库(内存窗口 + SQLite,重启回载)
risk.py 风控熔断器(CLOSED→BACKOFF→OPEN→HALF_OPEN)
timing.py 抖动 / 退化纯函数
integration.py 把熔断与抖动接进上游查询循环
notifier.py 统一告警接口 + 适配器(钉钉/ServerChan/Bark/webhook/console)
redaction.py 日志脱敏
runtime_state.py 登录态 AES-GCM 加密落盘 + 一键清除
waitlist.py 候补模式(官方渠道)
selfcheck.py 自检
cli.py 命令行分发
ui/ Qt 界面(只读 core,不直接碰上游对象)
theme.py 深色主题 + 字体探测
dashboard_widgets.py 状态卡 / 曲线图 / 任务表 / 事件表
main_window.py 主窗口:运行看板 / 风控事件 / 设置
panel_thread.py 在后台线程里起 Web 面板
webpanel/ 可选 Web 面板(Flask 蓝图 + server.py 应用工厂 + 零构建前端)
py12306/ 上游业务代码(登录、下单、乘客、CDN),只做必要的兼容修补
packaging/ PyInstaller spec / 安装包脚本 / EULA / 版本资源 / 图标生成
tests/ 397 个用例(pytest 或 tests/run_all.py 都能跑)
tools/ 仿真数据、桌面截图、锁文件生成、依赖对账(开发辅助)
data/ 上游必需的静态数据(stations.txt 站名表、cdn.txt、图片)
env.py.example 上游旧配置文件格式示例(仅用于对照 WAITLIST/QUERY_JOBS 字段)
requirements.txt 终端用户安装用(全部可从 wheel 安装)
requirements-lock.txt 完全复现开发环境用
requirements-upstream.txt 上游原始清单存档(**不要用它装依赖**,原因见文件头)
没有的东西(重构时删掉了,避免混淆):
Dockerfile / docker-compose.yml(改为本机直接运行)、上游那套 env 示例
(env.docker.py.example / env.slave.py.example,单机模式用不到)、
旧入口 main.py(改成 app.py)、一次性迁移脚本(JWT 修补、图标生成等,已执行完)。
UI 线程 ──QTimer 1 秒──▶ core.monitor ──读──▶ core.metrics(内存窗口 + SQLite)
│ ▲
└──开始/停止──▶ core.engine(后台线程)──写──────┘
│
└─▶ 上游 py12306 查询循环(已接入熔断与自适应抖动)
界面永远不会被网络或抢票速度拖住:所有耗时动作都在引擎线程里,界面只读快照。
- 上游业务逻辑完整保留(登录、下单、乘客、CDN、集群代码都在)。
- 对上游的修补只有四处,且都有回归测试:
@jwt_required→@jwt_required()(Flask-JWT-Extended 4.x 要求调用);- 受保护路由补显式
endpoint=(4.x 不再保留__name__,否则 Web 界面起不来); Web.__init__注册蓝图改为幂等(重建实例不再抛 endpoint 冲突);get_file_modify_time对不存在的配置文件返回 0(纯.env部署时不再崩)。
- 其余全是新增层。上游原本
main.py里那套启动流程(App.run / run_check / User.run / Query.run) 被core/uplink.py+core/engine.py取代,所以那个文件已经删除,不再是重复入口。
| 标签页 | 内容 |
|---|---|
| 运行看板 | 8 张指标卡(每分钟查询、累计查询、有票/成功、风控命中、延迟 p50/p90、熔断中任务、基础间隔、运行时长);查询量/风控/有票分桶柱状图;延迟 p50/p90 折线;任务组合表(熔断状态、连续失败、下次探针、有票率、最近原因) |
| 风控事件 | 退避与熔断事件表(分类/状态/等待秒数/原因)+ 实时日志(读上游日志文件,自动滚动) |
| 设置 | 查询节奏、风控阈值、告警渠道、Web 面板、维护时段开关、登录态清除、环境信息 |
工具栏:开始抢票 / 停止 / 解除全部熔断 / 自检 / 启动 Web 面板 / 打开日志目录。
熔断粒度是「任务 × 日期 × 车站」:撞墙的往往只是一个组合,全局熔断会误伤其它正常组合。
点工具栏「启动 Web 面板」,浏览器会打开 http://127.0.0.1:8010/panel/。
默认只允许本机;要局域网访问需 PANEL_ALLOW_REMOTE=1,建议同时设 PANEL_TOKEN。
面板与桌面看板读的是同一份指标库,两处数据一致。
程序目录只放代码;所有用户数据都在数据目录(默认 文档\py12306):
文档\py12306\
.env 账号、任务、密钥(自己创建,程序不写)
settings.json 界面设置(不含密钥)
logs\ py12306.log、12306.log、崩溃日志、selfcheck.txt
metrics\ metrics.sqlite3(指标库,面板与看板共用)
runtime\user\ 登录态(AES-GCM 加密,0600/ACL 收紧)
要换位置就设 PY12306_DATA_DIR(例如 D:\py12306-data)。
推荐做法:交给 GitHub Actions 云端构建(本地不需要装打包环境):
- 推到
main:自动构建,产物在 Actions 页面的 Artifacts 里可下载(保留 3 天) - 打标签
v*:自动构建并创建 Release,安装包直接挂在发布页上,任何人可下载 - 手动:Actions 页面点 Run workflow
git tag v1.0.1 && git push --tags # 发一个新版本构建流程(见 .github/workflows/build-windows.yml):
读版本号 → 同步到 exe 资源 → 装依赖 → 跑测试 → PyInstaller →
起 exe 跑 --selfcheck 验证可用(失败就中断,不会发出坏包)→
打便携版 zip → Inno Setup 生成中文安装包 → 上传/挂 Release。
本地打包(可选,需要自己装 PyInstaller 与 Inno Setup):
python packaging/sync_version.py # 版本号同步到 exe 资源
.venv\Scripts\pyinstaller packaging\py12306.spec --noconfirm
ISCC /DMyVersion=1.0.0 packaging\installer.iss # 生成安装包相关文件:packaging/py12306.spec(PyInstaller)、packaging/installer.iss(安装包脚本)、
packaging/EULA.txt(安装时展示的许可与风险声明)、packaging/make_icon.py(标准库生成图标)、
packaging/version_info.txt(exe 文件属性)。
打包后仍支持 --selfcheck:无人值守验证 exe 能否正常起来,结果写到
数据目录/logs/selfcheck.txt。
pytest -q --basetemp=.pytest-tmp # 推荐(397 个用例)
python tests/run_all.py # 零依赖方式,不装 pytest 也能跑全部离线:不联网、不连 Redis、不 sleep。界面测试用 QT_QPA_PLATFORM=offscreen,
没有 PySide6 的环境会自动跳过。
覆盖范围:风控分类与熔断状态机、抖动与退避、逐组合独立抖动、日志脱敏(含误伤防护)、 配置校验(字段写错即报错)、登录态加解密与清除、指标库与重启回载、候补状态机、 上游模块逐个 import、上游 Web 路由与 JWT 端到端、桌面窗口搭建与刷新、设置存取与收敛。
- 候补端点未经实测:12306 候补接口无公开文档,路径集中在
core/waitlist.py: DEFAULT_ENDPOINTS,可用WAITLIST_*_URL覆盖。 状态解析刻意保守:识别不出来报 ERROR,绝不猜成成功。 - 没有实盘验证过抢票:本机无法登录真实 12306,所以下单链路只做了代码级兼容修补与单元测试,
第一次真实使用建议先用
python app.py -t自检、再小规模试跑。 - 打包产物在本机未验证(本机没有 PyInstaller 运行环境所需的完整桌面环境, 但 spec 里的 datas/hiddenimports 已按本仓库实际路径写好)。
- 上游若在 12306 接口变更后失效,本程序的风控/指标层仍可用,但查询会拿不到结果。
- 基于 pjialin/py12306(Apache-2.0),保留其全部业务代码与 LICENSE。
- 本仓库的改造部分(core/、ui/、webpanel/、packaging/、tools/)同样以 Apache-2.0 发布。
