资讯动态

大麦网抢票脚本源码解读:Python自动化抢票原理与实战

发布时间:2026/10/21 21:52:45 来源:尧图企业网站定制
简介大麦网抢票脚本压缩包面向热门演出开票时希望提升购票成功率的Python学习者和票务用户解决手动刷新慢、提交订单容易错过时机的问题。脚本基于Python与Selenium实现能够模拟浏览器自动化完成刷票、填写购票信息、提交订单等操作项目中还通过独立的txt配置文件存放登录信息便于在运行时读取并保护隐私。压缩包内共2个文件含1个py源码文件与1个txt配置文件整体仅5KB结构简单轻量不过作者提示内容改得较乱需要使用者参考实测教程并结合实际页面、验证码策略自行调试。目前已有22067人浏览学习说明该脚本在自动化抢票场景下关注度较高。通过阅读源码可以掌握Selenium驱动浏览器、读取外部配置、封装抢票流程的典型写法也可借鉴定时刷新与订单提交的思路迁移到其他网页自动化练习中。1. 大麦网抢票脚本是什么一个从开票页面到支付确认的 Python 自动化工件周五下午三点的开票时间我守在电脑前刷了四十分钟页面从「即将开抢」变成「缺货登记」只用了三秒。这就是大麦网热门演出的常态。市面上流传的这套「大麦网抢票脚本.rar」不是黑科技本质就是一个用 Python 写成的浏览器与接口自动交互程序核心逻辑是带登录态发起请求、轮询库存、锁定座位、提交订单四步走。技术栈很朴素——requests 做接口交互selenium 负责保留真实浏览器指纹再加一个配置文件控制场次和票档。这个项目适合两类人一是自己抢票总差半秒的个人用户想把这个半秒变成程序里的毫秒级轮询二是想学 Python 自动化爬虫的开发者研究登录态维持、请求参数构造和风控对抗这三件套。对黄牛来说这套脚本反而太慢它不加代理、不换设备指纹、也没有多账号调度。所以定位很明确个人自用、提高抢票成功率顺便当自动化练习项目。2. 项目结构拆解从配置加载到订单提交的完整链路2.1 目录结构与职责划分解压这套脚本目录并不复杂但分层是清楚的。常见的排布是根目录下放主入口、配置、核心逻辑、工具集四块我把典型结构列一下damai-script/ ├── main.py # 入口控制整个抢票流程的先后顺序 ├── config.yaml # 场次、票价档、抢票时间、轮询频率等参数 ├── core/ │ ├── login.py # 扫码登录与 Cookie 维护 │ ├── perform.py # 场次查询、座位锁定状态判断 │ ├── order.py # 提交订单、构造 payload、处理返回码 │ └── notify.py # 抢票成功后的通知逻辑音频/桌面推送 ├── utils/ │ ├── logger.py # 日志记录从启动到下单的每一步 │ └── captcha.py # 验证码识别辅助失败时人工兜底 └── requirements.txt # 依赖清单这个结构的价值在于把「查询库存」和「提交订单」拆成两个独立模块。很多第一次跑这脚本的人会问为什么不在一个文件里写完因为抢票场景里查询是高频轮询操作下单是低频但必须带着完整上下文的操作。如果合在一起每次轮询都要重新构造订单数据一旦接口返回「参数缺失」或者「会话过期」你就分不清是哪一环出了问题。分开之后perform 模块只干一件事循环请求演出场次接口直到发现目标场次的票档有库存。发现之后立刻把返回内容中的场次 ID、场馆 ID、演出计划 ID 这些关键值存到一个全局状态对象里order 模块再从这里取。整个数据流是单向的排查问题时顺着日志走一遍就知道卡在哪一步。2.2 抢票主流程的状态机设计主流程本质上是一台状态机。我把 main.py 里的循环逻辑概括成下面几个状态待开启、轮询中、已锁定、已下单、已完成。每个状态之间都有明确的转移条件。普通的手工抢票是人在做状态切换脚本要做的是把状态切换的延迟压到最低。具体到代码里main.py 的骨架长这样import time import config from core.login import LoginSession from core.perform import PerformFetcher from core.order import OrderSubmitter def main(): cfg config.load(config.yaml) session LoginSession(cfg[account]) session.login_by_qrcode() # 先拿登录态 fetcher PerformFetcher(session, cfg) submitter OrderSubmitter(session, cfg) print(等待开票时间...) while time.time() cfg[start_time]: time.sleep(0.2) # 每 200 毫秒检查一次是否到点 while True: stock fetcher.check_stock() if stock and stock[available]: seat fetcher.pick_seat(stock[seat_list]) result submitter.create_order(seat) if result[success]: print(下单成功等待支付) break time.sleep(cfg[poll_interval])核心设计点是时间判断和轮询节奏分开。while time.time() cfg[start_time]这一段是预先等待精准唤醒进入第二个循环之后才是高频轮询。很多魔改版本把两个循环合在一起结果就是每天跑一次这个脚本会一直请求接口抢票还没开始就已经被风控盯上了。参数说明poll_interval一般设 0.3~0.8 秒别低于 0.2 秒。低于这个值请求频率和正常用户差距太大反而容易触发频控。start_time建议设成开票时间前 10~20 秒留出加载演出详情页和初始化 session 的时间。2.3 关键接口参数解读大麦网抢票脚本能跑通的关键是搞清楚 web 端的演出详情接口和下单接口要什么样的参数。项目里把这部分参数写死在 core/perform.py我拆出来给你看def build_query_params(self, item_id, perform_id): return { itemId: item_id, performId: perform_id, channel: damai_web, platform: pc, returnItemInfo: true, }这几个参数里itemId是演出的 IDperformId是具体哪一场同一部剧可能有 19:30 和 14:00 两场这两个 ID 就不一样。returnItemInfotrue是让接口把可售库存、票档列表、座位图一并返回省去二次请求。很多二次开发的人会在这上面踩坑用手机 App 抓包拿到的参数直接套到 web 前端脚本上channel还在用damai_app结果请求接口直接返回空库存。原因是渠道不同后端返回的库存数据结构和座位分布完全不一样。这个项目里如果看到channel: damai_web说明作者是按网页端抓包设计的你改造时保持一致就行。下单接口的参数更敏感一点核心包括场次 ID、座位 ID 列表、购买数量、支付方式以及一个签名用的buyNow字段标志。这部分的代码放在 3.3 节里细讲因为它直接关系到能否提交成功。3. 核心模块实战登录态、选座筛选与订单提交的代码细读3.1 扫码登录与 Cookie 自动续期登录模块是整个脚本的基石。requests 本身不保存任何会话状态所以抢票脚本必须显式管理 Cookie。项目里常见的实现是用 selenium 打开一个真实浏览器窗口生成二维码用户扫码后把登录态写入本地文件之后脚本就用这个文件里的 Cookie 去发请求。from selenium import webdriver import pickle, time class LoginSession: def __init__(self, cookie_filecookies.pkl): self.cookie_file cookie_file options webdriver.ChromeOptions() options.add_argument(--disable-blink-featuresAutomationControlled) self.driver webdriver.Chrome(optionsoptions) def login_by_qrcode(self): self.driver.get(https://passport.damai.cn/login) print(请在两分钟内扫码) time.sleep(120) cookies self.driver.get_cookies() with open(self.cookie_file, wb) as f: pickle.dump(cookies, f) self.driver.quit()这段代码有两个容易被忽视的点。第一是--disable-blink-featuresAutomationControlled这个参数它关闭了浏览器自动化标记让 selenium 打开的 Chrome 不至于一上来就被识别成机器人。第二是 Cookie 直接 pickle 落盘下次运行可以加载复用不用重复扫码。使用上有玄学成分Cookie 有效期不稳定有时候能撑几天有时候几小时就失效。所以项目里我一般会加一个校验函数登录后先请求一次个人信息接口看返回是 200 还是 401判断是否要重新登录。这个脚本里如果没写你可以在 main.py 的login_by_qrcode()后面补一个检查避免开抢那一刻才意识到会话已经过期。3.2 场次、票档与座位的三层筛选逻辑抢票不能只盯着「有票」这个粗粒度状态。一场演出可能分了 180、580、980 三个票档每个票档的库存是独立的。脚本得先查票档再查指定票档的座位列表最后从可售座位里选一个。这个层层收敛的逻辑是这个项目的核心价值所在——人工手点之所以慢就是因为这三层信息需要逐个页面去看。class PerformFetcher: def filter_perform(self, stock_info, target_levels): levels stock_info[priceLevelList] matched [] for level in levels: if level[priceName] in target_levels and level[sellStatus] SOLD_OUT: continue matched.append(level) return matched def pick_seat(self, seat_map): # seat_map: {areaId: areaId, seatId: seatId, status: 0/1} for seat in seat_map: if seat[status] 1: # 1 表示可选0 表示已被锁定 return { areaId: seat[areaId], targetSeatId: seat[seatId], priceId: seat[priceId], } return Nonefilter_perform的过滤条件是目标票档在列表里且销售状态不是已售罄。这里有个容易翻车的地方SOLD_OUT是大麦网在 PC 端接口里的返回文案但 App 端可能是soldOut或者0。如果你拿到的是旧版脚本需要先打印一次接口返回的原始 JSON对着字段名改过滤条件。pick_seat只选status 1的座位这个逻辑在并发场景下其实不够稳。因为两个同时抢票的人可能选中同一个座位后提交的人会收到「座位已被锁定」的错误。所以更稳妥的做法是一次性拿多个可选座位放进列表下单失败时自动换下一个。这个改造不复杂把pick_seat的返回改成座位列表订单模块里加一个 for 循环就行我会在最后一章展开。3.3 下单请求的构造与防重提交订单提交是整个脚本里对参数最敏感的函数。字段多一个少一个后端都可能直接拒绝。按这套脚本的设计提交订单走的是 web 端 JSON 接口核心代码大致长这样class OrderSubmitter: def create_order(self, seat_info, buy_count1): url https://detail.damai.cn/api/order/create payload { itemId: seat_info[itemId], performId: seat_info[performId], seatInfo: [{ areaId: seat_info[areaId], seatId: seat_info[targetSeatId], priceId: seat_info[priceId] }], buyCount: buy_count, payType: 2, # 2 表示微信支付1 表示支付宝 extendInfo: {} } headers { Referer: fhttps://detail.damai.cn/item.htm?id{seat_info[itemId]}, Content-Type: application/json;charsetUTF-8, } resp self.session.post(url, jsonpayload, headersheaders) data resp.json() if data[code] 0: return {success: True, orderId: data[data][orderId]} return {success: False, msg: data[message]}参数说明seatInfo是列表结构意味着支持一次买多张连座buyCount要和seatInfo里的座位数量一致否则会报「购买数量与座位数不匹配」。payType的取值对应支付渠道很多脚本默认支付宝但如果你用的是微信钱包需要在 config 里改成 2。提交订单失败时要看的返回码也有讲究。code 0是成功code -10001通常是参数校验失败code 203大概率是座位冲突或者库存没了。这套脚本的作者会在日志里打印data[message]这是排查下单失败的关键线索比看状态码直接得多。还有一个细节提交订单的 Request Header 里的Referer必须是当前演出的详情页地址。有些脚本为了省事写死一个 Referer结果换一场演出就下单失败。改造时记得从配置里读item_id动态拼别写死。3.4 抢票结果通知从音频到桌面推送抢到票之后脚本必须立刻提醒你去支付否则订单会在十五分钟内自动失效。这个项目的通知模块很简单但很实用用的是 Windows 的 pywin32 弹窗和默认铃声import win32api, win32con import winsound def notify(show_name, order_id): winsound.Beep(1200, 1500) # 频率 1200Hz持续 1.5 秒 win32api.MessageBox( 0, f抢到票了订单号:{order_id}请尽快支付, show_name, win32con.MB_OK | win32con.MB_ICONWARNING )这个实现朴素但可靠MessageBox是模态的弹出来之后会阻塞主线程直到你点了确认。好处是你不可能错过通知坏处是脚本会暂停工作。不过抢到票之后脚本本来就该收工了阻塞反而安全避免你还在盯着屏幕的时候脚本又去下单买重复的票。如果要改造成手机通知常见做法是把 notify 函数里加一个 requests.post 调用往「钉钉机器人」或者「企业微信机器人」的 webhook 发消息代码量不超过五句。不推荐用个人的微信接口容易封号webhook 机器人是合法通道。4. 抢票常见问题排查风控拦截、接口失效与座位冲突4.1 现象脚本一运行就提示「非法请求」或直接跳滑块验证根因是请求的 HTTP 特征和真实浏览器差异过大。很多脚本直接用 requests 带了个User-Agent字符串就冲上去但服务器还能看 TLS 指纹、请求间的间隔、Cookie 的完整性。这属于反爬虫的基本判决不单看某一个值。解决不要绕过滑块而是别触发它。做法是先用 selenium 打开真实浏览器完成登录把这个 session 持有一个真实浏览器的所有上下文再用 requests 携带一模一样的 Cookie 去请求。同时把轮询间隔调成 0.5 秒以上加上随机抖动避免固定频率被统计出来。触发滑块之后大多数人会花半小时去补各种参数不如直接重启流程重新登录一次。4.2 现象页面显示有票但提交订单一直报「座位已锁定」这是并发场景下的经典问题。seatInfo 里那个座位是全局共享的资源你看到它可选的时候可能已经有三四个人同时提交了其中一个人先到先得其余人全部失败。解决不要只传一个座位。我一般会在 3.2 节的pick_seat里一次取出 5~10 个可选座位在create_order里按顺序逐个提交直到其中一个成功。这样把单点失败变成了批量重试。注意seatInfo和buyCount要配对买一张票就传一个座位别为了抢成功率买一堆没用的。4.3 现象Cookie 保存了但第二天跑脚本提示登录过期Cookie 过期是大麦网这类平台的常态尤其是扫码登录的会话服务端可以随时让你失效没有固定周期。脚本里如果只保存 Cookie 不校验有效期就会出现开抢前才发现登录态早没了的情况。解决在main.py的启动流程里加一次轻量校验请求个人信息接口看返回码。如果返回 401不要停下来让用户手动跑一次登录而是自动打开浏览器让用户扫码扫完自动继续原来的流程。我在项目里惯用的写法是if not session.validate(): session.login_by_qrcode()加到主流程最前面。4.4 现象换一台电脑或部署到服务器上脚本点击无反应这类脚本如果用了 selenium 模式Linux 服务器上没安装 Chrome 和对应的 chromedriver就会在启动浏览器这一步静默失败而且很多脚本对异常的处理是 pass日志里什么都看不到。解决先安装带无头模式支持的浏览器驱动然后给 ChromeOptions 加--headlessnew和--no-sandbox。同时注意 chromedriver 和 Chrome 的主版本号必须一致否则也会启动失败。我会写一个环境自检函数启动时打印 Chrome 和 chromedriver 的版本号不一致就直接退出不浪费时间排查。4.5 现象脚本跑通了但抢到的时间比手动还慢日志显示从开抢到下单成功花了三秒多其实比手点还慢。这个问题的根因一般是轮询节奏和下单链路之间有太多非必要操作例如每次轮询都重新请求一次演出详情页、每次都重新解析整个座位图 JSON。解决把不变量提前算好。场次 ID、演出 ID、票档 ID 这些都是开抢之前就固定的开抢后只需要轮询库存字段拿到库存后立刻带着预构造的 payload 去下单。检查你的脚本在perform.py里是不是有额外的time.sleep(1)或者打印整页 HTML 的调试代码这些全都该删掉。5. 本地跑通项目环境配置、依赖安装与一键开抢5.1 环境准备与依赖安装这个脚本依赖 Python 3.8 以上版本主要安装 requests、selenium、PyYAML、pywin32。项目里如果看到 requirements.txt直接一行命令搞定pip install -r requirements.txt如果没有 requirements.txt就手动安装pip install requests selenium pyyaml pywin32。pywin32 只有 Windows 上有意义macOS 和 Linux 下可以先注释掉 notify 模块里的相关导入不影响抢票主流程。Chrome 浏览器和 chromedriver 是两样必须同时存在的东西。我踩过的坑是下载了最新版 Chrome 但用了旧版 chromedriver启动就报session not created。先去chrome://version看你的浏览器版本号再按主版本号去官网找匹配的 driver。装完之后在命令行跑一句chromedriver --version验证一下能输出版本号才算配好。5.2 配置文件修改一场演出的全部参数打开 config.yaml里面需要填的核心参数就几项。我把必须填的字段列出来并且标注来源account: cookie_file: ./cookies.pkl # 登录状态保存路径 target: item_id: 289928883 # 演出ID详情页URL末尾的数字 perform_id: 183118021 # 场次ID点选具体场次后从接口抓 price_levels: [580, 780] # 想要的价格区间名称 start_time: 2026-06-18 15:00:00 strategies: poll_interval: 0.5 # 轮询间隔单位秒 retry_times: 8 # 下单失败重试次数price_levels这个字段要写票档的名称不是数字价格。有的演出会把 580 元票档命名为「580 看台」过滤时用的是包含关系匹配所以写「580」就够了不用精确匹配580 看台。item_id的来源很直接打开演出的详情页URL 后半段id后面的数字就是。perform_id是开票后才能从场次查询接口拿到的值写配置时可以先留空跑一次查询接口把返回的场次列表打印出来再做二次填充。5.3 从命令行到一键开抢配置填好后启动流程分两步。第一次运行先做登录第二次才是真正抢票。很多人在第一步就翻车——扫码登录的窗口只停留两分钟超时后 selenium 闪退然后就开始怀疑脚本有 bug。python main.py --login # 第一次运行完成扫码登录 python main.py # 正式抢票正式运行之后脚本会按 config 里的start_time进入等待态屏幕上没有太多输出这是正常的。到点之后开始高频轮询日志会从「等待开抢」变成「查询到库存准备下单」再到「提交订单成功订单号 xxx」。验证跑没跑通的最快方式是看数据库日志文件logs/run.log。如果里面每一行都有时间戳和字段名说明环境没问题如果只有一堆裸打印检查是不是从这解析的接口返回格式和预期不一致。这个脚本切到日志文件之后比开着命令行窗口盯输出要实用得多抢完票回头还能复盘每个环节花了多少毫秒。6. 二次开发指南多场次监控与自动重试的改造思路拿到这套脚本的人多数不会满足于只抢指定的一场演出。最值得做的改造有两个方向一是把单场次轮询变成多场次并发监控二是把人工处理验证码的逻辑接入一个自动识别库。多场次监控的核心是在 config 里把 target 改成数组然后用 Python 的ThreadPoolExecutor起两三个线程每个线程盯一个场次。这里不要为每个场次开独立请求会话所有线程共用同一个登录态否则容易触发账号级别的风控。我改造时用了session requests.Session()作为共享对象线程间不再单独登录效果明显抢票高峰期账号没有被踢下线过。验证码这块不少脚本把 ddddocr 接进来做图形验证码的自动识别。但根据我的实际体验大麦网 web 端虽然有验证码但出现的概率很低而且一旦出现往往是行为验证比如点选文字这种 ddocr 根本吃不下。我一般让验证码出现时通知我手动处理而不是让脚本自己硬解——硬解失败三次反而会被拉黑一段时间。重试逻辑的设计要克制。retry_times设 8 次的意思是同一场同一个座位提交失败后换下一个座位再试 8 次而不是 8 次都提交同一个座位。可以判断create_order的返回结果里如果是「座位冲突」立刻换pick_seat拿新座位如果是「参数错误」别重试了大概率是接口字段已经变了得回去抓包更新逻辑。检查改造是否有效的验证方法也很简单把 config 里的start_time改成当前时间往后推五分钟人为开一场测试观察日志里轮询→锁座→下单每个环节的耗时。我改完总喜欢跑一遍这个模拟流程再收工确保登录、选座、下单三步全通不然真到开票那一刻才发现字段失效就白等了。这是从血泪经验里学来的习惯——有一次我改完通知模块直接睡大觉第二天开抢发现下单接口的返回值结构变了日志里全是红色报错整整一周的热门演出都错过了。从那以后我每次上线前都强制走一遍 mock 流程验证完才敢关电脑。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑