简介:一份面向12306购票场景的自动化抢票脚本资源,主要帮助用户应对高峰期购票难题,通过模拟登录、查询余票、自动提交订单等流程提升抢票效率。资源包共134个文件,以Python脚本(py/pyc)为核心逻辑,涵盖登录验证、票务查询、验证码识别等模块;同时包含验证码识别的H5模型文件、Dockerfile运行环境配置、CDN筛选脚本以及运行日志、说明文档等辅助材料,压缩包整体约62.84MB。已有440人学习下载,适合具备一定Python基础、希望研究自动化脚本或图像识别落地的开发者参考。资源完整呈现了从请求处理到下单支付的代码思路,并附带预训练模型与容器化部署方案,便于学习端到端实现。需要提醒的是,使用此类脚本可能违反12306平台条款,请读者在了解相关法律风险后谨慎使用。 每年到了春运和节假日,12306抢票就成了绕不开的话题。我身边不少朋友都问过我有没有什么“神器”能提高抢票成功率,问我用的什么脚本。这个标题里的“qiangpiao12306”,其实就是围绕12306抢票脚本这一套自动化工具的代称。今天我就把这套东西的完整技术思路、具体实现和踩坑经历都整理出来。不管你是程序员想自己写一个,还是普通用户只是想搞明白这类工具到底靠不靠谱,这篇都能给你一个比较完整的参考。
先说清楚这套脚本到底能干什么:它本质上是把你在浏览器里手动查票、提交订单的过程,用代码自动化掉。核心就是比人手更快地刷新余票、更早地提交购票请求。但这里有个坑我必须先告诉你:12306官方并没有开放专门的抢票API,所以所有这类脚本都是基于网页端接口的模拟请求,不是官方提供的快速通道。这意味着,脚本提升的是你的“操作速度”,而不是给你插队特权。理解这一点,你才能正确评估脚本的价值和风险。
1. 抢票脚本的核心思路与整体架构设计
写抢票脚本之前,一定要先把12306的购票流程拆清楚。整个购票链路可以分成几个大的阶段,脚本要做的就是把其中重复性最高、最耗时间的环节自动化。
1.1 拆解12306购票流程中的关键节点
一个完整的购票流程,从用户角度是这样的:登录账号 → 查询车次 → 选中车次和乘车人 → 提交订单 → 支付。听起来很简单,但每一个步骤在技术上都有对应接口,而且这些接口之间有严格的调用顺序和依赖关系。
从技术角度看,整个流程的核心是这几个点:登录态维持、余票查询、提交订单前的Cookie校验、订单提交。其中,余票查询这个接口是整个抢票脚本的心脏。12306的余票查询接口是公开可访问的,不需要登录就能查,这给了脚本很大的操作空间——你可以开很多个并发请求,轮询指定车次的余票状态,一旦发现有票就立即进入下单流程。
至于下单流程,就需要登录态了。脚本需要模拟一个完整的浏览器会话,包括携带用户的Cookie、处理可能的验证码校验、构造正确的表单数据。很多人以为抢票就是“一直点提交按钮”,实际上12306有频率限制,同一个账号短期内的操作频率过高,会被系统判定为异常行为,触发风控,轻则需要重新登录,重则会暂时封禁账号的购票功能。
1.2 为什么选择“接口模拟”而不是“浏览器自动化”
实现自动化抢票,有两种主流的技术路线:一种是用Selenium、Playwright这类工具驱动真实浏览器,模拟鼠标点击和键盘输入;另一种是直接分析网页后端的API接口,用HTTP请求库(如Python的requests)直接发送数据包。
两种方案各有优劣,但对12306抢票这个场景,接口模拟是明显更合适的选择。原因很简单:第一,速度差异巨大。Selenium驱动真实浏览器,每一次操作都要加载页面、执行JavaScript、渲染DOM,整个流程下来最快也要两三秒。而直接调接口,一个请求从发出到收到响应,通常只需要200到500毫秒。在抢票场景里,这个速度差异就是生死线。
第二,资源占用不同。开十个Selenium浏览器窗口,电脑基本就卡死了。但用接口模拟,哪怕起二十个协程并发查询,对系统资源的消耗也很小。我自己的测试经验是,一个轻量级的接口模拟脚本,跑在普通笔记本上,同时监控大约10趟备选车次,CPU占用率基本保持在5%以下。
当然,接口模拟的缺点是开发门槛更高。你需要自己抓包分析每个请求的完整参数,理解12306的加密逻辑和反爬机制。这个后面细说。
1.3 抢票脚本的整体功能模块划分
我设计的脚本架构,按功能划分成四个独立模块:
- 登录模块:负责用户账号的登录认证,保存登录后的Cookie,并在Cookie过期时自动重新登录。
- 余票监控模块:核心模块。负责按照预设的车次、日期、席别条件,高频查询余票状态,判断是否满足抢票条件。
- 下单模块:一旦监控模块发现符合条件的车票,立即触发。负责构造订单请求、提交订单、处理可能的验证码校验。
- 通知与日志模块:记录整个抢票过程中的关键日志,并且在抢票成功或失败时,通过推送渠道(如Server酱、钉钉机器人、邮件)通知用户。
模块化设计的好处很直接:任何一个模块出问题,其他模块还能正常工作。比如登录模块的Cookie失效了,但查询模块用的接口是公开的,不受登录影响,监控照样能跑,只是下单会失败并触发重新登录。这种容错机制在实际抢票场景里非常重要。
2. 各核心模块的技术细节与实现要点
光有架构还不够,每个模块里都藏着大量的细节坑。这一部分我逐一拆解,把关键的实现思路和参数选择讲清楚。
2.1 登录模块:Cookie管理与会话保持
登录是抢票脚本的第一道坎。12306的登录接口做了很复杂的加密,用户名和密码在提交前会经过多次编码。直接把密码明文放进请求里,是绝对过不了校验的。
比较常见的做法是,先通过脚本手动引导用户完成一次扫码登录。具体流程是:脚本调用登录页面的二维码接口,获取二维码图片展示给用户,用户用12306 App扫码确认后,脚本再用扫码结果去换取登录Cookie。这种方式绕开了密码加密的复杂环节,而且扫码登录的安全性更高,账号不容易被风控标记。
拿到Cookie后,要持久化保存到本地。因为12306的会话有效期通常比较长,几天内不需要重新登录。但如果脚本运行中Cookie过期了,下单请求会返回未登录的错误码,这个时候脚本需要自动进入重新登录流程。我的实现里还有一个细节:在Cookie刷新后,要立即重新验证所有乘车人的信息,因为有时候会话切换会导致乘车人列表的缓存失效。
提示:这里不建议使用“记住密码+自动填表”的无头浏览器方案。一方面,模拟密码加密逻辑复杂,且12306的加密算法会不定期更换;另一方面,无头浏览器的特征容易被12306检测到并拦截。扫码登录是省心又稳妥的方案。
2.2 余票监控模块:查询频率与并发策略
余票查询接口是整个流程里对性能要求最高的部分。这里的关键参数有两个:查询间隔和并发数量。
查询间隔是个需要拿捏的参数。设置得太短,比如500毫秒一次,容易被12306的网关限流,返回异常数据或者直接封一段时间IP;设置得太长,比如3秒以上,又会错过放票的黄金时间。根据我的实际测试,1秒到1.5秒的单线程查询间隔是一个相对安全的区间。但如果你有多个车次需要监控,更好的做法是不要同步轮询,而是把车次切割到不同的协程里去异步查询,每个协程的间隔错开,避免瞬间高并发。
并发数量这里要特别注意。很多人有个误解,以为并发越高越好,恨不得开100个线程去刷。真实情况是,12306的余票查询接口虽然不做登录校验,但它有针对IP的请求频率限制。我自己测试下来,单个IP的查询并发控制在5到10个是可行的,超过15个就会开始出现偶发的请求失败和响应超时。如果你确实需要监控大量车次,建议用多台设备或者多个网络出口分摊压力,而不是在一台机器上硬扛。
还有一个很容易忽略的优化点:解析响应数据的时机。余票接口返回的是JSON格式的数据,里面的余票信息是按站序排列的数组。如果目标车次是过路车,要判断你出发站和到达站的区间是否有票,就需要按照站序找到出发站和到达站的索引,从这两个索引区间里寻找余票数据。这里有一个常见误区——有人只看第一站到最后一站的全程余票,结果明明中途区间有票却错过了下单机会。正确的做法是在查询参数里指定出发站和到达站,让接口直接返回你需要的区间余票。
2.3 下单模块:验证码识别与订单提交
下单模块是整个脚本里最复杂的部分,因为12306在下单过程中会动态变换验证码的类型。早期的验证码主要是图像点选,后来增加了滑块验证,现在还会根据账号风险等级动态决定要不要出验证码、出哪种验证码。
图像点选验证码的自动化识别,常用的方案是接打码平台。这个方案理论上很成熟,但实际体验依赖于打码平台的服务质量和响应速度。高峰期抢票时,打码平台的请求量也大,识别速度和准确率都会下降。滑块验证码的自动化,则是在无头浏览器里模拟拖拽轨迹,关键在于轨迹要符合人工操作习惯——不能是匀速直线,要有加速减速和微小的抖动。但这套方案实现复杂,而且12306的滑块验证会动态监测操作行为数据,不推荐普通开发者尝试。
说点实在的:如果你不是专门搞验证码攻防的,不要把精力浪费在自动化识别验证码上。我自己的经验是,当脚本检测到需要验证码时,立即把二维码或者点选图弹给用户,让人工在几秒内完成识别和操作。这样虽然牺牲了一点自动化程度,但成功率高得多,而且不容易触发风控。毕竟,抢票的核心是“提交得快”,而不是“全程无人值守”。
订单提交的请求构造也很有讲究。需要提交的参数包括:车次ID、乘车日期、出发站和到达站的编码、乘车人信息(姓名、身份证号、手机号)、席别类型。乘车人信息可以从“常用联系人”接口获取,但要注意,一个订单最多添加5个乘车人,如果你设置的家庭成员超过5人,脚本要自动做分批处理或优先级排序。这个参数在实际使用中经常被人忽略,等到下单成功却发现漏了一个人的票,就很尴尬了。
3. 从零搭建一套可用的抢票脚本:完整实操流程
接下来我把整个脚本的搭建过程走一遍。这里以Python为主要开发语言,因为相关的库支持和资料最多,遇到问题也最好排查。
3.1 环境准备与依赖安装
基础运行环境是Python 3.8以上。需要安装的第三方库有这些:requests(HTTP请求)、Pillow(二维码图片处理)、pyecharts或prettytable(日志可视化,可选)、APScheduler(定时任务调度,用于定时开启抢票)。
用下面这行命令就能完成全部安装:
pip install requests Pillow APScheduler prettytable安装完成后,建议先用浏览器登录一次12306网站,然后通过浏览器开发者工具(F12)复制出自己的Cookie串,保存为cookie.txt。这是为了调试其他模块时不用反复扫码登录,开发完再换成自动扫码登录的完整流程。
3.2 核心代码框架与关键参数配置
我习惯先把配置文件和核心逻辑分离。配置文件用JSON格式,里面写清楚车次、日期、乘车人、席别偏好等信息:
{ "train_date": "2025-02-08", "from_station": "北京", "to_station": "成都", "passengers": [ {"name": "张三", "id_card": "110101199001011234", "phone": "13800000000"}, {"name": "李四", "id_card": "110101199202022345", "phone": "13900000000"} ], "train_preferences": ["G307", "G317", "Z49"], "seat_preferences": ["M", "P", "A1"], "query_interval": 1.2, "concurrent_count": 6, "notify_url": "https://sctapi.ftqq.com/你的sendkey.send" }这里解释一下seat_preferences里的代号,这些是12306内部的席别编码:M是一等座,P是二等座,A1是硬卧,A2是软卧,O是硬座。设置多个偏好值时,脚本会从前到后依次尝试,先试试有没有一等座,没有就自动降级为二等座。
主脚本的框架大致如下:
import requests import json import threading import queue from datetime import datetime class TicketGrabber: def __init__(self, config): self.config = config self.session = requests.Session() self.cookie_jar = {} self.stop_flag = threading.Event() self.notified_trains = set() def login_by_qrcode(self): # 获取二维码 -> 展示给用户 -> 轮询扫码状态 -> 获取Cookie pass def query_left_ticket(self, train_code): # 构造余票查询URL,请求并解析余票数据 url = "https://kyfw.12306.cn/otn/leftTicket/queryG" params = { "leftTicketDTO.train_date": self.config["train_date"], "leftTicketDTO.from_station": self.config["from_station"], "leftTicketDTO.to_station": self.config["to_station"], "purpose_codes": "ADULT" } resp = self.session.get(url, params=params) # 解析并返回候选车次的余票状态 pass def auto_submit_order(self, train_code, seat_type): # 提交前校验 -> 选乘车人 -> 提交订单 pass def run(self): # 主循环:并发查询 -> 判断余票 -> 触发下单 pass3.3 关键环节的调试记录与输出验证
实际调试中,最容易出问题的地方是乘车人信息的提交格式。12306的订单提交接口对于乘车人参数有严格的序列化要求,包括每个乘车人的姓名、身份证号、手机号、席别、车次ID。尤其是身份证号有加密要求,需要调用一个单独的加密接口先把明文转换成密文,再塞进订单请求里。这一步我初次实现时踩了不少坑,每次提交都提示“乘车人信息格式不正确”。后来对照浏览器的请求日志,发现是自己漏掉了加密步骤。
调试时建议加详细的日志输出。我用的是prettytable把查询到的余票信息格式化成表格,打印在控制台上,方便肉眼观察每次查询的结果变化。同时,对所有HTTP请求的响应状态码、响应耗时、返回的错误信息都做记录。这样做的好处是,当抢票失败时,你能根据日志快速定位问题是出在网络层面、接口参数层面还是风控拦截层面。
在这个环节,我强烈建议先做一次“模拟抢票测试”。找一趟非高峰期的冷门车次,把脚本跑通整个流程——查票、选人、提交订单,一直到“订单待支付”状态然后手动取消。这样既能验证所有环节正常,又能发现真实环境下的隐患,比等到春运当天再手忙脚乱要靠谱得多。
4. 常见问题与排查技巧实录
脚本写完之后,真正的挑战才开始。我在多次抢票实战中积累了一些问题和排查经验,整理成表供参考。
4.1 高频问题速查表
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| 查询接口频繁返回空数据 | 请求频率过高触发限流 | 适当增大查询间隔,降低并发数 |
| 提交订单时提示“未登录” | Cookie失效或会话过期 | 检查是否成功重新登录,刷新Cookie缓存 |
| 下单成功但乘车人信息报错 | 身份证号未加密或提交格式错误 | 核对加密接口是否生效,对照浏览器抓包数据 |
| 页面能登录但脚本无法登录 | 风控策略触发,需要验证码 | 改用扫码登录,或等待一段时间再试 |
| 提示“当前排队人数过多” | 请求并发太高或账号异常 | 降低频率,等待风控解除 |
| 余票查询正常但下单总是失败 | 车票区间判断逻辑有误 | 检查站序索引,确认区间余票解析正确 |
| 脚本运行一段时间后突然无响应 | 某个请求长时间未返回,无超时设置 | 给所有HTTP请求添加超时参数和重试机制 |
4.2 高频踩坑点:限流、风控与请求超时
限流和风控是第一大坑。12306的后端有一套实时风控系统,会根据请求频率、操作路径、设备指纹、IP行为模式等维度综合判定账号的风险等级。一旦被判定为高风险,轻则要求额外验证,重则直接无法下单。
我亲身经历过一次:一个测试脚本在15分钟内高频查询了上千次,结果账号的购票功能被锁定了近6个小时。从那以后,我把“查询间隔”设定为动态的——平时1.5秒一次,当检测到响应时间变长或者返回异常数据时,自动拉长到3秒,同时降低并发。这个策略看起来保守,但胜在“活得久”,整个抢票窗口期都能持续稳定运行。
请求超时是第二大坑。12306在高峰期服务端的响应会变慢,如果你没有设置合理的超时时间,一个请求可能卡住几十秒,直接拖垮后面的所有操作。我的做法是:所有请求统一设置timeout=5,即5秒内没有响应就放弃这次请求,进入下一次重试。不要担心错失机会——一次超时的请求,即使等更久大概率也是失败,不如快速放弃重试。
4.3 并发模型的选择:多线程还是协程
最后一个值得专门聊聊的技术细节是并发模型。很多人一上来就写多线程,开了几十个线程,结果性能没提升多少,反而因为线程上下文切换和共享内存的锁竞争问题,把自己搞得焦头烂额。
我的建议是在Python 3.8以上版本优先使用asyncio协程。原因很直观:这里的任务都是I/O密集型的网络请求,协程在等待网络响应的间隙会自动让出控制权,完全不需要手动管理锁。实测下来,用协程写10个并发查询,代码量比多线程精简至少一半,可读性和可维护性都要好得多。
需要特别提醒的是,处理共享受控资源时仍然要小心。比如Cookie的更新、乘车人列表的缓存,这些是多个协程共享的数据。我在代码里给它们加上了asyncio.Lock,在每次读取或更新时先获取锁,避免多个协程同时写数据导致状态错乱。这个问题排查起来非常隐蔽,因为不是每次都必现,属于典型的“偶发性bug”。
5. 合规使用与边界思考:脚本不是万能钥匙
技术聊到最后,必须聊边界问题。抢票脚本这个领域,很容易陷入一个误区——以为脚本越猛越好,自动化程度越高越好。但从我多年的实际使用经验来看,这个观点是危险的,也是不现实的。
首先是合规风险。12306的用户协议里明确禁止使用自动化工具进行购票。虽然目前对个人使用脚本的“小额低频”行为监管相对宽松,但一旦你的脚本触发了风控,被系统检测到并认定为高风险操作,官方有权限制你的账号功能。每年春运期间,都能在社交平台上看到有人分享“账号被12306风控锁定”的经历,其中相当一部分就是因为用了太过激进的抢票工具。
其次是概率论上的现实。12306的放票机制有很强的随机性和动态性,不同车次、不同区间的放票时间点并不完全固定。脚本能做的,只是把“你盯票”的成本降到最低,把“你提交订单”的速度提升到接近极限。至于放不放票、放多少票,脚本是左右不了的。说白了,脚本的价值在于“当票出现时你能比别人快半秒”,而不是“凭空变出一张票来”。
我在实际使用中得到的感受是,这类工具的最佳使用方式是:把它当成一个勤快的助手,而不是一个包抢成功的外挂。让脚本帮你盯紧几个备选车次,一旦有票马上通知你、帮你抢占一个待支付订单,但最后是否支付、是否调整行程,还是由你来做决策。
最后分享一个真实的个人经验:去年春运,我用这套脚本给家里人抢一张成都到北京的高铁票。由于开车前三天是退票高峰,我把脚本的监控车次加到了8个,查询间隔调整到1秒,并发拉到8个,从早上的7点一直跑到晚上11点。最终在下午的3点17分,监控模块捕捉到一趟原本无票的车次放出了两张商务座,脚本自动提交订单,从检测到票到提交成功只用了不到3秒。这趟车的票真的很难刷,但脚本帮我做到了“在票出现的那一瞬间就锁住它”。这种体验,单纯靠人和浏览器,确实很难复制。
本文还有配套的精品资源,点击获取