Python自动参与B站抽奖:脚本设计、风控避坑与计划任务托管

发布时间:2026/10/13 14:24:04
Python自动参与B站抽奖:脚本设计、风控避坑与计划任务托管 简介面向B站互动抽奖自动化场景这份JavaScript脚本包通过GitHub Actions托管Node.js脚本实现动态抽奖的自动参与与防重复转发适合想用低成本方式运营小号或提升中奖效率的B站用户及开发者参考。压缩包共49个文件约630KB核心为20个js脚本并辅以14张png操作截图、4个yml工作流配置、4个json配置、2个txt说明及code-snippets、bat等文件从脚本逻辑到环境配置均有覆盖结构清晰便于定位。已有2358人浏览学习。资源内含完整的库模块与API封装覆盖Cookie获取、抽奖监控、动态ID本地与远程存储等环节并配有Cookie获取的操作截图和README指引使用者既能据此快速部署自动抽奖任务也能参考其中Node.js操作B站API、利用GitHub Actions做自动托管的工程实现。1. 动作托管解决的不只是手速抽奖动态没人盯得住做抽奖脚本这行最玄学的从来不是中奖率而是你能否在正确时间出现在参与池里。B站官方抽奖平台的开奖逻辑我拆过很多次不拼手速、不看在线时长开奖时从满足条件的参与池里随机抽取。反直觉的结论是手动盯动态抽奖最大的损失不是没中奖而是根本没参与。某UP主晚上十点发一条转发抽奖动态第二天早上才看到参与人数已经过了三千你补个转发照样能进池子问题在于你每天不可能把动态流完整翻一遍。LotteryAutoScript这类脚本做的就是这件事把盯动态流、识别抽奖标记、执行关注与转发、等待开奖这一整套动作托管给常驻进程你只负责定规则——哪些抽奖值得参与、每天最多参与几次、评论到底发不发。它解决的不是玄学概率而是确定性的“不错过”。2. 抽奖参与机制与脚本选型先搞懂一次“参与”背后发生了什么2.1 官方抽奖平台是怎么确认一次“有效参与”的B站动态抽奖分两类。一类是UP主发动态时直接勾选平台抽奖由官方抽奖平台托管开奖时间精确到分钟开奖后自动在动态评论区公布中奖名单这是脚本唯一值得自动参与的类型。另一类是UP主手动抽奖自己在评论区数楼层、从转发列表里选人开奖过程是个黑匣子脚本就算参与了也只能被动等结果而且这类动态没有接口层面的抽奖标记脚本只能靠“抽奖”“转发”这类关键词去猜误判率极高还会把无效抽奖计入参与配额。我一般会在过滤规则里直接关掉第二类不是它中不了而是它不该被自动化托管。对脚本来说一条动态能否被托管式参与取决于能不能从动态数据里认出三样东西抽奖标识、开奖时间、参与条件。官方抽奖动态的返回数据里会带一个抽奖标记字段同时能取到开奖时间和参与条件文本比如“关注转发评论”。这三样信息决定了脚本要不要参与以及需要执行哪些动作。具体字段名不建议照抄任何旧笔记接口返回结构已经改过几轮最稳的办法是抓一次真实动态亲眼看一遍。// 用浏览器开发者工具抓动态详情 // Network 面板过滤动态详情接口找一条带官方抽奖标记的动态 // 把响应保存为 JSON搜索 lottery / draw 关键词确认当前版本的标记结构 // 这一步只需做一次目的是让解析逻辑跟上真实返回这个环节不写代码也能完成但值得做。原因是接口是个黑匣子旧教程里的字段名可能已经失效把解析逻辑单独封装成函数后后续接口结构变了只改适配层不用动参与主流程。搜索关键词用“lottery”“draw”“抽奖”三选一哪个命中用哪个抓到后把值打印出来确认结构再往下写。跑通抓包之后解析层的写法大致是这样def parse_lottery_info(dynamic_json): # dynamic_json 是单个动态的完整返回 lottery_flag dynamic_json.get(lottery) or dynamic_json.get(draw) if not lottery_flag: return None return { lottery_id: lottery_flag.get(id), open_time: lottery_flag.get(open_time), conditions: lottery_flag.get(condition_text, ), }逻辑说明先把动态返回里与抽奖相关的部分捞出来捞不到直接返回None避免把普通动态当成抽奖参与。捞到了就把抽奖ID、开奖时间、条件文本组合成一个字典后续的过滤规则、动作执行器、状态存储都围绕这个字典工作。这里有个值得注意的参数open_time建议统一转成时间戳再存。日志里“2025-03-01 20:30”这种文本没法直接比较大小转成int后一条不等式就能判断动态是否还在可参与窗口内后续做开奖检查也要跟当前时间戳比较早转早省事。官方抽奖最常见的参与条件是“关注UP主转发该动态”偶尔附带“评论”。脚本执行动作的顺序通常固定为先查自己是否已关注该UP主未关注就执行关注再按策略执行转发、评论、点赞。顺序错了会引入一种隐蔽的失效场景——先转发再关注部分抽奖要求在转发生效时账号已处于关注状态先转后关很可能被判参与无效。2.2 为什么选用Python脚本做动作托管而不是浏览器插件实现自动参与本质上三选一浏览器插件、界面模拟器、接口请求脚本。早期我试过浏览器插件方案能直接读页面、配置直观但必须常驻一个浏览器窗口夜里系统睡眠或浏览器自动更新就断档页面DOM一改版脚本多半白写。界面模拟器的问题是慢一次参与要移动鼠标、点开、等加载、再点击单次好几秒刷新几十条动态就是几分钟的机械劳动。接口请求脚本直接用requests构造参与动作一次“查关注关注转发”可以压到几百毫秒不依赖浏览器资源占用也小这才是“动作托管”该有的形态。方案运行稳定性平均单次延迟页面结构敏感度适合无人值守托管浏览器插件依赖浏览器常驻秒级高一般界面模拟器依赖桌面环境3~8秒高一般Python接口脚本仅依赖Python环境百毫秒级仅接口字段变化适合选Python而不是其他语言还有一层现实原因时间解析、日志切分、状态持久化这些配套能力都有现成库后续想接推送通知也就几十行。脚本本身是低频IO任务性能不是瓶颈部署便利性优先于运行效率。Go编译出来的二进制部署确实省心但配套生态要自己攒同类开源脚本里Python最常见遇到问题搜到样例的概率也大得多。动作托管在工程上可以拆成四块扫描器按周期拉取被托管UP主的动态列表规则引擎读取配置里的过滤条件和参与策略动作执行器对命中动态顺序执行关注、转发、评论并在每两次请求之间加随机延时状态存储把“已参与”“待开奖”“已开奖”三个状态落到本地JSON文件保证重启脚本不重复参与。标题里这个脚本的设计思路基本就是围绕这四块展开的使用者的主要工作集中在调规则引擎和看状态存储。def run_once(session, config, state): dynamics scanner.fetch_dynamics(session, config[follow_uids]) # 1. 扫描动态 for d in dynamics: info parse_lottery_info(d) if not info or not rule_engine.pass_filters(info, config[filters]): continue # 2. 过滤 if state.has_participated(info[lottery_id]): continue # 3. 去重 actor.execute(session, d, info, config[strategy]) # 4. 执行动作 state.record_participated(info[lottery_id])这段是整条管线的骨架。逻辑说明扫描器和执行器之间隔着规则引擎与状态去重两层前者决定值不值得参与后者保证不重复参与。参数说明follow_uids是你要托管哪些UP主的动态流在config里配成列表即可state.record_participated必须在动作执行成功且接口返回code为0之后再调用如果转发接口返回风控错误这单就不该计入已参与否则进程重启后这条抽奖就永远漏掉了。注意接口自动化参与抽奖与平台用户协议存在冲突账号有被限制登录、取消中奖资格的风险。本文只讨论技术实现建议在了解风险后用不重要的账号做验证别拿主账号高频长时间跑。3. 在本地跑通LotteryAutoScript登录态、最小命令与第一次日志3.1 拿到登录态SESSDATA与bili_jct缺一不可动手前先准备登录态。这类脚本的所有参与动作都代表用户身份cookie里两个值必须拿对SESSDATA是会话主凭证决定“你是谁”bili_jct是CSRF令牌所有写操作类型的POST请求都要带它不然接口一律拒绝。第三个值建议同步带上buvid3它参与设备指纹的构成缺少时风控模型容易把陌生请求判为异常设备不少首次运行就报风控的例子追根溯源都是只复制了SESSDATA。获取方式很直接用浏览器登录B站开发者工具Application面板里找Cookie列表手动复制需要的值或者在控制台执行document.cookie把整串cookie拷出来。取到后不要硬编码进config单独放一个credential.json权限设为当前用户可读避免后续分享截图或配置时泄露登录态。{ cookie: { SESSDATA: 这里填你的SESSDATA, bili_jct: 这里填你的bili_jct, buvid3: 这里填你的buvid3 } }逻辑说明cookie是脚本能代替你执行动作的唯一凭证一旦失效所有接口都会退回未登录状态。参数说明bili_jct主要在POST请求时参与CSRF校验buvid3建议尽量与浏览器里的值保持一致频繁变化设备指纹反而更容易触发验证码。运行环境方面Python建议3.10以上核心依赖只有requests和PyYAML两个安装基本没有坑。把脚本放进独立目录我习惯放在用户目录下避免后续配置计划任务时碰到路径带空格或中文的麻烦。# 以仓库实际提供的方式获取脚本clone 或下载压缩包均可 git clone 仓库地址 ~/lottery-script cd ~/lottery-script pip install -r requirements.txt说明仓库地址以仓库首页展示的为准我这里用占位符是因为不同渠道转发的地址不一致直接给死地址反而容易让读者拉到过期版本。逻辑说明requirements.txt里锁了requests和PyYAML的版本装完可以执行python -c import requests, yaml验证两条import不报错就说明环境就绪。参数说明clone到~/lottery-script是为了让后续cron任务里的绝对路径固定且简单不要放在桌面这类带特殊字符的路径下计划任务跑起来容易出幺蛾子。3.2 跑通最小命令与读懂第一次日志第一次运行强烈建议用单次扫描模式只扫一轮、执行一轮、然后退出不进入常驻轮询。这样配置里的任何问题都会在十几秒内暴露出来而不是等脚本夜里挂在某个角落第二天才发现cookie早就填错了。python main.py --config config.json --once--once的含义是“跑完一轮就退出”。不带这个参数时脚本进入常驻循环按scan_period的间隔反复扫描。第一次跑完看三样东西日志里扫描到的动态总数过滤条件命中了几条动作执行后接口返回的code是不是0。返回0代表参与动作被服务端接受非0需要对照错误码排查常见的有-101代表未登录-412代表请求被风控拦截。# 预期日志形态 INFO 扫描完成 动态总数126 抽奖标记命中17 过滤后命中3 已参与去重后新增2 INFO 转发成功 dynamic_id12345678 code0 ERROR 转发失败 dynamic_id87654321 code-412 message请求被拦截日志解读126条动态里17条带官方抽奖标记过滤规则再筛掉14条最终只新增2条参与这个漏斗是正常的。如果过滤后命中长期为0先不要怀疑抽奖变少而是把过滤条件放宽跑一轮看变化。那种“过滤后命中0”的情况八成是关键词黑名单写太宽把官方抽奖动态也误杀了——比如把“转发”加入黑名单而官方抽奖条件文本里大概率包含“转发”两个字等于自己堵死自己的路。第一次跑通后再考虑去掉--once进入常驻模式。顺手把log_level从DEBUG调回INFODEBUG日志会打印每个POST请求的请求头日志文件一天能涨几十兆排查价值却很低。另外有读者遇到过仓库README里示意图加载不出来的情况这类脚本仓库的README通常还有备用方案标题里提到的“单图版”就属于这种兜底交互图加载失败时照着单图版核对config字段完全够用。4. 过滤规则与参与节奏让脚本只投你真正想参与的抽奖4.1 抽奖源的过滤规则五个配置项把无效抽奖挡在外面脚本扫到的是全量动态流不设规则它就会什么都参与——包括只要求评论区抽奖的、中奖后要联系主播的、还要求进粉丝群的。这类抽奖要么参与条件残缺要么后续兑奖流程繁琐自动化脚本一旦参与进去反而给自己添了一堆手动收尾工作。所以我把过滤规则看作整个脚本里最值得花时间打磨的部分。我常用的一组配置直接从config里摘出来{ filters: { official_only: true, keyword_blacklist: [粉丝群, 加微信, 线下领取, 连麦], user_blacklist: [], min_forward_count: 100, expires_in_hours: 24 } }逐个参数说明official_only是总开关只参与官方抽奖平台托管的动态手动抽奖一律不碰这个开关建议默认打开。keyword_blacklist配几条常见的坑人条件凡是条件文本里出现这些词的动态直接跳过能过滤掉大部分需要线下兑奖或者拉人头的抽奖。user_blacklist用于避开个别不信任的UP主配置后该UP主的所有抽奖动态不参与。min_forward_count是转发量下限动态发布几小时后转发还不到一百说明基本没什么人认可参与价值不高。expires_in_hours表示只参与发布后24小时内的动态超出这个窗口的要么已开奖要么参与池已经溢出没必要再补。注意min_forward_count只作用热度参考别把它当成中奖率指标。官方抽奖是随机抽取跟转发量没有正相关这个参数的作用是规避冷清的小范围抽奖。过滤规则存在一个顺序陷阱规则引擎按“与”逻辑组合任意一条不通过就直接跳过。这意味着official_only开启时如果再配一个“keywords_include: 转发”去圈定目标动态反而会因为官方抽奖条件文本里普遍带“转发”二字而大面积误杀。调试过滤规则最直接的办法是先用--once跑一轮看“过滤后命中”这个数字然后逐项关掉过滤条件再跑把这个数字当标尺就能定位是哪条规则卡得太严。4.2 参与节奏的三个关键参数扫描周期、动作延迟、每日上限过滤规则决定“做什么”参与节奏决定“怎么做得不像机器”。这部分是整个脚本里最像玄学的地方底层逻辑其实很简单风控模型判断异常靠的是请求统计特征固定频率、固定内容、固定动作序列都是高危特征。{ strategy: { repost: true, comment: false, like: false, follow_first: true, random_delay_min: 5, random_delay_max: 30, daily_limit: 20 } }repost、comment、like三个开关控制每次参与时执行哪些动作。我一般只开转发评论默认关闭原因是评论会走内容审核连续发几条相似评论容易触发反垃圾过滤如果某条抽奖明确把评论作为必要条件就给评论模板加随机后缀比如“祝中奖{random}”并把评论间隔拉大到30秒以上。follow_first表示参与顺序先补关注再转发修正前面提到的“先转后关”失效问题。random_delay_min和random_delay_max是每次动作执行前的随机等待区间单位秒。配5到30的含义是脚本转发完一条动态后随机睡5到30秒再进行下一次动作。这个区间不是越大越好一轮命中10条就要多等几分钟托管效率会打折扣但也不要小于3秒连续快速请求在风控日志里太扎眼。daily_limit是每日参与上限超过后扫描继续跑但不再执行动作。它可以防风控也反过来逼着过滤规则更挑剔——把每天20次的额度留给真正值得参与的抽奖。扫描周期scan_period建议设在300秒以上也就是每5分钟拉一次动态。扫描频率对“参与率”没有任何正向提升抽奖动态不是秒级产出扫得再勤看到的还是那几条只会白白抬高请求计数。时间维度上还可以加一个active_hours配置限定只在18点到23点扫描这个时段抽奖动态投放量最大其他时段让脚本休眠日请求量能压得更低。5. 避坑清单耗时但零命中的五个典型问题5.1 参与了却等于白参与的三个坑坑一转发成功但开奖名单里没有自己。现象脚本日志显示转发成功状态文件也记录了开奖后去动态评论区翻中奖名单找不到自己的ID。原因绝大多数官方抽奖的条件都含“关注UP主”这一项。脚本只执行转发没执行关注或者之前关注过但中途手动取关开奖时就不在有效参与池里。解决把follow_first打开让脚本每次参与前主动检查关注关系未关注就补关注同时参与后到开奖前这段时间不要手动取关任何UP主。先后顺序同样重要先关注再转发不要颠倒。坑二评论发出去了但从动态评论区看不到自己的评论。现象脚本返回评论成功、code为0但打开动态评论区翻不到自己。原因连续多条相似评论触发反垃圾过滤接口收下了内容但没让它公开展示这种情况参与池里当然也不会有你。解决把comment开关默认关掉只保留转发参与。如果某条抽奖明确要求评论给评论模板末尾加随机后缀并把每条评论的间隔控制在30秒以上让它看起来像真人手动参与。坑三扫描一直在跑日志却连续几天显示“过滤后命中0”。现象脚本正常启动每轮都在扫状态文件里却没有新增参与记录。原因过滤条件组合太严。常见的情况是official_only开着keyword_blacklist里又写了“转发”这类引导词官方抽奖的条件文本通常包含“转发本动态”之类的表述一匹配就全被跳过。解决临时把过滤条件全部放宽只保留official_only跑一轮确认能命中然后逐条加回黑名单关键词每加一条跑一轮看命中数变化把误杀词逐个揪出来。这个方法比对着文档猜快得多。5.2 登录与风控cookie失效和滑块验证怎么处理坑四昨天一切正常今天所有请求统一报-101。现象日志从第一个接口开始连续报未登录转发与扫描全部失败状态文件却仍显示正常。原因SESSDATA过期了。B站登录态有效期与浏览器活跃度相关长时间不登录、修改密码、异地登录都可能导致SESSDATA作废。解决把cookie读取单独做在credential.json里换cookie时只改这个文件不用动config。更稳的做法是脚本遇到-101时主动写一条ERROR日志“登录态失效请重新登录”配好计划任务后第二天看日志就能感知状态变化。强调一点不要把cookie写进代码或提交到仓库代码一旦分享出去等于把账号权限一并交了出去。坑五跑了一周后动作请求开始出现-412和滑块验证。现象转发接口开始返回-412或浏览器里弹出滑块验证必须手动点一下才能继续。原因请求节奏太规律比如固定每5分钟扫描一次、每次动作间隔固定30秒统计特征被风控模型识别了另一种可能是单日参与量冲破了阈值。解决把scan_period打散成基础值加随机偏移比如300秒加上0到90秒的随机数动作延迟区间从5到30秒扩大到8到45秒daily_limit从20降到10让请求频率回归普通活跃用户的水平。已经出现滑块验证时先停脚本、在浏览器手动登录一次清掉验证状态再恢复运行不要在验证状态下反复重试重试只会加重风控记录。6. 托管到计划任务开奖检查与状态文件变待办清单6.1 用Linux cron或Windows任务计划托管常驻任务自动化的最后一步是让脚本脱离终端也能运行。Linux上我用cron以--once模式每10分钟跑一轮比常驻进程更稳每次都是全新启动状态从state.json恢复内存占用和残留句柄问题天然不存在。Windows对应的是任务计划程序触发器设每10分钟重复一次操作里填python main.py --config config.json --once。# crontab -e 添加以下行路径换成自己机器的实际路径 */10 * * * * cd /home/用户名/lottery-script /usr/bin/python main.py --config config.json --once run.log 21逻辑说明cron里必须cd到脚本目录再执行否则相对路径找不到config和statestdout和stderr都追加到run.log便于第二天检查夜里有没有报错。参数说明/usr/bin/python用which python查一下再填不要直接写pythoncron继承的PATH比终端窄得多找不到解释器是常见问题。6.2 开奖结果检查状态文件就是你的待办清单最后一个技巧是把state.json当待办清单用。每参与一条抽奖就往pending列表追加一条记录包含lottery_id和open_time扫描器每次启动先检查pending凡是open_time已过去的动态转去抓一次开奖结果根据评论区里是否出现“恭喜中奖”或是否收到中奖提示把记录从pending移到finished并打一条WARNING提醒你去看。for item in state.pending: if item[open_time] now: result check_lottery_result(session, item[lottery_id]) state.move_to_finished(item, result)逻辑说明把开奖检查也托管给同一个常驻任务就实现了从扫描、参与、开奖到结果通知的全链路托管。参数说明check_lottery_result的实现建议复用动态评论拉取接口只关注官方抽奖小助手发出的那条置顶评论中奖名单以那条置顶评论为准这样可以显著减少请求量。我自己早期栽过的跟头就是只做了参与托管、没做结果托管几十条抽奖参与完就忘了一个月后才想起来核对中奖的早过了填收货地址的时效。后来把状态文件拆成pending和finished两部分每天由计划任务自动推进状态心态一下子轻松很多。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询