ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

大麦自动抢票从零上手:Appium 安卓链路一次跑通到提交订单

大麦自动抢票从零上手:Appium 安卓链路一次跑通到提交订单

大麦自动抢票从零上手:Appium 安卓链路一次跑通到提交订单

【免费下载链接】ticket-purchase大麦自动抢票,支持人员、城市、日期场次、价格选择项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase

抢一张热门票最难的不是"打开 App",而是开售那一秒内连续点掉七步:选城市、点购买、选票档、设数量、勾观演人、提交订单——手快的人靠肌肉记忆,脚本靠的是把这条链路固化成一段可重跑的 Python。ticket-purchase 干的就是这件事:你把手机停在演出详情页,开售时刻由脚本接管后面所有点击,你只管看结果。

先懂原理:Appium 安卓链路是怎么替你点屏的

在装任何东西之前,先花两分钟搞清楚"它凭什么能自己点",后面排错会顺很多。这条链路只有三个角色,各管一段:

角色是什么在这条链路里负责什么
大麦 App(包名cn.damai)你手机上装的购票 App真正的页面在这里:城市、场次、票档、提交按钮,全部渲染在它内部
Appium架在电脑和手机之间的"遥控器"监听4723端口,把脚本说出的"点这里"翻译成设备能执行的触摸事件
ADB(Android 调试桥)安卓官方的设备通信通道负责电脑↔手机的底层握手:App 装没装、设备在不在线,都由它确认

串起来是这样一条传送带:Python 脚本发出指令 → Appium 服务(跑在你电脑上)接收 → 通过uiautomator2驱动下发 → 经由 ADB 打到手机 → 在大麦 App 的界面元素上落下一次真实触摸。所以它"自己点"不是玄学,而是它先找到目标控件在屏幕上的坐标,再按坐标点下去。理解了这一点,你就明白后面每个报错基本都是这条传送带的某一环断了。

零基础备料:一键自检 + 真机账号门槛

克隆下来第一件事不是跑脚本,而是自检。仓库里带了 check_environment.sh,它会逐项核对 Python、Node.js、Appium、Android SDK、ADB、设备连接和配置文件,每一项给出 ✅ 或 ❌,把缺的补上再进下一步:

git clone https://gitcode.com/GitHub_Trending/ti/ticket-purchase cd ticket-purchase ./check_environment.sh

这个脚本是 shell 写的,贴合 macOS / Linux;Windows 用户改用 damai/check_environment.py 这套 Python 自检。

下面是完整的依赖底账,对照自查:

依赖版本 / 状态怎么装、怎么确认
Python3.9+运行抢票脚本本体
Node.js20.19.0+ / 22.12.0+ / 24.0.0+Appium 的运行底座,node --version查看
Appium3.1.0+npm install -g appium
uiautomator2 驱动需单独装appium driver install uiautomator2
Android SDK已设ANDROID_HOME管理设备通信,随 Android Studio 提供
adb随 SDK 自带adb devices看设备是否device态
大麦 App已安装 + 已登录 + 观演人已登记提交订单的硬前提,包名cn.damai

两个新手最容易栽的坑,先记下来:

  1. 脚本里的示例路径是作者机器上的。start_appium.sh、start_ticket_grabbing.sh、check_environment.sh 都硬编码了作者 Mac 上的 SDK 目录(/Users/shengwang/Library/Android/sdk)和 Python 解释器路径。跑之前要把这些对齐到你本机的 SDK 目录和你的 Python,否则第一条命令就会路径报错。
  2. 设备必须真的在线。adb devices里序列号后面应是device;若是offline,真机去查 USB 调试开关,模拟器用adb shell getprop sys.boot_completed确认它是否完全启动(返回1才算就绪)。

config.jsonc 配置:把目标票喂给脚本的最快方法

移动端的全部行为,都由 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": false }

详情页上的城市、场次、票档三行,和city、date、price三组字段是一一对应的。下面这张标注图把"页面上看到哪一格 → 改哪个字段"标了出来:

逐字段拆解,重点是一个反直觉的字段:

字段作用新手注意
server_urlAppium 服务地址换了端口要同步改
keyword搜索关键词填歌手名 / 巡演名
users观演人姓名数组与账号登记逐字一致;票的数量也按它的人数来
city城市站支持模糊匹配,"深圳"能命中"深圳站"
date场次日期形如12.06(移动端是 MM.DD,不是完整日期)
price票档文字描述只给人眼核对,不参与点击
price_index票档索引真正瞄准目标的那个数,从 0 计数
if_commit_order是否自动提交订单首次运行保持false空跑

price_index为什么才是关键。新版大麦 App 里,票档区域的文本是空串"",按文字去找按钮的老办法已经失效。脚本因此改成按位置来:先定位票档容器project_detail_perform_price_flowlayout,再取其中第price_index个"可点击的 FrameLayout"去点。索引从 0 开始,5就是从上往下第 6 个档位。所以price这个字段看着像票档,其实只负责让你确认没选错行;真正决定点哪一格的,是price_index。开抢前从上往下重新数一遍票档,把索引对齐,这是最省心的校验。

另外两件事脚本替你办了:users写几个人,数量就点几次加号(len(users) - 1次);city走三级匹配——先精确、再包含、最后 XPath 兜底,所以城市名不必写全。

不想走 App 端,仓库里还有一套 Selenium 的 Web 端兜底实现(damai/ 目录),它读的是 damai/config.json,字段定义见 damai/config.py,target_url填详情页地址、users/city/dates分别对应观演人、城市与场次,配置长这样:

开售那一刻:双终端分工、Appium 常驻与 3 次重试

把运行过程按时间线走一遍,你就知道两个终端和手机各在哪一刻登场:

  1. 终端一跑./start_appium.sh:先export ANDROID_HOME,确认设备在线、cn.damai已安装,然后appium --port 4723常驻。这个窗口全程别关,关了就等于遥控器没电了。

  2. 手机:打开大麦 App → 搜到目标演出 → 停在详情页。未开售时底部按钮是"预约",开售后变"立即购买",两种文案脚本都认,所以停在详情页等就行,搜索环节不用管。

  3. 终端二跑./start_ticket_grabbing.sh:先用curl http://127.0.0.1:4723/status确认 Appium 活着、再确认 config.jsonc 存在,回显keyword/city/users供你核对,输入y进入。

  4. 脚本接管(入口 damai_appium/damai_app_v2.py),按这个顺序连点:

    ① 选城市 精确 → 包含 → XPath 三级匹配 ② 点购买按钮 "预约 / 购买 / 立即" 任一文案都能命中 ③ 选票档 按 price_index 点票档区第 N 个可点击 FrameLayout ④ 设数量 按 users 人数点加号 (len(users) - 1) 次 ⑤ 确定购买 btn_buy_view,兜底"确定 / 购买" ⑥ 勾观演人 按 users 姓名收集坐标后,几乎一次性全部点完 ⑦ 提交订单 if_commit_order 为 true 才真正提交
  5. 失败不认命:整条流程最多重试 3 轮,每轮间隔 2 秒,并且每轮都重新初始化驱动(_setup_driver)。单次卡顿或某一步没点到,不会直接判负,下一轮重来。

零基础自救手册:常见报错的 现象 → 原因 → 怎么修

排错时按"现象 → 原因 → 怎么修"对号入座,比从头读文档快得多。

Appium 拒绝启动,提示 Node 版本不兼容

  • 现象:要求 Node 至少^20.19.0 || ^22.12.0 || >=24.0.0,本地过旧。
  • 原因:Node 版本低于 Appium 门槛。
  • 怎么修:升级 Node(如brew upgrade node),再重跑自检确认版本落在兼容区间。

报Neither ANDROID_HOME nor ANDROID_SDK_ROOT

  • 现象:脚本说找不到 SDK。

  • 原因:两个环境变量都没设。

  • 怎么修:

    export ANDROID_HOME=/你的/android/sdk路径 export ANDROID_SDK_ROOT=/你的/android/sdk路径

    写进~/.bashrc或~/.zshrc让下次登录仍在,同时别忘把启动脚本里那处硬编码示例路径换成你自己的 SDK 目录。

提示找不到活动设备 /Unable to find an active device

  • 现象:Appium 拿不到设备。
  • 原因:设备处于离线态,或模拟器没完全启动。
  • 怎么修:跑adb devices看状态列,应为device;offline就查 USB 调试,模拟器用adb shell getprop sys.boot_completed确认返回1。

连接被拒绝Connection refused

  • 现象:抢票脚本连不上 Appium。
  • 原因:终端一的服务已经停了,或端口被别的进程占用。
  • 怎么修:确认终端一的start_appium.sh还开着,再用curl http://127.0.0.1:4723/status验证端口;端口被占就换端口,并同步改server_url。

点到的票档不是想要的

  • 现象:选错了档位。
  • 原因:索引从 0 计数,且页面票档顺序可能因活动而异。
  • 怎么修:打开详情页票档区从上往下重数,把price_index对齐后再开跑,别凭印象填。

用之前想清楚的边界:合规、频率与风险

工具能帮你把那几步点得快,但它改变不了"票就那么多、所有人同时抢"这个事实。开跑前把这几条想透:

  • 不承诺"必中"。脚本只压缩了你的手速,不能保证一定抢到;热门场次该难抢还是难抢。
  • 遵守大麦网使用条款。自动化工具属于平台使用条款关注的范围,别拿它做高频并发刷单,也别用别人的账号或观演人信息——观演人姓名必须是你账号下真实登记、且与证件一致的。
  • 尊重其他购票者的机会。把自动化当成"替自己点得快一点",而不是"挤掉别人"的手段,控制频率、别起多开并发。
  • App 会更新,选择器会失效。新版票价文本变空串、只能改用price_index,就是活例子;大麦升级界面后,控件 ID 和文案可能跟着变,脚本点不动时先核对选择器,而不是盲目重试。
  • 风控有真实存在的可能,请自行评估并只在你愿意负责的账号上使用,网络保持稳定。

开抢前最后过一遍:环境自检通过、脚本里的示例路径已对齐本机、price_index已重数对齐、观演人姓名逐字一致、curl .../status能正常响应、手机停在详情页且已登录;确认开售时间,开抢前才把if_commit_order改为true,之前一律保持false空跑,确认流程无误再上。

愿它替你省下那一秒的犹豫,也愿你抢到的那张票,是自己真正想看的演出。

【免费下载链接】ticket-purchase大麦自动抢票,支持人员、城市、日期场次、价格选择项目地址: https://gitcode.com/GitHub_Trending/ti/ticket-purchase

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进