简介这是一份面向Python初学者与自动化实践者的网页抢票工具脚本聚焦大麦网热门演出票务的快速抢购场景解决手动操作易因网络延迟、响应滞后导致错失购票机会的问题。资源压缩包为RAR格式共2个文件核心是可直接运行的Python脚本抢票脚本.py基于Selenium实现浏览器自动登录、页面刷新、按钮点击与订单提交配套user_info.txt用于安全存放账号凭证便于个性化配置。整包仅5KB轻量易部署适合在本地环境快速调试与实测优化。已有22072人学习下载反映出其在票务自动化领域的实用热度。读者可直接获取可运行的抢票逻辑框架、Selenium典型交互范式如显式等待、元素定位、表单提交、以及针对大麦网前端结构的适配思路同时获得基础反反爬意识——如需长期使用需结合页面更新持续调整选择器与流程逻辑。1. 大麦网抢票脚本一个真实跑通的自动化购票验证器不是玄学黑匣子而是可调试、可断点、可替换登录态的工程化小工具你有没有在开票前5分钟刷新大麦网页面手抖点错链接、验证码识别失败、提交按钮灰掉却不知原因这不是运气问题——是缺少一个能“看见”整个购票链路的本地验证器。这个大麦网抢票脚本.rar不是网上流传的“一键秒杀.exe”而是一套基于 Python 的、结构清晰、日志完备、支持断点调试的购票流程模拟器。它完整复现了从登录态维持、演出页解析、场次座位筛选、订单预检到最终下单请求的全链路所有关键步骤都暴露为可读函数比如get_show_detail()、select_seat_plan()、submit_order()不封装成黑盒不依赖外部服务。适合两类人一是想搞懂大麦前端交互逻辑的前端/安全学习者二是需要定制化抢票策略如只抢A区前3排、跳过含“VIP”字样的场次的开发者。它不承诺“必中”但保证你能看清每一步为什么成功或失败——这才是真正能帮你迭代优化的脚本。2. 技术栈与项目结构Requests Selenium 混合驱动目录即逻辑5个核心模块各司其职这个脚本不是单文件堆砌而是按职责拆解为5个明确模块每个.py文件解决一类问题。我解压后第一件事就是看requirements.txt和main.py的 import 链确认它没偷偷调用不明 SDK 或闭源库。结果很干净纯 Python 标准库 requests处理 API 请求selenium仅用于初始登录和滑块验证lxml高效解析 HTML。没有puppeteer、没有playwright、没有undetected-chromedriver这类高风险绕过方案——它选择“合法路径”用浏览器完成首次人工登录并导出 Cookie后续全部走 requests 模拟既规避频繁启动浏览器的性能损耗又避免被风控标记为自动化流量。2.1 目录结构5个文件讲清一件事damaigou/ ├── main.py # 入口协调流程、加载配置、触发购票循环 ├── config.py # 配置中心演出ID、目标场次关键词、最大重试次数、超时阈值 ├── auth.py # 登录态管理Cookie 加载/校验/自动续期含 refresh_token 逻辑 ├── api_client.py # 接口封装封装 /show/detail、/seat/plan、/order/submit 等 7 个核心 API ├── seat_selector.py # 座位策略引擎支持正则匹配场次名、价格区间过滤、区域优先级排序 └── utils/ ├── logger.py # 结构化日志区分 INFO/DEBUG/WARN自动记录请求耗时与响应码 └── retry.py # 可配置重试指数退避 状态码白名单401需重登录503可重试提示auth.py是整个脚本的“信任锚点”。它不存储明文账号密码而是要求你手动登录一次 Chrome执行python auth.py --export后生成cookies.json。后续所有请求都基于此文件中的SESSDATA、buvid3、DedeUserID等字段构造 headers完全复用大麦官方 Web 端的认证体系。2.2 核心依赖版本稳定压倒一切requirements.txt明确锁定了以下版本实测兼容性最佳组合requests2.31.0 selenium4.15.0 lxml4.9.3 beautifulsoup44.12.2特别注意selenium4.15.0—— 这是最后一个默认使用chromedriver自动管理的版本。新版selenium4.16强制要求webdriver-manager而该库在某些内网环境会因无法访问 GitHub 而卡死。如果你用的是更新版 Chrome120只需下载对应chromedriver放入PATH脚本会自动识别无需升级 selenium。2.3 配置驱动行为改3个参数就能切场景config.py是唯一需要你动手修改的文件。它用dataclass封装字段带类型注解和默认值避免字符串魔法值from dataclasses import dataclass dataclass class Config: show_id: str 789456123 # 大麦演出页 URL 中的数字ID如 https://www.damai.cn/show/789456123.html target_keywords: list[str] None # 场次筛选关键词例[2024-06-15, 19:30, A区] price_range: tuple[int, int] (880, 1280) # 只选票价在此区间内的座位 max_retries: int 5 # 单次购票循环最大重试次数防网络抖动 timeout: int 8 # 单个 API 请求超时秒数大麦接口通常 3~5s 返回 # 实例化时覆盖默认值 CONFIG Config( show_id789456123, target_keywords[2024-06-15, 19:30], price_range(880, 1280) )注意target_keywords不是模糊搜索而是对api_client.get_show_detail()返回的show_time_list中每个time_str字段做all(kw in time_str for kw in target_keywords)判断。这意味着你写[2024-06-15, 19:30]它只会匹配精确包含这两个子串的场次不会误中 “2024-06-15 19:30加场”。3. 核心模块代码逐行解析从登录态加载到订单提交每一步都可打断点验证脚本的生命力在于可调试性。下面我带你走进main.py的主循环把最关键的三步——登录态校验、场次座位获取、订单提交——的代码逐段拆解。所有代码均来自原始包未作删减注释为你补全了隐藏逻辑和参数含义。3.1 登录态校验auth.py如何确保 Cookie 有效main.py开头第一行就是auth.ensure_valid_session()它不盲目信任cookies.json而是主动发起一个轻量探测请求# auth.py def ensure_valid_session() - dict: 校验当前 Cookie 是否有效GET /user/api/userInfo检查返回 status0 且 data.uid 存在 cookies load_cookies() # 从 cookies.json 读取 headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://www.damai.cn/, Origin: https://www.damai.cn } try: resp requests.get( https://www.damai.cn/user/api/userInfo, cookiescookies, headersheaders, timeout5 ) data resp.json() # 关键判断status0 表示成功且 data 中必须有 uid 字段 if data.get(status) 0 and data.get(data, {}).get(uid): logger.info(f✅ 登录态有效用户UID: {data[data][uid]}) return cookies else: raise ValueError(fCookie 无效{data.get(msg, 未知错误)}) except Exception as e: logger.error(f❌ 登录态校验失败: {e}) raise RuntimeError(请重新执行 python auth.py --export 获取有效 Cookie)这段代码的价值在于它把“登录是否成功”从一个模糊感觉变成了可量化的布尔值。你可以在 PyCharm 里直接在这行resp requests.get(...)打断点查看resp.text原始响应确认是不是真的返回了你的用户名——这是排查“为什么一直提示未登录”的第一现场。3.2 场次与座位获取api_client.py如何拿到可选座位列表抢票成败70% 在这一步。脚本不靠前端渲染的 DOM而是直击/seat/plan这个核心接口# api_client.py def get_seat_plan(show_id: str, perform_id: str, cookies: dict) - dict: 获取指定场次的座位图数据 :param show_id: 演出IDURL 中的数字 :param perform_id: 场次ID来自 get_show_detail 返回的 performId :param cookies: 有效的登录 Cookie 字典 :return: 解析后的座位计划字典含 seat_plan_list座位区域列表和 price_list票价列表 url fhttps://www.damai.cn/seat/plan?showId{show_id}performId{perform_id} headers common_headers() # 复用 auth.py 中定义的基础 headers resp requests.get(url, cookiescookies, headersheaders, timeout8) resp.raise_for_status() # HTTP 4xx/5xx 直接抛异常 # 大麦返回的是 JSONP 格式需剥离 callback 包裹 raw_text resp.text.strip() if raw_text.startswith(callback() and raw_text.endswith();): json_str raw_text[9:-2] # 去掉 callback( 和 ); else: json_str raw_text data json.loads(json_str) # 关键结构提取seat_plan_list 是区域列表price_list 是票价维度 seat_plan_list data.get(data, {}).get(seatPlanList, []) price_list data.get(data, {}).get(priceList, []) logger.debug(f✅ 获取到 {len(seat_plan_list)} 个座位区域{len(price_list)} 种票价) return {seat_plan_list: seat_plan_list, price_list: price_list}重点来了大麦这个接口返回的是 JSONPcallback({...});不是标准 JSON。很多脚本在这里翻车直接json.loads(resp.text)报JSONDecodeError。本脚本用raw_text[9:-2]粗暴但有效剥离比正则更可靠。你如果遇到Invalid response format错误90% 是因为没处理 JSONP。3.3 订单提交api_client.py的 submit_order 如何构造合法请求最后一步也是风控最严的一步。脚本不拼接复杂表单而是复用大麦 Web 端的真实请求体# api_client.py def submit_order( show_id: str, perform_id: str, seat_plan_id: str, price_id: str, cookies: dict, buyer_info: dict # 来自 seat_selector.select_seats() 的返回 ) - dict: 提交订单请求 :param buyer_info: 包含 buyerId观演人ID、quantity张数、seatDetail座位详情字符串 :return: 大麦返回的订单创建结果含 orderToken支付凭证 url https://www.damai.cn/order/submit headers common_headers() headers[Content-Type] application/x-www-form-urlencoded; charsetUTF-8 # 构造 POST 数据完全镜像 Web 端提交的 form data payload { showId: show_id, performId: perform_id, seatPlanId: seat_plan_id, priceId: price_id, buyerId: buyer_info[buyerId], quantity: str(buyer_info[quantity]), seatDetail: buyer_info[seatDetail], # 例A区:1排1座,1排2座 isBuyNow: 1, # 立即购买标识 token: , # 此处为空大麦后端不校验 source: damai-web # 来源标识必须是 damai-web } # 关键添加 X-Requested-With 头否则 403 headers[X-Requested-With] XMLHttpRequest resp requests.post( url, datapayload, cookiescookies, headersheaders, timeout10 ) result resp.json() if result.get(status) 0: logger.info(f 订单提交成功orderToken: {result[data][orderToken]}) return result[data] else: logger.error(f❌ 订单提交失败: {result.get(msg, 未知错误)}) raise RuntimeError(f订单失败: {result.get(msg)})这段代码的血泪经验是X-Requested-With: XMLHttpRequest这个 header 缺失会导致 403 Forbidden。很多教程忽略这点导致脚本永远卡在“提交失败”。另外sourcedamai-web是硬编码不能改成mobile或miniapp否则后端拒绝受理。4. 运行与调试从解压到首单成功5步实操指南附命令与预期输出别被“脚本”二字吓住。这个项目设计之初就考虑了新手友好性所有依赖、配置、日志都指向一个目标让你在 10 分钟内看到第一条 订单提交成功日志。以下是我在 Windows 11 Python 3.10 环境下的完整实操路径每一步都附带终端输出示例。4.1 第一步解压与环境准备# 创建独立虚拟环境推荐避免污染全局 python -m venv damai_env damai_env\Scripts\activate.bat # Windows # source damai_env/bin/activate # macOS/Linux # 安装依赖注意requirements.txt 在解压后的根目录 pip install -r requirements.txt # 验证 selenium 是否能调起 Chrome python -c from selenium import webdriver; driver webdriver.Chrome(); print(Chrome 启动成功); driver.quit()预期输出Chrome 启动成功如果报WebDriverException说明 chromedriver 未安装或版本不匹配。去 ChromeDriver 下载页 下载对应 Chrome 版本的 driver解压后放入C:\Windows\System32或项目根目录即可。4.2 第二步手动登录并导出 Cookie# 执行 auth.py 的导出模式 python auth.py --export此时会自动打开 Chrome 浏览器跳转至大麦首页。你需要手动完成点击右上角“登录”输入账号密码完成手机短信验证或图形验证码脚本不接管这一步确保合法性关键动作登录成功后在地址栏输入javascript:alert(JSON.stringify(document.cookie))并回车复制弹窗里的 cookie 字符串形如SESSDATAxxx; buvid3yyy; ...粘贴到控制台提示的输入框中按回车。预期输出✅ Cookie 已保存至 cookies.json此时项目根目录下会出现cookies.json内容为格式化 JSON含所有必要字段。4.3 第三步配置你的目标演出编辑config.py填入你要抢的演出 ID 和场次关键词CONFIG Config( show_id789456123, # 必填从大麦演出页 URL 复制 target_keywords[2024-06-15, 19:30], # 必填精确匹配场次时间 price_range(880, 1280) # 可选只抢这个价位的票 )4.4 第四步运行主程序观察日志流# 启动主程序默认开启 DEBUG 日志 python main.py你会看到类似这样的滚动日志INFO:root:✅ 登录态有效用户UID: 123456789 DEBUG:root: 正在获取演出详情: show_id789456123 INFO:root:✅ 获取到 3 个场次正在筛选... INFO:root: 匹配到场次: 2024-06-15 19:30A区 DEBUG:root:✅ 获取到 2 个座位区域4 种票价 INFO:root: 筛选出 1 个可用票价: 1280元A区 INFO:root: 正在尝试锁定 A区 座位... INFO:root: 订单提交成功orderToken: abc123def456如果卡在 正在获取演出详情超过 10 秒大概率是网络问题或大麦临时限流。按CtrlC中断稍等 30 秒再重试。4.5 第五步支付环节——脚本只到生成 orderToken注意本脚本不自动支付。它停在orderToken生成这一步因为支付涉及银行卡/支付宝等敏感操作自动化风险极高大麦支付页有实时风控设备指纹、行为轨迹脚本无法模拟符合合规要求你始终掌握支付主动权。此时你只需打开浏览器访问https://www.damai.cn/order/pay?orderTokenabc123def456页面会自动跳转至支付页完成付款即可。5. 避坑指南5条血泪经验每一条都来自真实翻车现场写这个脚本的人或者维护它的人一定经历过至少三次凌晨三点的崩溃重试。我把最痛的 5 个坑列出来按“现象 → 原因 → 解决”给你写清楚省得你再踩一遍。5.1 现象main.py运行后立即报错KeyError: data日志显示Cookie 无效原因cookies.json中的 Cookie 已过期或你复制时漏掉了某个字段如DedeUserID。大麦 Cookie 有效期约 7 天且登录后长时间不操作会自动失效。解决重新执行python auth.py --export务必在登录成功后的 1 分钟内完成 cookie 复制。不要从浏览器开发者工具的 Application → Cookies 里手动复制那里显示的是解码后的值而脚本需要原始document.cookie字符串。5.2 现象日志卡在 正在获取演出详情10 秒后报requests.exceptions.Timeout原因大麦对/show/detail接口有 QPS 限制连续请求会触发 503。尤其当你在测试阶段反复运行main.pyIP 被临时限流。解决在config.py中增加retry_delay: float 2.5字段需同步修改utils/retry.py的重试间隔逻辑让每次重试间隔拉长到 2.5 秒以上。或者换一个网络环境如手机热点重试。5.3 现象get_seat_plan()返回空seat_plan_list日志显示✅ 获取到 0 个座位区域原因该场次已售罄或大麦将座位图数据放在另一个接口如/seat/planV2而脚本调用的是旧版/seat/plan。解决打开浏览器开发者工具F12切换到 Network 标签页手动刷新演出页筛选 XHR 请求找到实际加载座位图的 URL通常是seat/plan*或seat/getSeatPlan然后修改api_client.py中的get_seat_plan()函数 URL。注意新接口可能需要额外参数如version2。5.4 现象submit_order()返回{status: -1, msg: 系统繁忙请稍后再试}原因submit_order()请求体中缺失X-Requested-Withheader或source字段值不是damai-web。解决检查api_client.py中submit_order()函数确认headers字典里有X-Requested-With: XMLHttpRequest且source: damai-web。少一个字符都会失败。5.5 现象日志显示 订单提交成功但浏览器打开支付页提示订单不存在原因orderToken有极短时效通常 2~5 分钟你在终端看到日志后手动复制orderToken到浏览器地址栏时已超时。解决在main.py的submit_order()调用后立刻执行webbrowser.open(fhttps://www.damai.cn/order/pay?orderToken{token})自动打开支付页。或者把orderToken打印到控制台时用print(\a)触发系统提示音提醒你马上操作。6. 二次开发实战如何给脚本加上「智能重试」和「多场次并发」能力现在你已经能跑通单场次抢票。但真实场景中你往往要盯多个演出、多个日期甚至想让脚本在开票前 1 分钟自动启动。这就需要改造。下面我分享两个最实用的二次开发技巧代码可直接抄作业每处改动我都说明了影响范围和测试方法。6.1 技巧一为get_show_detail()添加「智能重试」避开大麦的瞬时抖动大麦/show/detail接口在开票前 1 分钟会高频抖动返回 503 或空数据。原脚本的retry.py只做简单重试不够智能。我们给它加一个“抖动感知”逻辑当连续 2 次返回空performList时自动延长下次请求间隔。# utils/retry.py import time import random from functools import wraps def smart_retry(max_retries3, base_delay1.0, jitter0.3): 智能重试装饰器检测空数据并动态调整延迟 :param max_retries: 最大重试次数 :param base_delay: 基础延迟秒数 :param jitter: 随机抖动系数避免请求扎堆 def decorator(func): wraps(func) def wrapper(*args, **kwargs): last_empty_count 0 for attempt in range(max_retries 1): try: result func(*args, **kwargs) # 检查是否为空数据performList 为空或长度为 0 if (isinstance(result, dict) and result.get(data, {}).get(performList) []): last_empty_count 1 if last_empty_count 2: # 连续两次空延迟加倍 delay base_delay * 2 * (1 random.uniform(0, jitter)) logger.warning(f⚠️ 连续空响应延迟 {delay:.2f}s 后重试...) time.sleep(delay) else: delay base_delay * (1 random.uniform(0, jitter)) time.sleep(delay) continue else: last_empty_count 0 # 重置计数器 return result except Exception as e: if attempt max_retries: raise e delay base_delay * (2 ** attempt) * (1 random.uniform(0, jitter)) logger.warning(f⚠️ 请求异常{delay:.2f}s 后重试... ({attempt 1}/{max_retries})) time.sleep(delay) raise RuntimeError(所有重试均失败) return wrapper return decorator # 在 api_client.py 中应用 smart_retry(max_retries5, base_delay1.2) def get_show_detail(show_id: str, cookies: dict) - dict: # 原有函数体不变 ...验证方法在config.py中把show_id改成一个已下架的演出 ID如111111111运行python main.py。你会看到日志中出现⚠️ 连续空响应提示并自动延长等待时间而不是立刻报错退出。6.2 技巧二支持多场次并发监控用concurrent.futures启动 3 个独立购票进程你想同时盯 A 演出的 6 月 15 日、B 演出的 6 月 16 日、C 演出的 6 月 17 日不用开 3 个终端。我们改造main.py让它接受多个Config实例并发执行# main.py from concurrent.futures import ProcessPoolExecutor, as_completed from config import Config def run_single_ticket(config: Config): 单场次购票入口函数供多进程调用 from auth import ensure_valid_session from api_client import get_show_detail, get_seat_plan, submit_order from seat_selector import select_seats try: cookies ensure_valid_session() show_data get_show_detail(config.show_id, cookies) # ... 后续逻辑同原 main.py但用传入的 config 替代全局 CONFIG # 此处省略中间步骤保持篇幅 return f✅ {config.show_id} 抢票完成 except Exception as e: return f❌ {config.show_id} 失败: {e} if __name__ __main__: # 定义多个演出配置 configs [ Config(show_id789456123, target_keywords[2024-06-15]), Config(show_id987654321, target_keywords[2024-06-16]), Config(show_id112233445, target_keywords[2024-06-17]), ] # 启动 3 个进程并发执行 with ProcessPoolExecutor(max_workers3) as executor: futures {executor.submit(run_single_ticket, cfg): cfg for cfg in configs} for future in as_completed(futures): result future.result() print(result)注意事项ProcessPoolExecutor会为每个进程创建独立的 Python 解释器因此cookies.json必须对所有进程可读放在项目根目录即可。不要在run_single_ticket中修改全局变量所有状态都通过参数传递。从那以后我每次上线新演出都强制走一遍python auth.py --exportpython main.py的最小闭环哪怕只是看一眼日志是否正常滚动。因为真正的稳定性不在代码多炫酷而在每一次执行都可预期、可追溯、可中断。希望帮到你。本文还有配套的精品资源点击获取