简介:针对演唱会抢票这一高频场景,资源内含自动化抢票脚本与配套说明文档,面向有一定编程基础、希望系统掌握爬虫、多线程、定时任务等实战技能的开发者。压缩包共两个文件,分别是py脚本和txt说明;脚本覆盖模拟登录、并发请求、定时触发和异常处理等关键环节,说明文档交代运行环境、依赖库及基本使用流程。包体仅6KB,轻量易用。目前已有1065人学习下载。通过该案例,可以直观理解请求库与解析库在数据抓取中的配合方式,学习多线程与多进程在并发场景下的取舍,并掌握利用定时任务库实现到点自动执行的方法;代码中体现的Cookies与会话维持、验证码处理思路,以及日志输出习惯,也可迁移到其他自动化项目中,是提升Python工程能力的实用参考。 不少朋友应该经历过这种场面:开票前一分钟,页面上的按钮还灰着,倒计时一过,你疯狂点鼠标,结果永远被卡在“排队中”。我也一样,手速拼不过别人之后,干脆写了一套Python抢票脚本,从登录到下单前前后后调试了两周,最后帮着抢到两张内场票。这篇文章就把我的完整思路、代码结构和踩坑记录一起分享出来,算是一个真实的Python实战项目复盘。
先说清楚,这不是什么黑科技,也不是教你绕过平台规则的灰色操作。Python在这里做的事情,本质上是把“盯倒计时、刷余票、选场次、点提交”这些重复动作固化成程序,让脚本比人手更快、更稳定。文章会涉及Python安装、requests请求、Cookie登录、轮询与异常处理等知识点,适合有点Python基础、想做一个完整实战项目的读者参考。用之前一定先看平台的用户协议,个人学习、自己抢票没问题,但千万别拿它去干破坏公平购票的事。如果你连Python环境都还没装好,建议先去官网下载Python 3.10以上版本,安装时记得勾选“Add Python to PATH”,装完在命令行敲一下python --version,能输出版本号再继续往下看。
1. 为什么有人能用Python抢到票:先理清抢票的本质
1.1 手动抢票为什么拼不过脚本
很多人觉得抢票是拼网速、拼手速,其实更准确地说,是拼“做重复动作的速度”。人的反应时间通常在200到300毫秒,鼠标移动到指定位置、确认场次、选择票档、勾选观演人,再点提交,整套流程至少需要一两秒。而脚本通过网络请求发出指令,在同等网络条件下可以达到毫秒级,甚至可以在开票瞬间同时完成多次尝试。
另一个关键点在于,手动抢票时页面要先渲染、加载JavaScript、等图片资源,真实看到按钮能点击的时候,其实已经比最原始的数据慢了很多。Python脚本可以直接请求后端接口,跳过大量页面渲染时间。很多平台开票后会先“锁库存”,这时候谁先提交订单,谁就大概率锁住票。脚本的优势不在于“聪明”,而在于省掉了所有不必要的中间步骤。
1.2 一条门票订单背后的完整请求链路
要写抢票脚本,就得先搞明白从打开页面到支付成功,系统里到底发生了什么。我以自己调试过的流程为例,大致可以分成几步:打开演唱会详情页,拿到基本场次信息;点击“立即购买”,进入选票档和观演人页面;系统加载余票状态,判断当前是否可购;提交订单,平台锁定库存;跳转支付,订单状态变为待支付。
其中真正的关键节点只有两个:余票查询接口和提交订单接口。前者负责告诉脚本“什么时候有票”,后者负责把票锁到你的名下。其他步骤比如页面渲染、倒计时动画、选座动画,都只是交互层的装饰。理解了这一点,Python抢票脚本的核心就变成了两件事:以合理的频率轮询余票接口,一旦发现有余票,立刻用携带好的用户身份信息去提交订单。
1.3 抢票脚本的基本策略
基于上面的链路,我的脚本策略非常简单:提前登录保持会话,提前选好目标场次和票档,开票前几分钟开始轮询,检测到余票后立刻下单;如果提交失败,根据错误信息决定是重试还是停下来人工处理。这套逻辑不需要机器学习,也不需要造什么复杂模型,大部分情况下用requests和基本的异常处理就够了。
还有一个容易忽略的点:抢票脚本的成功率不只取决于“快”,还取决于“稳”。比如请求超时要重试,接口返回异常要记录日志,提交订单后要确认是否真的锁单成功。很多半路失败的脚本,问题不是不够快,而是一次请求报错后直接崩溃,或者重复提交导致订单异常。所以后续所有代码,我都围绕这个最小可用流程来展开。
2. 环境准备:从Python安装到依赖选型
2.1 基础环境与虚拟环境配置
写Python抢票脚本的第一步,是准备一套干净、可控的开发环境。Python版本我建议用3.10以上,有些旧的加密库在3.7上已经跑得不太稳,没必要给自己添堵。安装完成后,最好给项目单独建一个虚拟环境,避免系统里乱七八糟的包互相影响。在项目目录下执行:
python -m venv venvWindows环境下激活虚拟环境用venv\Scripts\activate,macOS和Linux用source venv/bin/activate。激活后,命令行前面会出现(venv)前缀,代表你正在独立环境里工作。这一步看起来简单,但能帮你省掉很多依赖冲突的问题。
接下来安装项目需要用到的库。我最初只装了一个requests,后面调试时又加上了fake-useragent用来随机生成User-Agent,以及loguru用来打印带时间的日志。安装命令就一行:
pip install requests fake-useragent loguru我一直建议不要在一开始就把所有可能用到的库全装上,做到哪一步需要什么再装什么,这样你对每个依赖的作用会更清楚。
2.2 requests、selenium、playwright到底怎么选
这是很多新手第一个卡住的地方。网上关于抢票的教程,有人用selenium模拟浏览器点击,有人用playwright自动打开页面,也有人用requests直接请求接口。我的结论是:优先用requests,不到万不得已不要碰浏览器自动化。
做个简单对比:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| requests直接请求接口 | 请求体积小、执行快、资源占用低 | 需要手动分析接口和构造参数 | 能抓到接口且登录态好处理时首选 |
| selenium模拟浏览器 | 不需要分析接口,直接用页面元素定位 | 启动慢、容易被风控识别、维护麻烦 | 页面复杂或接口加密难解时兜底 |
| playwright模拟浏览器 | 自动化能力更强、支持多浏览器 | 同样有被识别风险,体积大 | 需要稳定调试浏览器交互时使用 |
我当时先试过selenium,发现每次启动浏览器都要浪费好几秒,而且打开真实页面后还要等动态加载,抢票高峰期很容易被“排队等待”拦住。后来老老实实打开开发者工具,找到余票查询和提交订单两个接口,改用requests直接请求,速度和稳定性都上来了。
2.3 为什么我推荐“半自动”而不是“全自动”
所谓全自动,就是脚本连登录、验证码、滑块全部自己处理。理论上很诱人,但实际写的时候你会发现,票务平台的风控不是吃素的,一旦检测到高频自动化行为,验证码会频繁出现,甚至账号被临时限制。与其花大量时间去破解这些机制,不如做一套“半自动”流程:脚本负责轮询、下单、异常重试,遇到验证码或滑块时,由人工介入处理。
这种设计的好处有两个。第一,开发成本低很多,我只需要关心核心的请求逻辑,不需要和前端加密对抗。第二,账号安全性高,不会因为代码里某个参数写错导致被平台判定为外挂。我在实际使用中,遇到验证码的概率并不高,但只要出现,就暂停脚本,手动点一下,然后再继续。整个过程也就多花十几秒,但账号安全很多。
3. 抢票脚本的核心结构:登录、选座、下单三步走
3.1 登录与Cookie管理
直接通过requests模拟登录票务平台往往是件痛苦的事,很多平台的登录接口有加密参数,单纯用账号密码很难构造出合法请求。我自己的做法是:先打开浏览器,手动完成一次登录,然后从开发者工具里复制Cookie,放到脚本里作为请求头。这样既绕开了复杂的登录加密,又保证了身份信息的真实性。
这里要特别注意Cookie是有时效的,不同平台有效期不一样,短的可能只有几小时,长的能维持几天。所以脚本里应该保留一份读取Cookie的代码,每次运行前手动检查一下是否过期。简单示例:
import requests COOKIES = { "sessionid": "你的sessionid", "user_token": "你的user_token", } HEADERS = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Referer": "https://example.com/concert/123", }复制Cookie时,建议把请求头里的User-Agent一起复制,很多风控系统会同时校验这两者。如果发现请求返回“未登录”或“请先登录”,第一件事就是检查Cookie有没有过期,而不是怀疑代码写错。
3.2 抢票主流程:开票前倒计时与快速下单
主流程我写成了一个死循环,开票前每0.5秒查一次余票,发现有余票就跳出循环去执行下单函数。轮询频率不建议太快,低于0.3秒的请求率很容易触发接口限流,反而适得其反。下面是一个简化版本的余票检查逻辑:
import time def check_ticket(): url = "https://api.example.com/concert/ticket/status" resp = requests.get(url, cookies=COOKIES, headers=HEADERS, timeout=3) data = resp.json() return data.get("has_ticket", False) while True: try: if check_ticket(): print("检测到余票,开始下单") break except Exception as e: print("请求异常,等待重试", e) time.sleep(0.5)真正跑起来之后,你会发现最耗时的不是判断逻辑,而是网络请求本身。如果余票接口的响应时间超过1秒,0.5秒的循环就名存实亡。所以我在代码里把timeout设置为3秒,同时对异常做了捕获,保证单个请求失败不会让整个脚本退出。
3.3 订单提交接口的正确调用姿势
检测到余票后,下一步是提交订单。这一步比轮询余票更容易出错,因为提交订单通常需要携带更多参数:场次ID、票档ID、观演人ID,以及用于防伪的token字段。我在调试时踩过最典型的坑,就是少带了一个动态token,导致接口直接返回“参数错误”。
正确做法是:先在浏览器里手动完成一次下单流程,在开发者工具里找到提交订单的POST请求,把请求体里的字段逐个和页面上的选择对应起来。比如场次对应页面上的日期时间,票档对应“看台399/内场1299”这种按钮,观演人对应你添加的购票人姓名。参数补齐后,提交代码类似:
def submit_order(show_id, price_id, viewer_ids): url = "https://api.example.com/order/create" payload = { "show_id": show_id, "price_id": price_id, "viewer_ids": viewer_ids, "token": "从请求体中复制", } resp = requests.post(url, json=payload, cookies=COOKIES, headers=HEADERS) result = resp.json() if result.get("success"): print("下单成功,订单号:", result["order_id"]) else: print("下单失败:", result.get("message")) return result提交成功后,不代表就结束了。很多平台在高峰期会返回“排队中”或者“库存紧张”,这时候需要轮询订单状态,直到确认订单真正生成,再引导自己去支付。千万不要因为没立刻看到结果就重复提交,否则可能出现两个重复订单,处理起来非常麻烦。
4. 实战中的风控与排队问题:我的踩坑记录
4.1 一次“订单状态未知”的排查过程
我用脚本抢票的时候,遇到过这么一件事:提交订单接口返回了“成功”,但页面订单列表里却看不到任何记录。第一次遇到时我以为是脚本出了问题,反复提交了好几次,结果一个订单都没生成,反而把自己账号的请求频率拉高了。后来静下心来排查,才发现真正的原因在于:请求成功只是服务端接收了请求,并不代表库存锁定成功。由于我提交订单的速度太快,触发了平台内部的排队机制,很多请求进入队列后又被异步丢弃了,接口却返回了“已接收”的假象。
那次排查的链路大致是:先看接口返回码,确认是不是200;再看响应体里的业务状态码,区分code=0和code=1的含义;然后重新打开浏览器,手动下一单,对比正常订单和异常订单的请求参数差异;最后发现需要在提交订单后继续轮询一个“订单确认”接口,只有当确认接口返回有效订单号,才代表锁单成功。从那以后,我的脚本里就多了一个“确认订单”步骤,宁可慢一点,也不要一次次重复提交造成脏数据。
4.2 验证码与滑块验证的处理原则
很多人喜欢研究怎么自动通过滑块验证,我劝你少走这个弯路。验证码和滑块出现的本质,是风控系统已经注意到异常请求了。这时候继续加大自动化力度,只会让账号的风险等级更高。我的原则很简单:脚本检测到验证码元素或接口返回验证码标记时,立刻暂停自动提交,切换到人工处理。
如果你用的是requests直连接口,可以观察下单响应里是否包含类似need_captcha的字段。如果包含,就说明需要人工打开浏览器完成一次验证,然后拿着新的Cookie继续跑。如果你用的是selenium或playwright,处理起来更直观:截个图,弹窗提醒,让人工把滑块拖到指定位置。实测下来,人工处理滑块的成功率远高于程序模拟,而且账号更安全。
4.3 频率控制与IP限制:别因为抢票把自己账号搞封了
抢票脚本最容易犯的错,就是以为“请求越多越容易抢到票”。其实所有正规票务平台都有接口频率限制,短时间请求次数过多,轻则返回“操作频繁”,重则直接封禁账号。我在调试早期就因为轮询间隔设置成0.1秒,导致账号被临时限制登录,差点错过了正式开票时间。
后来我给自己定了几条参数底线:轮询间隔不低于0.5秒,提交订单后至少要等待2秒再查状态;每次开票最多连续尝试10次提交,超过10次就停下来休息30秒;所有请求都增加随机延迟,比如在基础间隔上增加0.1到0.3秒的随机数,让请求节奏更接近真人操作。这些参数不保证一定能抢到票,但至少能保证账号活着,活着才有机会。
4.4 日志和断点续跑:脚本稳定性的最后一道防线
脚本跑在本地,最怕就是运行到一半崩溃,而你刚好走开喝了个水。那次排查订单状态问题时,我发现脚本在请求异常后直接死循环,没有记录任何有效日志,导致我完全不知道卡在哪一步。后来我加了loguru日志,每次轮询、每次下单、每次异常都记录带时间戳的日志,一旦出错能很快定位。
同时,我会把抢票的“状态”写入一个本地JSON文件,比如当前是否已经下单、订单号是多少、是否已确认。如果脚本中途崩了,重启后先读状态文件,判断是继续轮询还是直接进入等待支付,而不是傻傻地重新下单。这套“断点续跑”的设计让整个抢票过程可靠很多。
5. 从抢票脚本到自动化工具:合规边界与后续扩展
5.1 哪些事情一定不能做
写了这个项目之后,经常有人问我能不能帮忙写一个“代抢工具”,或者做成多开、多线程版本去提高成功率。我的答案都是拒绝。原因很简单:用脚本抢票用于个人学习、节省重复操作时间,这是合理的;但如果你用它批量注册账号、囤票、高价倒卖,或者绕过平台验证码、突破接口频率限制,那就完全变了性质,轻则违反用户协议,重则涉及法律风险。
我这里要特别强调几个不能碰的边界:不要尝试破解任何验证码;不要多线程并发请求去压测平台;不要收集他人账号信息;不要爬取非公开的接口数据。Python是个强大的工具,但工具本身不分善恶,使用方式却决定了风险。写这个项目时,我给自己立的规矩是:只在开票时段使用,不恶意占用资源,不用于任何商业用途。
5.2 抢票脚本之外的自动化学习思路
虽然抢票只是一个很小的场景,但它把Python自动化的几个核心知识点串起来了:HTTP请求和会话维持、Cookie与登录态、接口分析与参数构造、异常处理与重试机制、日志记录与状态管理。这些知识完全可以直接迁移到其他自动化任务上,比如自动化报名、定时签到、库存监控、报表拉取等等。
如果你想深入学习,我建议从“把这个脚本部署到云服务器上”开始,加上定时调度,让它每天自动检查某场演出的余票,有票时发个邮件或微信通知给自己。还可以尝试用FastAPI写一个简单的Web控制台,在浏览器里手动修改目标场次和票档。你会发现,抢票脚本只是自动化项目的一扇门,门后才是真正的Python实战能力。
5.3 我对这类效率工具的真实态度
做了这个项目后,我不再觉得“抢票脚本”是个神秘的东西。它的核心价值,是让程序替人去等、去盯、去重试,把人从机械操作里解放出来。但同时我也清楚,这类工具天然带着灰色色彩,因为每一个被脚本抢到的票,背后可能是另一个人没抢到的遗憾。所以我在实际使用中给自己定了一个很保守的原则:只抢自己真正要去的场次,不一次性抢多个场次、不帮人代抢、不囤票占坑。
我最后分享一个自己的小技巧:与其把整个流程都交给脚本,不如把它当成一个“加速器”。开票前我还是会在电脑前守着,脚本一旦检测到余票,立刻给我弹窗提醒,我再手动确认场次和票价。这样既保证了速度,也留了一道人工判断的阀门,很多因为参数错误导致的烂摊子,其实都能靠这一道阀门拦下来。希望这篇复盘能给你一些启发,也祝你下次开票时能顺利见到想见的人。
本文还有配套的精品资源,点击获取