Python监控演唱会回流票:轮询接口与状态翻转实战 📅 发布时间:2026/9/11 21:29:09 👁 浏览次数: 简介面向大麦、猫眼、票星球等平台的演唱会门票回流监控工具基于Python开发聚焦热门演出售罄后的回流票捕捉与自动抢购场景适合需要实时掌握余票动态、愿意研究抢票逻辑的用户或开发者。压缩包内共56个文件以14个py源码和18个pyc编译文件为主另有4个json配置、Dockerfile、requirements.txt等辅助内容整体93KB。py文件包含模拟登录、库存监控、抢购触发等核心模块json保存不同票务平台的参数配置Dockerfile则用于快速部署运行环境。目前已有147人学习使用。这份资源展示了完整的项目结构与代码实现可帮助理解多平台票务监控的原理通过阅读和修改源码能够掌握回流检测、登录模拟等关键环节也可基于现有框架二次开发成适配更多票务渠道的抢票脚本。1. 演唱会门票回流监控先用 Python 把判断逻辑想清楚开票瞬间没抢到门票真正让人上火的不是手速而是下单超时后被释放的回流票。人工刷新通常隔几分钟一次Python 脚本却能把轮询缩短到十几秒只要场次状态从“不可购买”变成“可购买”就立刻推送通知。标题里的 zip 是这类小项目最常见的分发方式把脚本、依赖说明和启动入口压成一个压缩包别人解压就能跑不用现场教怎么配环境。适合有抢票需求、又不想花钱买现成脚本的人也适合想练手轮询、请求与状态通知的 Python 开发者。回流情况不只是“有票”或者“没票”更值得记录的是释放时间、持续时长和余票数量这些信息能判断要不要立刻下单。下面这套方案按“需求拆解 → 代码实现 → zip 打包 → 参数调优”展开能直接复现也可以改成其它票务场景。2. 回流监控的技术选型轮询节奏、接口识别与 Python 版本策略监控回流不是去看首页的演出大图而是要找到一个能反映场次状态的 JSON 接口然后以合适频率去轮询它。这个频率要快过人工刷新又要低于平台风控阈值所以先理解回流怎么产生、平台怎么暴露数据再写代码才不容易返工。2.1 回流票为什么只出现几十秒用户在票务平台下单后会保留一段时间完成支付通常是 5 到 15 分钟。超时未支付或者支付失败后关闭订单座位就会被释放回公共库存。平台释放座位的时间点并不固定有些在订单关闭瞬间立即释放有些会延迟到下一个整点。无论是哪种回流票出现在列表里的窗口都只有几十秒因为等待这张票的人远不止一个。后端释放座位后前端详情页的“缺货登记”会变成“立即购买”同时库存数字从 0 变为正整数。这个变化就是监控的核心信号。很多平台没有公开的“回流通知”订阅接口做回流监控最常见的方案就是定期轮询详情接口用自己的登录态去请求同一个数据源。2.2 找接口而不是爬页面从 Network 面板到 JSON 字段页面上的 HTML 是给浏览器渲染用的结构经常改而且包含大量无关样式和文案。解析 HTML 判断“缺货登记”四个字只要前端改文案就得改代码。正确做法是打开详情页按 F12 进入开发者工具切到 Network 面板筛选 XHR 或 Fetch 请求刷新页面后找返回场次详情或库存信息的 JSON 请求。找到接口后先用 Python 直接请求一次确认返回的是 JSON 而不是整段 HTMLimport requests session requests.Session() session.headers[User-Agent] Mozilla/5.0 resp session.get(https://api.example.com/show/detail?showId123) print(resp.status_code, resp.text[:200])这段代码的作用就两步一是确认接口地址能通二是看返回结构里有没有下面表格里的关键字段。实际项目里我会把返回内容复制到本地格式化逐个字段看含义而不是猜。常见字段大致如下具体名称以平台返回为准字段含义常见取值status场次销售状态1未开售2售卖中3已售罄stock当前库存0 或正整数limit单笔限购张数1~6beginTime票种开售时间时间戳提示如果 Network 面板里找不到字段明确的 JSON优先看详情页加载时发起的异步请求不要解析首屏 HTML。返回内容里同时包含 status 和 stock 两个字段的接口才适合做判断。2.3 用状态翻转判断回流而不是库存绝对值直接判断“库存大于 0”有一个问题有些票种在未开售时接口里也能看到预留库存还有些场次在售罄后接口仍会短暂返回几条缓存数据。绝对值不可靠状态发生的翻转才可靠。监控脚本应该维护一个“上次状态”变量if last_status unsold and current_status saleable: notify(回流) last_status current_status上一次不可购买、本次可购买才触发回流通知上一次可购买、本次仍可购买不做任何操作避免每次轮询都被推送轰炸。第一次运行时要将 last_status 初始化为当前状态否则脚本一启动就会把历史存量当成一次回流通知收到手软。2.4 依赖精简Python 3.8 与单个 requests这个项目对 Python 版本要求不高3.8 及以上都行。requests 库负责带 Cookie 请求、超时控制和 JSON 解析其余逻辑全部用标准库实现。依赖越少最后 zip 分发给别人时越省事。requirements.txt 只需要一行requests2.31如果电脑上还没有 Python先确认python3 --version输出再安装一个 3.8 以上的版本。依赖精简也是 zip 包能顺利跑起来的前提别人解压后装一个包比装五个包省事得多。3. 用 Python 写回流监控脚本轮询、去重与通知选型定下来之后核心代码就是把“轮询 → 状态比较 → 通知”三件事串起来。下面这份脚本是完整可运行的骨架接口地址、场次 ID 和通知地址替换成自己的配置就能用。3.1 最小可运行脚本请求详情接口并判断可售状态# monitor_ticket.py import time import requests POLL_INTERVAL 10 # 轮询间隔单位秒 WEBHOOK_URL # 通知地址按群机器人文档填写 def get_show_status(session, api_url): 请求场次详情接口返回可售状态与库存 resp session.get(api_url, timeout10) resp.raise_for_status() data resp.json() payload data.get(data, {}) # 假设 status2 表示可购买stock0 表示有票 return { saleable: payload.get(status) 2 and payload.get(stock, 0) 0, stock: payload.get(stock, 0), } def send_notice(text): 通过 webhook 推送文本消息忽略失败不中断轮询 try: requests.post( WEBHOOK_URL, json{msgtype: text, text: {content: text}}, timeout5, ) except Exception as exc: print(通知失败:, exc) def main(): session requests.Session() session.headers.update({ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64), Referer: https://example.com/detail, }) # 浏览器登录平台后复制 Cookie 到这里 # session.headers[Cookie] ... api_url https://api.example.com/session/detail?id123 last_saleable None while True: try: status get_show_status(session, api_url) if last_saleable is None: # 第一次请求只记录状态不触发通知 last_saleable status[saleable] print(初始状态:, status) elif status[saleable] and not last_saleable: send_notice(回流当前库存: {}.format(status[stock])) print(检测到状态变化已通知) last_saleable status[saleable] except Exception as exc: print(请求异常:, exc) time.sleep(POLL_INTERVAL) if __name__ __main__: main()脚本的核心逻辑是按顺序执行的创建 Session 保留登录态第一次请求只建立基线后续请求把当前状态和上一次状态比较只有从不可购翻转为可购时才发送通知。任何一次请求异常都不会让进程退出打印错误后跳到下一次轮询。参数作用建议值POLL_INTERVAL轮询间隔8~15 秒WEBHOOK_URL通知地址按群机器人文档填写api_url场次详情 JSON 接口从 Network 面板复制User-Agent请求头与浏览器保持一致Cookie登录凭证浏览器登录后复制提示Cookie 包含账号身份信息不要把真实 Cookie 放进要分发的 zip 包。别人拿到脚本后应该自己填自己的 Cookie注释里留好说明即可。3.2 状态缓存与去重重启后不产生误报脚本重启后 last_saleable 会丢失。假如重启前回流已经出现你打开脚本时状态仍然是“可购买”新基线就会把这个回流当作已有状态忽略白白错过。反过来如果重启前状态是不可购买重启后还是不可购买不会有问题。把上一次状态持久化到本地文件就能解决import json import os STATE_FILE state.json def load_last_state(): if os.path.exists(STATE_FILE): with open(STATE_FILE, r, encodingutf-8) as f: return json.load(f).get(last_saleable, None) return None def save_last_state(value): with open(STATE_FILE, w, encodingutf-8) as f: json.dump({last_saleable: value}, f)main 循环里改成启动时先last_saleable load_last_state()每次请求结束后调用save_last_state(status[saleable])。这样脚本重启、断网恢复都不会因为丢了上次状态而误报或漏报。state.json 应该由脚本运行自动生成不要跟着源码一起打进 zip 分发。3.3 请求失败重试与频率控制轮询脚本要长时间跑网络抖动和平台临时限流都会出现不能因为一次失败就中断。常见做法是捕获异常后继续循环同时配合指数退避。def get_with_retry(session, api_url, max_retries3): for attempt in range(max_retries): try: resp session.get(api_url, timeout10) if resp.status_code 429: time.sleep(5 * (attempt 1)) continue resp.raise_for_status() return resp.json() except (requests.exceptions.Timeout, requests.exceptions.ConnectionError): time.sleep(2 ** attempt) return None429 是常见的限流状态码出现 429 先退避再继续超时和连接错误用 2 的幂次退避。函数返回 None 时主循环要保留上一次状态不更新避免一次失败的响应把状态改错。实际接入时把主请求函数替换成 get_with_retry并对 None 返回值单独处理即可。3.4 通知链路对比与替换方式通知是整个闭环的最后一跳。最常见的做法是往聊天工具里推一条群机器人消息钉钉和企业微信都可以创建自定义机器人拿到 Webhook 地址后填到 WEBHOOK_URL 里。相比短信来说配置简单、不花钱。通知方式需要准备内容优点注意点钉钉群机器人群内创建自定义机器人拿到 Webhook配置简单文本消息方便开启加签后需要计算签名企业微信机器人群内添加机器人拿到 Webhook支持被提及消息频率限制更严格SMTP 邮件邮箱授权码、SMTP 服务器不依赖群聊延迟较高不适合秒级回流控制台输出无快速验证接口和逻辑人不在电脑前就收不到替换通知方式时不需要改轮询逻辑只改 send_notice 函数内部实现。保持函数签名不变是这类小脚本方便扩散的关键。改成 SMTP 时把 requests.post 换成 smtplib.sendmail参数从 webhook 换成邮箱配置调用方完全不用动。4. 把监控脚本打成 zip 包分发依赖、启动与跨平台坑脚本写好后要交给别人跑最常见做法是打成 zip 包。zip 包的内容和组织方式直接决定对方解压后能不能跑起来这节把文件清单、虚拟环境和启动脚本一次说清。4.1 zip 包里放哪些文件解压后要能一眼看明白怎么用zip 包里的文件应该按角色分清楚文件/目录作用monitor_ticket.py主脚本轮询入口requirements.txt依赖清单start.bat / start.shWindows / Linux 启动入口README.md参数说明、改哪里、跑什么命令runtime/运行目录state.json 和 log 放这里不要把虚拟环境压进 zip。venv 目录包含大量依赖文件而且带原始机器路径和 Python 版本信息拷到另一台机器上很容易失效。依赖交给启动脚本在首次运行时安装这是 zip 分发最省事的方案。4.2 用虚拟环境解决依赖安装虚拟环境的作用是避免污染接收方的系统 Python首次运行时自动创建python3 -m venv .venv ./.venv/bin/pip install -r requirements.txt ./.venv/bin/python monitor_ticket.pyWindows 上对应命令是py -3 -m venv .venv和.venv\Scripts\python.exe。如果目标机器无法联网可以在有网的机器上执行pip download -r requirements.txt -d packages/把 packages 目录也打进 zip对方再执行pip install --no-index --find-linkspackages -r requirements.txt。requests 的依赖比较轻离线包体积不大。提示pip download 时指定的运行平台要和目标机器一致否则装不上。requests 及其依赖基本都是纯 Python 包跨常见平台的坑比带二进制依赖的库少得多。4.3 Linux 与 Windows 启动脚本的差异启动脚本是给“不想敲命令”的人准备的。zip 解压后双击启动文件即可首次运行会自动建虚拟环境、装依赖、跑脚本。Windows 的 start.batecho off cd /d %~dp0 if not exist .venv ( py -3 -m venv .venv .venv\Scripts\pip install -r requirements.txt ) .venv\Scripts\python monitor_ticket.py pauseLinux 的 start.sh#!/usr/bin/env bash cd $(dirname $0) || exit 1 if [ ! -d .venv ]; then python3 -m venv .venv ./.venv/bin/pip install -r requirements.txt fi exec ./.venv/bin/python monitor_ticket.py脚本里第一行先切到所在目录防止双击运行时工作目录不对导致相对路径失效。zip 打包不保留 Unix 可执行权限位用系统 zip 命令或 7-Zip 压缩都一样所以 start.sh 要用bash start.sh运行不能直接./start.sh。4.4 也压成 zipPyInstaller 打包后的分发差异如果接收方完全不想装 Python可以用 PyInstaller 把脚本打包成独立可执行文件再压成 zippyinstaller -F -n monitor_ticket monitor_ticket.py-F生成单文件-n指定输出名生成的 dist/monitor_ticket 直接双击运行。可执行文件会把 Python 运行环境一起打进去产物通常比源码大很多压缩后体积会小一些。注意杀毒软件对 PyInstaller 产物经常误报发给别人之前最好先在自己和目标系统类型上都跑一遍验证。5. 调参、验证与误报收敛让回流监控真正可用代码跑起来只完成了一半。轮询间隔、通知内容和日志排查这三件事决定了脚本在真实回流场景中是否可靠。5.1 轮询间隔的调参参考与随机抖动轮询间隔是回报率与风险之间的权衡和 Prometheus 抓取指标时配置 scrape_interval 的思路一样间隔越小数据越及时压力也越大。间隔适用场景主要风险3~5 秒期望极高的回流竞争容易触发限流10 秒大多数回流场景风险中等收益均衡30 秒以上低热度场次、怕扰动容易错过回流窗口固定间隔连续跑几小时请求模式过于规律容易被识别。加一点随机抖动打散规律import random time.sleep(POLL_INTERVAL random.uniform(0, 3))5.2 命中后验证动作通知内容带足上下文收到通知后通常要在手机上再打开平台如果通知里只有一句“有票了”还要去翻是哪个场次。把场次、价位、余票数拼进消息里能节省一次切换msg 【回流】%s %s 剩余 %d 张时间 %s % ( show_name, price_label, stock, now_time)这里直接用字符串格式化拼接比传一整个对象更直观。通知内容越具体收到后越容易立刻判断值不值得打开 App。5.3 用日志定位“报有票但买不到”的问题日志是唯一的查错入口。常见做法是用 logging 模块同时写文件和终端文件用 RotatingFileHandler 限制大小避免跑一晚上后日志撑满磁盘import logging from logging.handlers import RotatingFileHandler logging.basicConfig(levellogging.INFO) handler RotatingFileHandler(monitor.log, maxBytes1_000_000, backupCount3) logging.getLogger().addHandler(handler)写日志时不只记录“检测到回流”把接口返回的原始 json 保留一小段方便日后对比“脚本说可购买但页面买不到”的差异。5.4 常见误报现象与对应排查现象常见原因排查方向提示有票但点进去无票接口返回了缓存数据看日志里 json 原始内容和请求时间重复收到同一条通知状态判断没有依赖上一次状态检查 last_saleable 是否被更新跑一会就收到限流错误轮询间隔太短拉长间隔并加随机抖动重启后立刻通知回流没有持久化上一次状态使用 state.json 恢复再判断把 state.json 和 monitor.log 放到单独 runtime 目录之后发布新版本 zip 时只更新脚本和启动文件运行数据继续保留在旧的 runtime 里换版本不用重新观察基线。本文还有配套的精品资源点击获取