Python+Selenium自动抢票脚本实战:大麦网抢票工具源码解析
简介这是一份面向Python爬虫与自动化爱好者的「大麦网自动抢票工具」源码包针对热门演出票务紧张、手动抢票效率低的问题提供了一套可运行、可二次开发的自动化购票实现方案适合具备一定Python基础、希望学习浏览器自动化与并发请求的开发者参考。压缩包共6个文件以1个py主程序、1个json配置文件、1个md说明文档和3张png示意图为主整体约24KB结构精简便于快速定位核心逻辑。目前已有32995人学习下载热度较高。通过阅读源码读者可以了解Selenium等浏览器自动化工具如何模拟点击、输入与提交订单理解多线程与异步处理在提升抢票效率中的作用并接触验证码识别、IP代理池、异常重试等常见工程思路配置文件则展示了账号、演出偏好等参数的存储方式为改造或自建类似工具提供实践基础。1. 抢票这件事手速真不如脚本稳去年帮朋友抢一场演出票开票前五分钟我就把手机架好了倒计时归零的瞬间猛戳屏幕结果页面卡了半秒再刷新已经全是“缺货登记”。后来我换了个思路用 Python 写了个自动抢票工具把“点击—提交—确认”这条链路交给程序去跑成功率肉眼可见地往上走。这个项目就是围绕大麦网这类票务平台的抢票场景做的自动化工具核心是用 Selenium 驱动浏览器完成登录、选场次、选票档、提交订单这一整套动作再配合定时刷新和异常重试来对抗开票瞬间的高并发。它适合两类人一类是想拿它直接抢票的普通用户另一类是想学 Web 自动化实战、拿它当练手项目的开发者。下面我按“能干什么—怎么跑—怎么改”的顺序把这份源码拆开讲清楚。2. 项目定位与技术选型为什么是 Selenium 而不是纯 requests2.1 抢票场景对技术栈的真实要求抢票工具和普通爬虫最大的区别在于它要完成的是“有状态的操作序列”而不是单纯拉数据。你得先登录登录后拿到会话再进详情页选场次、选票档、勾选观演人、提交订单每一步都依赖上一步的页面状态。纯 requests 当然也能模拟但大麦网的页面交互大量依赖 JavaScript 渲染请求参数里还夹着动态 token 和加密字段逆向成本极高而且平台一改前端逻辑你就得跟着重写。Selenium 的优势在这里就体现出来了它直接驱动真实浏览器页面怎么渲染、按钮怎么点程序就怎么操作相当于把“人手操作”翻译成代码。代价是速度比纯请求慢但在抢票这个场景里稳定性比极限速度更重要——你请求发得再快参数算错了照样提交失败。所以这个项目选 Selenium 是合理的常见做法是配合 ChromeDriver 或无头模式来跑。2.2 核心依赖与目录结构项目依赖不复杂主要是这几块# 核心依赖 selenium # 浏览器自动化驱动 webdriver-manager # 自动匹配并下载对应版本的浏览器驱动 pyyaml # 读取配置文件场次、票档、观演人等信息 loguru # 日志记录方便排查抢票失败原因目录结构大致是这样我按功能做了拆分ticket-grabber/ ├── config/ │ └── config.yaml # 抢票参数配置场次、票档、数量、观演人 ├── core/ │ ├── browser.py # 浏览器初始化与驱动管理 │ ├── login.py # 登录模块支持扫码/账号两种方式 │ ├── grab.py # 抢票主逻辑选场次、选票档、提交 │ └── retry.py # 重试与异常处理 ├── utils/ │ ├── logger.py # 日志封装 │ └── timer.py # 定时器控制开抢时间 ├── main.py # 入口串联整个流程 └── requirements.txt这个结构的好处是职责清晰browser.py只管浏览器生命周期login.py只管登录grab.py只管抢票动作改哪块都不影响其他模块。二次开发时你大概率只需要动config.yaml和grab.py。2.3 配置文件驱动的设计思路把场次、票档、观演人这些易变信息抽到 YAML 里是为了不改代码就能换目标。配置长这样# config/config.yaml target: url: https://detail.damai.cn/item.htm?idxxxxx # 演出详情页 session: 2024-12-31 19:30 # 目标场次按页面文本匹配 price: 680 # 目标票档按价格文本匹配 quantity: 1 # 购买数量 viewers: # 观演人姓名需提前在账号里添加 - 张三 timing: start_time: 2024-12-25 12:00:00 # 开抢时间 advance_seconds: 2 # 提前几秒开始刷新 retry: max_attempts: 50 # 最大重试次数 interval: 0.3 # 重试间隔秒参数说明session和price用的是页面文本匹配而不是写死索引因为不同演出的场次和票档数量不一样用文本匹配更通用advance_seconds设成 2 秒是为了抵消网络延迟让程序在开票瞬间正好处于刷新状态interval别设太小0.3 秒左右比较稳设成 0.05 容易被平台风控盯上。3. 核心模块拆解从登录到提交订单的完整链路3.1 浏览器初始化与反检测处理Selenium 最容易被识别的地方是navigator.webdriver这个属性默认情况下它会是true平台一检测就知道你是脚本。所以初始化时要做一些处理# core/browser.py from selenium import webdriver from selenium.webdriver.chrome.options import Options from webdriver_manager.chrome import ChromeDriverManager from selenium.webdriver.chrome.service import Service def init_browser(headlessFalse): options Options() # 去掉自动化特征 options.add_argument(--disable-blink-featuresAutomationControlled) options.add_experimental_option(excludeSwitches, [enable-automation]) options.add_experimental_option(useAutomationExtension, False) if headless: options.add_argument(--headlessnew) options.add_argument(--window-size1920,1080) options.add_argument(--user-agentMozilla/5.0 ...) service Service(ChromeDriverManager().install()) driver webdriver.Chrome(serviceservice, optionsoptions) # 注入脚本抹掉 webdriver 标记 driver.execute_cdp_cmd( Page.addScriptToEvaluateOnNewDocument, {source: Object.defineProperty(navigator, webdriver, {get: () undefined})} ) return driver逻辑说明--disable-blink-featuresAutomationControlled关掉 Chrome 的自动化控制提示excludeSwitches去掉顶部那条“Chrome 正受到自动测试软件控制”的横幅最关键的是最后那段 CDP 注入它在每个新页面加载前执行把navigator.webdriver改成undefined。参数上headless建议调试时设False能看到页面操作过程正式抢票再开无头模式省资源。3.2 登录模块扫码登录比账号密码更省心登录这块我踩过坑。最早用账号密码自动填充结果平台弹了滑块验证脚本直接卡死。后来改成扫码登录程序打开登录页把二维码截图保存到本地人工扫一下程序轮询检测登录状态登录成功后继续跑。这样既绕开了验证码又不用把账号密码写进配置里。# core/login.py import time from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def login_by_qrcode(driver, timeout120): driver.get(https://passport.damai.cn/login) # 等待二维码出现并截图 qr WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.CLASS_NAME, qrcode-img)) ) qr.screenshot(qrcode.png) print(请扫描 qrcode.png 完成登录) # 轮询检测登录成功标志比如用户昵称出现 end time.time() timeout while time.time() end: if driver.find_elements(By.CLASS_NAME, user-nick): print(登录成功) return True time.sleep(1) raise TimeoutError(登录超时请重新运行)逻辑说明WebDriverWait显式等待二维码元素出现比time.sleep硬等靠谱截图后人工扫码程序用轮询代替固定等待扫完一秒内就能继续。参数timeout给 120 秒够你从容扫码。这里注意一点登录成功后浏览器会话要复用别关掉重开否则登录态就丢了。3.3 抢票主逻辑定时刷新 文本匹配选档这是整个项目的核心。思路是到开抢时间前开始循环刷新详情页一旦目标场次和票档可点击立刻选中并提交。# core/grab.py import time from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC def grab_ticket(driver, cfg): driver.get(cfg[target][url]) wait WebDriverWait(driver, 5) for attempt in range(cfg[retry][max_attempts]): try: # 1. 选场次按配置文本匹配 session_el driver.find_element( By.XPATH, f//*[contains(text(), {cfg[target][session]})] ) session_el.click() # 2. 选票档 price_el driver.find_element( By.XPATH, f//*[contains(text(), {cfg[target][price]})] ) price_el.click() # 3. 选数量并提交 buy_btn wait.until( EC.element_to_be_clickable((By.CLASS_NAME, buy-link)) ) buy_btn.click() print(f第 {attempt1} 次尝试提交成功) return True except Exception as e: # 元素没出现说明还没开票或已售罄刷新重试 time.sleep(cfg[retry][interval]) driver.refresh() return False逻辑说明用 XPath 的contains(text())做文本匹配比按索引定位稳因为页面元素顺序可能变每次失败后refresh()重新加载模拟人工不断刷新的动作。参数max_attempts和interval从配置读抢热门票可以设 50 次、0.3 秒间隔。这里有个细节提交订单后还会弹出观演人确认页需要再勾选观演人并点最终确认这段逻辑我放在grab.py后半部分思路一样都是等元素可点击再操作。3.4 定时器与异常重试开抢时间要卡准早刷新没用晚刷新票没了。定时器负责在指定时间点触发抢票# utils/timer.py import time from datetime import datetime def wait_until(target_time_str, advance_seconds2): target datetime.strptime(target_time_str, %Y-%m-%d %H:%M:%S) while True: now datetime.now() delta (target - now).total_seconds() if delta advance_seconds: print(到达预定时间开始抢票) return # 距离远时睡久点临近时精细等待 time.sleep(min(delta - advance_seconds, 1))逻辑说明advance_seconds让程序提前两秒进入抢票循环抵消网络往返延迟time.sleep取min(..., 1)是为了临近开抢时把等待粒度降到 1 秒以内避免睡过头。重试逻辑则包在grab_ticket的循环里配合日志记录每次失败原因方便事后看是没开票还是被风控了。4. 避坑与常见问题那些让我重跑好几遍的坑4.1 元素定位失效报 NoSuchElementException现象脚本跑起来就报找不到元素明明页面上肉眼能看到。原因通常是页面还没渲染完或者元素在 iframe 里。解决把find_element换成WebDriverWait显式等待给 5 到 10 秒超时如果元素在 iframe 内先driver.switch_to.frame()切进去再找。我一般会在关键定位前加一句等待宁可慢一点也别直接崩。4.2 登录态丢失每次都要重新扫码现象抢票循环里刷新几次后跳回登录页。原因是driver.refresh()在某些情况下会重置会话或者平台检测到异常行为踢下线。解决刷新用driver.get(current_url)代替refresh()并且控制刷新频率别太密另外把登录后的 cookies 存下来掉线时用driver.add_cookie()恢复能省一次扫码。4.3 被风控拦截页面提示操作过于频繁现象跑一会儿就弹出验证或直接拒绝访问。原因是请求频率太高、行为太机械。解决把interval调到 0.3 秒以上在刷新之间加随机抖动比如time.sleep(0.3 random.random() * 0.2)并且别用无头模式跑太久适当模拟鼠标移动。血泪经验是越急越容易被拦稳一点反而成功率高。4.4 提交订单后卡在观演人确认页现象票档选好了点提交后停在确认页没往下走。原因是确认页的观演人需要手动勾选脚本没处理这一步。解决在提交后增加一段逻辑等待观演人列表出现按配置里的姓名勾选对应复选框再点最终确认按钮。注意观演人必须提前在账号里添加好脚本只能勾选不能新增。4.5 驱动版本不匹配浏览器起不来现象报SessionNotCreatedException提示驱动和浏览器版本不符。原因是本地 Chrome 自动更新了但 ChromeDriver 还是旧版。解决用webdriver-manager自动匹配版本它会检测本地浏览器版本并下载对应驱动省去手动对照的麻烦。如果还不行检查 Chrome 是不是装在默认路径非默认路径要手动指定binary_location。5. 二次开发与改造把工具改成你自己的形状5.1 从单账号到多账号并发现在这套代码是单账号串行跑的如果你要帮几个人一起抢最直接的改法是引入多线程每个账号一个 driver 实例。但要注意Selenium 的 driver 不是线程安全的别共用一个实例。我一般会写一个GrabWorker类把 driver 和配置封装进去用threading.Thread起多个 worker各自独立登录、独立抢票。改造时把main.py里的单次调用换成线程池提交日志里带上账号标识方便区分。# 多账号并发示意 import threading class GrabWorker(threading.Thread): def __init__(self, account_cfg): super().__init__() self.cfg account_cfg def run(self): driver init_browser(headlessTrue) try: login_by_qrcode(driver) wait_until(self.cfg[timing][start_time]) grab_ticket(driver, self.cfg) finally: driver.quit() # 启动 for cfg in account_configs: GrabWorker(cfg).start()参数说明每个 worker 独立持有driverfinally里确保退出避免进程残留。线程数别开太多三到五个比较合适再多容易触发平台风控。5.2 用配置热加载减少重启调试阶段最烦的是改个票档就要重启脚本。可以在grab_ticket循环里加一段配置重载逻辑每次刷新前检查config.yaml的修改时间变了就重新读取。这样抢票过程中你还能临时换票档不用中断程序。实现上用os.path.getmtime对比时间戳即可几行代码的事但省下的重启时间很可观。5.3 验证改造是否生效的方法改完别直接上真实抢票先拿一场不热门的演出做全流程演练把start_time设成当前时间往后一分钟跑一遍看能不能走完登录、选场次、选票档、提交、确认观演人这条链路。日志里每一步都打上时间戳方便看哪一步耗时最长。我习惯在grab.py每个关键动作后加一行logger.info出问题时对着日志就能定位是定位失败还是点击失败。5.4 一个容易忽略的细节页面文本的空白字符文本匹配时页面上的场次文字可能带前后空格或换行直接contains(text(), 2024-12-31 19:30)有时匹配不到。稳妥做法是用normalize-space()处理//*[contains(normalize-space(text()), ...)]。这个坑我踩过一次明明页面上有这行字脚本就是说找不到查了半天才发现是空格问题。从那以后我每次写 XPath 文本匹配都强制走一遍normalize-space再也没翻过车。希望这个工具和这些改造思路能帮到你抢票顺利。本文还有配套的精品资源点击获取

相关新闻

Python+Selenium自动抢票脚本源码解析:登录态维持与定时触发实战

Python+Selenium自动抢票脚本源码解析:登录态维持与定时触发实战

简介:这是一份面向Python爬虫与自动化爱好者的大麦网自动抢票工具源码包,适合具备一定编程基础、希望研究浏览器自动化与购票流程模拟的开发者学习参考。资源围绕热门演出票务紧张场景,通过自动刷新页面、填写购票信息并提交订单来提升抢票效…

2026/10/18 20:55:23 阅读更多 →
五引擎微内核:AI平台底层架构设计与工程实践

五引擎微内核:AI平台底层架构设计与工程实践

1. 为什么我会把 AI 平台的底座设计成"五引擎微内核"先说一个我很早就有的判断:AI 平台真正难的不是算法,不是模型训练,而是平台本身。尤其当你需要把调度、安全、研判、评测、存证这五件事同时做好,还要求它经得起工程…

2026/10/18 20:55:23 阅读更多 →
挖到宝!用 TaoToken 统一 Key 替代 MotionSites.ai + Jiro.build 的网页动效提示词工作流

挖到宝!用 TaoToken 统一 Key 替代 MotionSites.ai + Jiro.build 的网页动效提示词工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 20:54:22 阅读更多 →

最新新闻

CANN开源科学算子:化工计算热点百倍提速实践

CANN开源科学算子:化工计算热点百倍提速实践

在化工研发里,最磨人的事情往往不是合成实验翻车,而是等计算。一个几十个原子的催化剂簇模型,用量化软件跑单点能,通宵排队是家常便饭;一条几百纳秒的分子动力学轨迹,更是动辄在机房蹲上一周。问题通常不是…

2026/10/18 21:58:19 阅读更多 →
NX二次开发:BlockUI选择对象控件程序组过滤实战指南

NX二次开发:BlockUI选择对象控件程序组过滤实战指南

做NX二次开发的朋友,十个里有八个会在“选择对象”控件上摔跟头。对话框一打开,用户想点什么就能点什么,明明是做加工仿真的工具,他给你框选了一堆辅助曲线和基准平面,后处理一跑,整个程序全乱套。我最早做…

2026/10/18 21:58:19 阅读更多 →
基于超表面的OAM涡旋光束产生:从几何相位到FDTD仿真全流程解析

基于超表面的OAM涡旋光束产生:从几何相位到FDTD仿真全流程解析

如果你做的课题里需要一个能稳定产生轨道角动量(OAM)涡旋光束的元件,第一反应多半是空间光调制器或者螺旋相位板。但等你真把它们放进系统里就会意识到两个问题:一是体积和光路调试成本都不小,二是它们对入射偏振态往往…

2026/10/18 21:58:19 阅读更多 →
深入理解C++ 容器 之 红黑树

深入理解C++ 容器 之 红黑树

std::map 的底层是**红黑树(Red-Black Tree)**,一种自平衡的二叉搜索树。理解红黑树,就理解了 std::map 为什么能同时提供**有序遍历**和**O(log n)** 的查找、插入、删除。下面从“为什么选它”讲到“它怎么工作”,最…

2026/10/18 21:58:19 阅读更多 →
32.完整的模型验证套路

32.完整的模型验证套路

一、模型验证套路(CIFAR数据集) 如果模型训练好了,那么就可以对外提供实际的应用了。 下面我们要做一个完整的 ‌PyTorch 模型推理(预测)流程‌。它的主要目的是:加载一张图片,使用预先训练好的…

2026/10/18 21:58:19 阅读更多 →
Tomcat 8 启动失败排查指南:JDK兼容、配置陷阱与日志诊断

Tomcat 8 启动失败排查指南:JDK兼容、配置陷阱与日志诊断

简介:本资源为 Apache Tomcat 8 官方二进制发行版(v8.0.32)的完整本地镜像包,面向 Java Web 开发初学者、后端工程师及教学实践者,用于快速搭建本地 Servlet/JSP 运行环境,解决开发调试中依赖官方下载慢、网…

2026/10/18 21:57:18 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →