从 0 到提交订单如何完整跑通大麦抢票:ticket-purchase 双端方案实操指南
【免费下载链接】ticket-purchase大麦自动抢票,支持人员、城市、日期场次、价格选择项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase
ticket-purchase 是一个开源的大麦自动抢票项目 🎫:移动端用 Appium 驱动大麦 APP,Web 端用 Selenium 操控 Chrome,两端各自独立配置、独立运行,支持按观演人、城市、日期场次、价格选择下单,并用原生坐标点击加内置重试机制来抢开售瞬间。整条链路按四步串起来:选路 → 备环境 → 改参数 → 启动验证。
先选抢票路线:APP 端是主链路,Web 端做备选
这一节回答开工前的第一个问题:票到底该用哪端抢。
仓库里是两套互不依赖的实现:damai_appium/ 管移动端,damai/ 管 Web 端,配置和流程各走各的。
为什么 APP 端是主链路?项目笔记里写得很直白:大麦的大部分票只能在 APP 里买,Web 端只是有 PC 详情页时的备选路线。目标场次在 APP 里有购买入口的话,直接走移动端。
两端也能同时上:同一场次,手机上跑 APP 端,电脑上跑 Web 端,谁先出单算谁的。
三条命令搭好 Appium 抢票环境
这一节覆盖抢票前必须敲完的三件事:克隆仓库、装 Python 依赖、装 Appium。
硬件和系统要求不高,卡在软件版本上:Python 3.9+;Node.js 必须是 20.19.0+、22.12.0+ 或 24.0.0+(Appium 是 Node 程序,版本不够会直接拒绝启动);Appium 3.1.0+,还要装配套的 UiAutomator2 驱动;真机或模拟器用,都得把 Android SDK 的环境变量 ANDROID_HOME / ANDROID_SDK_ROOT 配好。
先克隆仓库、装依赖:
git clone https://gitcode.com/GitHub_Trending/ti/ticket-purchase cd ticket-purchase pip install -r damai/requirements.txtdamai/requirements.txt 把 selenium 锁在 4.18.1;仓库根目录还有 pyproject.toml 走 Poetry 管理,用poetry install也可以。
再装 Appium 本体和驱动:
npm install -g appium appium driver install uiautomator2最后验证设备:adb devices输出里要能看到你的模拟器或真机。也可以先跑根目录的 check_environment.sh 做一键自检。
Web 端这边要求最少:装最新版 Chrome 就行,ChromeDriver 由 damai/check_environment.py 在构造浏览器时自动检查获取,不用手动管。
两分钟配好双端参数
这一节解决"两份配置到底改哪里",改完一场演出不用再动。
移动端就一个文件:damai_appium/config.jsonc,最小示例:
{ "server_url": "http://127.0.0.1:4723", "keyword": "周深", "users": ["观演人1", "观演人2"], "city": "深圳", "date": "12.06", "price": "内场1199元", "price_index": 5, "if_commit_order": true }| 字段 | 作用 | 什么时候改 |
|---|---|---|
server_url | Appium 服务器地址 | 启动端口不是 4723 时 |
keyword | APP 搜索关键词 | 换演出时(先手动搜进详情页) |
users | 观演人名单,人数即票数 | 观众有变时 |
city | 演出城市 | 与页面城市按钮文本对齐 |
date | 演出日期 | 与详情页场次对齐 |
price | 票价描述 | 与price_index指向的位置保持一致 |
price_index | 第几个票价按钮的位置,从 0 数 | 票档位置一变就必须重数 |
if_commit_order | 是否自动提交订单 | 想空跑验证流程时设为 false |
有个坑要提前说:config.py 的加载逻辑按固定键名逐字段取值,八个字段一个都不能少,缺一个直接 KeyError,所以改键名、动顺序都会出问题。
price_index 是人工数出来的位置
这个字段是移动端最反直觉的一个,值得单独说清来历。
大麦 APP 某次更新后,票价按钮在页面上的文本 Text 变成了空串"",旧版"按文本找按钮"的做法整体失效。V2 版换了思路:在票价容器里按索引找第 N 个可点击的 FrameLayout,N 就是price_index。
代价是得人工在界面上数:打开详情页,从左到右看目标票档排第几个(从 0 起数),把数字写进配置。票档位置变了(加场次、加票档)就会点错,必须重数。首次直接定位失败时还有一层备用方案:先用 WebDriverWait 等票价容器出现再重试一次。
Web 端 config.json:场次和票档都能写成列表
Web 配置在 damai/config.json,字段比移动端多,写法也不一样。
必填的四个:index_url(大麦首页,首次扫码登录用)、login_url(登录页)、target_url(目标演出详情页地址)、users(观演人名单,不能为空,人数决定票数)。
真正灵活的是两个列表:dates放多个场次日期,prices放多个票面价,脚本按你写的顺序逐个尝试,遇到标着"缺""售罄"的票档自动跳过——等于把候补场次和候补票档都堆进去,买到第一个有货的为止。
if_listen是"缺货登记"按钮的开关,代码直接读这个键,不能省;if_commit_order决定要不要自动提交订单;max_retries默认 1000 次;fast_mode默认开启,把各步等待从 0.5 秒级压到 0.1–0.2 秒级并跳过大量页面扫描输出;page_load_delay默认 2 秒,管订单确认页的加载等待。
进流程前 damai.py 会先做三道校验:文件存在、四个必填字段齐全、users非空,任何一条不过就打印模板直接退出,所以第一次跑报的错多半在这一步。
大麦抢票成功的三步:从启动服务到提交订单
这一节是全部流程里唯一需要背的操作序列:一个终端起 Appium,手机手动进详情页,一条命令跑脚本。
APP 端:先手动进详情页,再交给脚本接管
第一步,启动 Appium,注意加--relaxed-security:
appium --address 0.0.0.0 --port 4723 --relaxed-security这个参数解锁了脚本重度依赖的"原生点击手势"——不走常规点击通道,直接朝坐标落指。
第二步,手机上打开大麦 APP,搜到目标演出,停在详情页。V2 特意删掉了输入搜索的步骤,脚本从详情页开始接管:选城市 → 点预约/购买按钮 → 按索引点票价 → 有数量栏时把加号点(票数 − 1)次、每次间隔 20 毫秒 → 确定购买 → 批量勾选观演人 → 按"立即提交"。每一步都带备用选择器:城市会依次试精确文本、包含文本、XPath 三种写法,提交按钮先按"立即提交"文本、再试"提交/确认"正则、最后 XPath 兜底。
第三步,执行脚本:
cd damai_appium python damai_app_v2.py入口 run_with_retry() 默认试 3 次:失败会打印本轮耗时,关闭并重建驱动,隔 2 秒再试;想多试几轮就调大 max_retries。也可以用根目录的 ./start_appium.sh 和 ./start_ticket_grabbing.sh 两个快捷脚本,但它们把作者本机的 Android SDK 路径和 Python 路径写死了,换机器先改这两处。
Web 端(Selenium 抢票):扫码一次,之后自动轮询票档
在 damai 目录下运行cd damai && python damai.py。链路是:配置校验 → 加载参数 → 建浏览器(顺带自动检查 ChromeDriver)→ 进详情页 → 开轮询。
登录走 Cookie:首次运行时打开首页引导扫码,成功后把 Cookie 存进 damai_cookies.pkl;之后从文件恢复、只注入 .damai.cn 域,不用第二次扫码。
进详情页后,脚本先按 URL 是否含 m.damai.cn 区分移动/PC 页面,再按"城市 → 场次 → 票价 → 数量"的顺序依配置选;随后进入轮询循环等购买按钮亮起来,依次识别"立即预订""立即购买""选座购买""缺货登记"(最后一种受 if_listen 开关控制),并处理两种特殊状态:"提交缺货登记"(刷新目标页等开售)和弹窗里的"不,立即预订"链接。如果跳到选座页,脚本会喊"请快速选择您的座位!!!",你手动点完座位,它自动点确认。
提交订单做了四重容错:按钮文本(立即提交、提交订单、提交、确认、立即支付、去支付、支付)→ view-name 属性 → class 名(submit-button、bui-btn-contained 等)→ 原始 XPath,全失败才提示手动点。成功后页面停留 5 分钟,方便你当场核对订单和支付。
大麦自动抢票脚本怎么省时间:原生点击与批量坐标点击
这一节解释移动端脚本为什么比手动点快,以及它拿什么做了交换。
最大的收益在点击层。常规 Appium 的 element.click() 要先等元素进入"可点击"状态,脚本不等:ultra_fast_click 只等元素出现,立刻取 rect 中心坐标,调原生手势 mobile: clickGesture 落点,时长 50 毫秒;勾观演人更狠,ultra_batch_click 先把所有勾选框坐标一口气收集齐,再连续点击,单次时长 30 毫秒、点击之间只留 10 毫秒——对应项目笔记里"收集坐标信息,几乎一次性全部点击"。
驱动层把等待也整体调空:waitForIdleTimeout、actionAcknowledgmentTimeout、keyInjectionDelay 全部置 0,waitForSelectorTimeout 从 500 毫秒压到 300 毫秒;元素等待用 2 秒的 WebDriverWait 顶掉旧的 5 秒隐式等待;capabilities 里还关了窗口动画、把截图帧率降到 1。
代价同样明显:等待普遍变短,单步失败率上升,所以健壮性整体交给了前面说的重试机制——速度优先,失败重建。
顺带点一下最常改的位置:演出参数在 damai_appium/config.jsonc 和 damai/config.json 两份配置里;damai_appium/damai_app_v2.py 的 capabilities 写死了deviceName: "emulator-5554"和platformVersion: "16",真机或其他版本模拟器必须改这两行;根目录两个 .sh 是启动入口,同样带作者本机路径。
抢票报错 30 秒排查:症状-原因-动作速查
这一节把运行脚本时最常见的坑收成一张表,照症状对动作,不用通读文档。
| 症状 | 最可能的原因 | 先做什么 |
|---|---|---|
Node version must be at least ^20.19.0 \|\| ^22.12.0 \|\| >=24.0.0 | Node 版本太老,Appium 拒绝启动 | 用 brew upgrade node 升到任一兼容版本 |
Neither ANDROID_HOME nor ANDROID_SDK_ROOT ... exported | Android SDK 环境变量没导出 | 在终端 export 两个变量,或写进 shell 配置 |
Unable to find an active device or emulator | 没连设备,或脚本里写死的设备信息与真机不符 | adb devices看设备在不在;开 USB 调试;核对 capabilities 的 platformVersion 与 deviceName |
Connection refused(4723 端口) | Appium 没起或端口被占 | curl http://127.0.0.1:4723/status验活,server_url与启动端口对齐 |
| 票价按钮定位不到 | APP 改版动票档布局,或price_index数错了 | 打开详情页重数目标票档位置(从 0 起),更新配置 |
三条常用自检命令:adb devices确认设备在线;adb shell getprop ro.build.version.release和adb shell getprop sys.boot_completed确认系统版本与开机完成;adb shell pm list packages | grep damai确认大麦包 cn.damai 已装(启动入口 .launcher.splash.SplashMainActivity,与脚本 capabilities 一致)。
最后三句提醒:遵守大麦的使用条款,建议用专门的测试账号;网络要稳,开售前就让脚本处于运行状态;页面资源 ID、设备版本、票价索引全是硬编码,大麦改版后第一反应应该是重新校准 price_index 与选择器。预约场景暂未支持,目前只覆盖购买。
【免费下载链接】ticket-purchase大麦自动抢票,支持人员、城市、日期场次、价格选择项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考