ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

B站会员购抢票脚本安全解析:油猴与Python直连方案

2026/10/2 12:50:49 拓冰建站 浏览量
B站会员购抢票脚本安全解析:油猴与Python直连方案 简介面向哔哩哔哩会员购用户的自动抢票辅助工具基于Rust开发并具备跨平台GUI界面专为CP漫展、演唱会等热门票务设计。无论是CP31、BW还是其他会员购活动都能通过定时抢票与捡漏两大核心功能提升购票成功率用户可自定义抢票时间与规则软件自动执行抢票操作同时兼顾执行效率与运行稳定性。压缩包共15个文件整体大小38.74MB内含可直接运行的登录、滑块验证、抢票等exe程序以及配套Python源码、配置文件、说明文档和界面截图满足不同层级的用户需求——新手可一键启动开发者可研究源码进行定制。目前已有386人学习下载适合经常参与B站会员购活动的粉丝也适合对自动化抢票实现原理感兴趣的Python开发者参考。1. B站会员购抢票脚本.zip手点抢不到时这个压缩包到底能不能信你大概也见过这种场面一场热门演唱会的票在 B站会员购上开售你提前五分钟就守着页面倒计时一跳零你鼠标点下去页面转圈三秒然后弹出来“已售罄”或“缺票登记”。同一时间黄牛和手快的用户已经把票扫空了。手点一次请求从浏览器渲染到提交少说也要两三秒而脚本可以在倒计时归零的瞬间把请求发出去延迟压缩到几百毫秒以内。这就是“B站会员购抢票脚本.zip”这类压缩包存在的全部理由。这类 zip 包通常是从技术交流群、论坛帖子或网盘里流出来的命名很直接里面一般装着油猴脚本、Python 脚本运气不好还可能会混进一个伪装成脚本的可执行文件。对于刚接触的人来说它像是一个黑匣子你只知道它能抢票却不知道解压之后它在你电脑上做了什么。这篇文章就围绕这个标题把整条链路讲清楚拿到 zip 之后先做什么检查浏览器脚本和 Python 直连两条路线分别怎么落地参数怎么调以及最常见的翻车现场有哪些。这个方向适合两类人一类是想抢演出票、漫展票、限量周边的普通用户想在不写复杂代码的前提下把抢购成功率提上去另一类是已经在写爬虫或自动化脚本的开发者想从油猴脚本升级到相对可控的直连方案。先说明边界脚本能提升的是“提交请求的速度”和“操作稳定性”它不能保证你一定抢到也不能绕过平台的风控验证。下面从解压前的安全检查开始讲。2. 解压前先把 zip 拆开看脚本能跑的前提是包本身没问题2.1 别双击解压先用 file 命令确认压缩包里装的是什么从网上下来的抢票脚本 zip最常见的坑不是脚本写错而是压缩包里混着不该有的东西。我见过有人把一个 3MB 的“抢票脚本.zip”解压之后里面是一个 .exe 和一个 .bat没有任何 Python 或 JS 源码。双击 exe 之后脚本没跑起来电脑倒是被装了一堆推广软件。在你解压之前先用 file 命令看整体类型再用 unzip -l 看文件清单。file 抢票脚本.zip unzip -l 抢票脚本.zip unzip -p 抢票脚本.zip 文件名.py | head -n 50file 命令输出的是这个 zip 的真实格式信息如果显示 “Zip archive data” 那是正常的要是显示 “PE32 executable” 或者 “DOS batch file”那这个“zip”实际上是个程序直接停手。unzip -l 列出包内所有文件这一步能帮你快速判断里面是源码、目录结构还是躺着奇怪的 exe、scr、vbs、dll。第三行命令是把某个文件内容直接打印出来不解压也能先看源码头部。我一般会先看文件列表里有没有“后缀名和实际内容不符”的文件。比如一个叫 readme.txt 的文件大小却有 2MB这不是正常文档八成是个伪装的东西。判断标准很简单抢票脚本的逻辑无论如何都写在文本源码里如果压缩包里没有任何源码文件全是可执行文件那就没有必要继续了。2.2 zip 伪加密与密码移除这个参数位改一下就能绕过很多从群里流出来的抢票 zip 带密码分享者故意设置加密防止白嫖。但有一种情况叫“伪加密”它不是真正用 AES 或 ZipCrypto 算法把内容加密了而是只把 zip 头里的加密标志位改成 1让解压工具误以为文件有密码。zip 格式里每个文件头都有一段 general purpose bit flag其中的第 0 位标记“本文件已加密”。伪加密的原理是把这个 flag 置 1但实际上文件内容没有做任何加密运算。所以解压工具会弹窗要密码但直接用十六进制编辑器把标志位改回 0文件就能正常解出来。识别伪加密用 zipinfo 看一下zipinfo -v 抢票脚本.zip输出里每个文件会显示 “file security status” 和加密方式。如果显示 “encrypted” 但加密算法列是 “unknown” 或者 “zipcrypto” 的同时文件大小和原始文件完全一致就可以怀疑是伪加密。用 7-Zip 打开有些伪加密包在 7-Zip 里直接能读7-Zip 会忽略错误的加密标志位尝试列出内容。如果你确实需要去掉一个真正有弱密码的 zip 的密码常见做法是用 hashcat 或 fcrackzip 做字典攻击。fcrackzip 的使用很简单fcrackzip -D -p /usr/share/wordlists/rockyou.txt -u 抢票脚本.zip-D 表示字典模式-p 指定字典文件-u 表示通过解压来验证密码是否正确。不过这里有一条血泪经验来历不明的抢票 zip 如果加了密码不要去破解它直接删掉。分享者给一个破解门槛极高、内容完全不可见的脚本压缩包这本身就违背了“分享脚本”的逻辑。伪加密在恶意样本里非常常见攻击者故意让压缩包打不开诱导你去搜索“zip密码移除”工具而这类工具本身可能就是投放木马的载体。2.3 解压到隔离目录观察是否有多余动作确认包内是源码后也先别在主力环境里解压。用沙箱、虚拟机或者至少隔离目录解压然后跑一遍基础的行为观察。mkdir -p ~/sandbox/bsky-grab unzip 抢票脚本.zip -d ~/sandbox/bsky-grab cd ~/sandbox/bsky-grab find . -type f | sort python3 -m http.server 8899解压之后先看目录结构再启动一个本地 HTTP 服务把目录暴露在浏览器里用无痕窗口访问本机地址人工看一下页面效果。这样可以避开在本机环境直接运行带来的风险。更稳妥的方式是把源码从头读一遍重点看三件事有没有出现外部 URL 字符串、有没有调用系统命令、有没有把 cookie 或本地文件往外传。抢票脚本必然要登录 B站所以脚本会读取你的 cookie这是合理的但读取 cookie 之后往一个陌生的域名发送那就是偷数据了。用 grep 把可疑模式扫出来grep -rE https?://[^\] --include*.py --include*.js . grep -rE eval\(|exec\(|subprocess|os\.system --include*.py . grep -rE document\.cookie|localStorage|sessionStorage --include*.js .第一行列出代码里出现的所有 URL第二行扫 Python 脚本里的动态执行和系统命令调用第三行扫 JS 里对 cookie 和本地存储的读写。抢票脚本读 cookie 可以理解但读完之后把 cookie 拼进一个外部请求里这就是妥妥的账号盗窃行为。到这里压缩包本身安全了吗可以开始动手改造脚本了。3. 先跑通浏览器油猴方案改动最小、最容易复现的抢票脚本3.1 为什么优先选油猴而不用 Python 直连对于大多数“想抢票但不想逆向接口”的用户我建议第一条路走油猴脚本。B站会员购的所有接口都依赖登录态和风控参数Python 脚本直连需要自己处理签名、cookie 有效期、风控指纹这些对新手来说是绝对的大坑。而油猴脚本跑在浏览器里天然继承了浏览器的完整登录态脚本只需要做一件事在正确的时机点击正确的按钮。油猴脚本的另一个优势是安装成本低。下载一个 .js 文件油猴面板里新建脚本粘贴进去刷新页面就能生效不需要任何第三方依赖。Python 方案要装 requests、要处理证书、要模拟环境任何一个环节出问题都会导致脚本废掉。那油猴方案的劣势是什么是它仍然受浏览器渲染进程的调度影响。页面卡顿、定时器延迟、验证码弹窗都会拖慢节奏。所以油猴脚本适合抢购并发量中等、页面结构变化不频繁的场景如果你要抢的是那种开售一秒就没了的热门票可能需要升级到 Python 直连。3.2 油猴脚本的最小实现监听倒计时与自动点击一个合格的 B站会员购抢票脚本核心逻辑只有三个部分轮询商品状态、倒计时归零时触发点击、点击后监测是否有验证码或风控弹窗。下面是一个可以跑通的最小示例。// UserScript // name B站会员购抢购助手最小版 // match https://*.bilibili.com/* // grant GM_log // run-at document-idle // /UserScript (function () { use strict; const CONFIG { checkIntervalMs: 200, // 轮询间隔 preClickMs: 200, // 提前量一般不用 buttonText: 立即购买 // 按钮文字按页面实际文案调整 }; let clicked false; function findBuyButton() { const all document.querySelectorAll(button, .buy-btn, [class*buy]); return Array.from(all).find(el el.textContent.includes(CONFIG.buttonText)); } function tryClick() { if (clicked) return; const btn findBuyButton(); if (btn !btn.disabled) { btn.click(); clicked true; GM_log([grab] clicked at new Date().toISOString()); } } function checkCountdown() { const countdownEl document.querySelector(.countdown, [class*countdown]); if (countdownEl) { const text countdownEl.textContent.replace(/\s/g, ); if (/^0(时|:)|^00:00/.test(text)) { tryClick(); } } else { // 页面没有倒计时直接尝试点击 tryClick(); } } setInterval(checkCountdown, CONFIG.checkIntervalMs); })();这段脚本的逻辑是每 200 毫秒检查一次页面是否存在倒计时和购买按钮当倒计时归零或按钮变为可点击时立即执行 click。clicked 标志位用于防止重复点击。参数调整方面checkIntervalMs 不建议低于 100否则定时器频繁触发反而会造成页面卡顿preClickMs 是提前量参数默认 200会被倒计时文本解析干扰实际上不建议开启。按钮文字匹配是这套方案最大的弱点B站会员购页面改版后按钮文案可能变成“立即抢购”或“马上抢”改成对应文案即可。3.3 验证码与风控提示怎么处理别写绕过代码油猴脚本执行点击之后页面大概率会出现两种情况一是跳转到订单确认页脚本使命完成二是弹验证码或风控提示。很多人在这里开始动歪心思想用脚本自动识别验证码或模拟滑动。我的建议是不要写任何绕过验证码的代码。原因有两层。一层是平台风控识别验证码绕过的能力很强一旦侦测到自动化轨迹轻则验证失败重则账号被风控。另一层是验证码本身充当了“人类操作背书”的作用人工在验证码上点一下反而能证明这个账号操作正常。所以脚本的正确策略是点击按钮后脚本负责把页面滚动到验证码位置并聚焦剩下的人工完成。油猴脚本方案稳定跑通之后你会发现瓶颈依然存在你只能抢当前页面正在卖的东西。如果你要同时监控多个商品或者页面加载慢导致点击时按钮还没绑定事件油猴方案就不够用了。这就是下一章讲 Python 直连接口的原因。4. 进阶Python 脚本直连创建订单接口保留 cookie 会话4.1 抓包定位关键请求先看 F12再写代码Python 直连方案的核心不是写代码而是先搞清楚会员购下单的请求链路。用浏览器开发者工具打开 Network 面板勾选 Preserve log然后手动走一遍购买流程进入商品页 - 点击购买 - 确认订单 - 取消支付。全程记录下这几个关键请求的 URL、请求方法、请求头和请求体。我一般会重点抓三个接口。第一个是商品详情接口返回库存、价格、开售时间第二个是创建订单接口提交商品 ID、SKU ID 和数量第三个是订单确认接口校验订单信息。这三个接口的路径结构通常是 /x/xxx/detail、/x/xxx/order/create 之类的形式具体以你抓到的包为准不要去盲猜。抓包时注意一个细节创建订单请求里有几个签名参数比如 ts、sign 之类。B站的风控体系对这些参数做了加密硬逆向的工作量大。常见的绕行方案是用浏览器执行创建订单的 JS让浏览器把签名生成好Python 只负责发送最后的确认请求。这个方案不算完美但能把复杂度控制在可维护范围内。4.2 Python 最小实现抢票主循环与参数说明下面给出一个框架性的 Python 脚本核心是维护一个带 cookie 的 Session轮询库存并尝试创建订单。import time import requests session requests.Session() session.headers.update({ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://www.bilibili.com/, }) # 从浏览器开发者工具中复制你登录后的 cookie session.cookies.update({ SESSDATA: 你的SESSDATA, bili_jct: 你的bili_jct, DedeUserID: 你的DedeUserID, }) CONFIG { item_id: 商品ID, sku_id: SKU_ID, buy_count: 1, check_interval_sec: 0.3, order_timeout_sec: 10, } def fetch_stock(): # 详情接口返回库存信息 url https://api.bilibili.com/x/xxx/detail params {item_id: CONFIG[item_id], sku_id: CONFIG[sku_id]} resp session.get(url, paramsparams, timeoutCONFIG[order_timeout_sec]) resp.raise_for_status() data resp.json() return data.get(data, {}) def create_order(): url https://api.bilibili.com/x/xxx/order/create payload { item_id: CONFIG[item_id], sku_id: CONFIG[sku_id], count: CONFIG[buy_count], } resp session.post(url, jsonpayload, timeoutCONFIG[order_timeout_sec]) resp.raise_for_status() return resp.json() def main(): order_ok False while not order_ok: try: stock fetch_stock() if stock and stock.get(stock_count, 0) 0: result create_order() if result.get(code) 0: print(订单创建成功:, result.get(data)) order_ok True else: print(创建订单失败:, result) else: print(暂无库存继续轮询...) except requests.RequestException as exc: print(请求异常:, exc) time.sleep(CONFIG[check_interval_sec]) if __name__ __main__: main()这段代码的逻辑是每隔 0.3 秒请求一次商品详情接口当库存大于 0 时立即提交创建订单请求成功则退出循环。Session 对象自动维持 cookie不需要手动拼接 Cookie 头。参数说明check_interval_sec 设置的是轮询频率我习惯在 0.3 附近低于 0.1 容易触发风控order_timeout_sec 是单次请求超时时间建议不小于 5 秒因为抢购高峰期服务端响应慢buy_count 固定为 1不建议调大催生囤货对账号没好处。这个框架代码直接跑大概率会失败因为接口路径和签名参数都未补全。这正是前面强调“先抓包再写代码”的原因。把抓到的真实 URL 替换进去把签名参数按照你在浏览器里看到的方式补上这个脚本才有实际战斗力。4.3 两种方案的边界油猴不一定输Python 不一定赢做一个直接对比方便你在投入时间前想清楚选哪条路。维度油猴脚本Python 直连登录态自动继承浏览器需要手动复制 cookie签名参数由页面 JS 生成需要逆向或复用浏览器请求时机依赖页面渲染和定时器可精确到毫秒发出 HTTP 请求风控风险更低行为接近真人更高请求频率和指纹容易被识别维护成本页面改版后改个选择器接口调整后要重新抓包适合场景单商品、临时用多商品监控、需要组合操作油猴方案输在“点击这个动作本身需要页面元素存在”但赢在“浏览器环境天然可信”。Python 方案赢在可以直接对接口发请求不依赖页面加载但代价是要自己处理签名和风控。对于大多数只抢一两场票的用户油猴脚本足够用。对于想长期监控多个商品甚至写价格监控的人来说Python 方向更有价值。但无论哪条路都会遇到下面这些烦人的问题。5. 抢票脚本的常见翻车现场与排查清单5.1 现象一脚本在别人电脑上能跑自己一运行就报错原因是这个。抢票脚本的依赖环境比想象的敏感。油猴脚本要求浏览器版本不能太老还会被扩展商店的权限模型影响Python 脚本则卡在第三方库版本上。最常见的是 requests 版本过低导致 TLS 握手失败或者 Python 版本低于 3.8 无法解析某些语法。解决思路是先做最小验证。油猴脚本先打开 B站任意页面确认扩展图标亮了控制台里能用 GM_log 输出。Python 脚本先单独跑一条最简单的接口请求确认能拿到 200 响应再跑完整逻辑。python -c import requests; print(requests.__version__) python -V这个命令检查 Python 和 requests 版本。如果 requests 是 2.20 以下升级到新版即可。环境问题是最容易解决的也是最容易让人白忙一晚上的。5.2 现象二用脚本抢到了票但支付超时原因不在脚本而在支付环节。订单创建成功后一般有 15 到 30 分钟的支付窗口但很多人把脚本挂在后台自己没盯着页面等看到提醒时订单已经自动关闭了。另一种情况是支付页面加载慢脚本在跳转支付时被浏览器拦截。解决做法是在脚本里增加声音或浏览器通知提醒。油猴脚本可以用 Notification API 发桌面通知Python 脚本可以用最简单的控制台弹窗提醒。if (Notification.permission granted) { new Notification(抢到了, { body: 请尽快完成支付 }); }这段代码加在点击成功之后。支付窗口是脚本无法代劳的任何声称“自动支付”的脚本都要警惕它很可能在收集你的支付信息。5.3 现象三请求频率不高账号还是被风控了原因通常是环境指纹问题而不是频率问题。Python 脚本的请求头如果缺少一些浏览器默认会带的字段比如 Accept-Language、Sec-Fetch-Mode服务端就能判断这不是浏览器发的。而且数据中心 IP 或者宽带 IP 的段如果被标记过请求再少也会被风控。解决做法有两个方向。一是在 headers 里补齐浏览器特征字段把 F12 里复制出来的完整请求头原样贴进脚本。二是降低抢购前试探请求的频率。我见过有人写了个“提前十分钟开始刷详情接口”的循环开售前就把 IP 权重刷低了。正确的做法是开售前一分钟内再启动轮询前几十秒只在本地做倒计时不发出任何请求。5.4 现象四倒计时归零了脚本却没触发原因是本地时间和服务器时间不一致。B站会员购的倒计时以服务器时间为准但页面展示的倒计时往往基于你本机时间计算。本机时间快了或慢了一秒就会导致脚本提前或延后触发。解决做法是在脚本里面直接请求服务器时间接口和本地时间做差然后以校正后的时间作为触发基准。油猴脚本里可以这样处理const serverTime await fetch(https://api.bilibili.com/x/xxx/time).then(r r.json()); const offset serverTime.data.now - Date.now();拿到 offset 之后把倒计时判断逻辑里的时间全部加上这个偏移量。这个坑很隐蔽本地时间误差个几百毫秒就可能导致抢购失败而且是脚本代码层面看不出问题的类型。5.5 现象五脚本里藏着“更新逻辑”在偷数据这是最严重的一类情况。有些分享出来的抢票脚本源码写得像模像样但里面有一段“自动检查更新”的逻辑实际上是把 cookie、手机号这类信息 POST 到脚本作者的服务器上。它伪装成获取新版本配置实际干的是数据收集。排查方法在前面 2.3 节已经讲过grep 扫所有 URL重点看有没有往非 bilibili.com 域名发送的请求。真正的抢票脚本只需要访问 B站域名出现任何第三方域名都有问题。而且这类脚本往往会在 readme 里写着“必须联网获取配置才能使用”这个说辞就是提示风险的红旗。6. 让脚本稳定工作限速、重试策略与可观测性过了翻车期脚本能跑通了接下来要考虑的是怎么让它稳定工作。我的经验是三个词限速、重试、日志。限速不是越慢越好而是要有节奏。抢购前用低频轮询探路比如 500 毫秒一次开售瞬间可以提高到 200 毫秒一次持续 10 秒如果 10 秒内没抢到把频率降回 500 毫秒继续拉长到 1 秒避免在高峰期持续高频请求。这个策略可以用一句话概括快在关键瞬间慢在平时。重试要区分错误类型。网络超时可以立即重试但业务错误比如“库存不足”“订单频繁创建”不应该重试因为重试也没用反而增加风控风险。我习惯给重试加上上限超过 5 次进入冷却冷却 30 秒之后再继续。日志是最后一道后悔药。建立一个简单的日志文件记录每次请求的时间、状态码、响应耗时和返回内容判断脚本行为是否有异常。没有日志的脚本出了问题只能靠猜有了日志可以直接定位是网络问题、风控问题还是接口参数问题。import logging logging.basicConfig( filenamegrab.log, levellogging.INFO, format%(asctime)s %(levelname)s %(message)s ) logging.info(start grab item_id%s sku_id%s, CONFIG[item_id], CONFIG[sku_id])这套三件套用上之后脚本就不再是“碰运气跑一次”的黑匣子了。你每天打开日志就能看到它在几点几分做了什么有没有异常。我自己在这条路上踩过的最大一次教训就是第一版脚本没做限速把轮询间隔写成 50 毫秒结果开售后十分钟账号被风控锁定二十四小时完美错过了整场演出。后来老老实实把限速和重试策略加上反而稳定多了。这行字写给你希望帮到你。本文还有配套的精品资源点击获取