资讯动态

BiliRaffle:B站动态抽奖自动化监听组件的设计与实现

发布时间:2026/9/9 3:39:39 来源:尧图企业网站定制
简介BiliRaffle 是一套基于 C# 与 .NET Framework 4.5 开发的 B 站动态抽奖组件主要面向希望为 Up 主动态自动完成转发、点赞、评论并参与抽奖的开发者也适合不想手动盯动态的普通用户。解压后运行 BiliRaffle.exe 即可使用也可用 Visual Studio 打开工程二次开发。包体仅 60KB共 32 个文件包含 12 个 cs 源码文件、4 个 xaml 界面文件以及 config、xml、dll、sln、csproj、license、readme 等配套文件。源码按 LoginWindow、MainWindow、Raffle、ViewModel、Converter 等模块组织涵盖了登录授权、动态监测、抽奖判断、界面绑定与命令封装。借助这份资源读者既能掌握 B 站开放接口的调用流程与抽奖规则判断思路也能学习 WPF 桌面客户端中窗口跳转、数据绑定、值转换器等常见工程写法还可基于已有代码快速扩展定时任务、多账号管理等能力。目前已有 694 人学习下载适合有一定 C# 基础、希望接触真实第三方平台项目的读者。 我从一次“陪跑”经历开始了这个项目。当时刷到一位关注的UP主发动态抽奖规则是转发动态并且关注账号。我按要求转发了结果开奖那天发现自己压根没转发成功——动态被夹了或者因为时间记错错过了。这种事不是第一次手动盯着动态、翻历史记录、逐条判断要不要转发确实费神。于是我就想能不能做一个组件专门盯B站动态里的抽奖内容自动识别规则做到了不漏、不乱、可追踪。这就是BiliRaffle的起因一个围绕B站动态抽奖场景的自动化监听组件基于公开接口做数据拉取通过规则引擎判断抽奖动态再按配置决定是提醒用户还是半自动参与。适合正在学异步爬虫、定时任务、API接入的开发者也适合想省心跟进抽奖但不希望全程手动刷新页面的普通用户。我把它定位成“组件”而不是“脚本”是因为从一开始就打算拆成可复用的模块动态监听、抽奖规则解析、任务调度、通知推送可以各自独立跑。这个项目的核心不是“帮我抽奖”而是“帮我整理好所有抽奖信息并保证不错过动作节点”。这篇文章会把设计思路、关键实现、部署过程和踩坑记录完整拆出来尽量让想自己动手的人少走弯路。1. 项目背景与核心思路1.1 抽奖动态的常见形态与用户痛点B站动态抽奖的玩法并不复杂但细节很碎。绝大多数抽奖动态要求用户完成“关注UP主 转发动态 评论区留言”有的还会附加“好友”“点赞”“收藏视频”等额外条件。开奖时间也不统一有的是固定时间有的是三五天后手动开还有的是点赞数到某个量级后才开。这些条件分散在动态文案里有的用加粗文字写明白了有的藏在表情包后面还有的干脆写在长图里。人工判断的效率很低尤其是关注列表超过几十个UP主之后每天刷动态的时间成本会高得吓人。另一个痛点是错过开奖后无法及时复盘。虽然B站的“抽奖平台”接口会记录参与状态但用户绝大多数情况下不会主动去查。等到翻动态时才发现错过参与已经没有任何补救余地。BiliRaffle要解决的就是把“发现抽奖动态”“解析参与条件”“记录参与动作”这条链路变成自动化流程。1.2 整体设计思路人机结合的半自动模式刚开始我设想过全自动参与检测到抽奖动态后直接调用转发/关注接口全程无人值守。但后来我放弃了全自动改成默认半自动原因是风险和实用性的平衡。全自动看似方便实际很脆弱。抽奖规则千奇百怪有些动态里写的是“转发本动态并关注我评论区留下暗号”机器很难理解“暗号”是评论区第一层内容另一些动态会要求“必须公开可见”自动操作容易因为Cookie或权限配置问题导致失败而且失败后很难察觉。更现实的问题是平台风控。一个账号在几十秒内连续点赞、转发、关注多个账号很容易被判定为异常行为。所以我把组件设计成两层第一层负责“发现和解析”全程自动第二层负责“执行互动”默认只做提醒和跳转用户在自己手机上确认后操作。如果需要半自动执行可以在配置里显式开启并设置严格的频率上限。这种设计还有一个好处降低了项目对脆弱接口的依赖。执行动作的人不是程序而是用户组件只需要做好“信息管道”长期稳定跑着也不容易出问题。2. 核心技术点解析动态数据流与抽奖识别2.1 动态数据来源与API选型要监听B站动态首先得有数据源。B站有两套常见的动态接口老版的api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail用于拉取单条动态详情新版的api.bilibili.com/x/polymer/web-dynamic/v1/feed/space用于获取指定用户的动态列表。我采用的是新版的space接口它返回的数据结构更规整包含动态ID、发布时间、转发信息、图片内容、文本内容等适合做解析。这个做法的前提是只使用B站公开的HTTP接口不涉及任何逆向工作。接口返回JSON之后项目里统一封装了一层DynamicFetcher负责把原始响应转成内部的数据模型。为什么要封装一层因为B站接口经常调参返回字段名偶尔会变。集中封装之后接口变化时只需要改一个文件不用牵扯到业务逻辑。调用接口时容易忽略一个细节空间动态接口返回的内容分“新动态”和“历史动态”翻页参数是offset字符串而不是简单的页码。如果你用循环去翻页需要把上一页返回的offset原样传给下一页。我一开始直接把页码当偏移量传结果第二页开始永远拿到的是重复数据。2.2 抽奖文案识别不能只靠“抽奖”两个字判断一条动态是否属于抽奖最直接的想法是正则匹配“抽奖”。但实际跑下来会发现两个问题。第一是误报。很多动态会提到“抽奖结果公示”“抽奖活动已结束”并不代表现在还有抽奖。第二是漏报。文案写“转发送手办”“评论抽一个幸运儿”“本条动态揪一位朋友送周边”这些都没出现“抽奖”二字但确实是抽奖动态。我的处理方法分了三层第一层是关键词召回用一个关键词表包含“抽奖”、“抽送”、“送周边”、“抽一位”、“揪一位”等召回候选动态。第二层是排除词过滤比如“已开奖”、“开奖结果”、“公示”、“活动结束”命中排除词就跳过。第三层是规则解析从文案中提取参与条件提取结果结构化后用于后面的任务生成。三层都放在独立模块里方便后面替换成更复杂的文本分类模型。实测下来关键词召回加排除词过滤的准确率已经足够日常使用误报率可以控制在5%以内。2.3 参与条件的结构化解析这是整个项目里最有意思的部分。抽奖规则虽然多样但基本可以拆成几个维度是否要求关注UP主、是否要求转发、是否要求评论、是否要求好友、是否要求点赞、是否要求收藏。针对这些维度我用正则和关键词组合做逐行扫描。比如“关注转发”是高频组合文案通常写成“关注我并转发本条动态”、“转发关注缺一不可”。解析逻辑就是先判断是否存在“关注”类词再判断是否存在“转发/转赞”类词。如果文案里出现“评论/留言/回复”就析出评论要求如果出现“好友/艾特”就析出要求。解析结果会存成字典例如{ need_follow: True, need_forward: True, need_comment: True, need_at: False, need_like: False, need_favorite: False, raw_text: ……原始文案…… }这里有个容易踩坑的点不要只依赖关键词因为同一个词在不同语境下含义会变。“关注后抽奖”和“关注我评论区说说你的想法”是两种不同的动作强度。前者只要点击关注即可后者还要求评论内容。所以我会把“评论方式”单独提出来如果文案里包含“评论想法/聊聊/说说”等词就把评论动作标记为“需要带文字”而不是单纯点个赞了事。这个细节直接影响了后续提醒信息的质量。3. 组件架构与核心实现3.1 模块划分与职责边界BiliRaffle整体分成五个模块每个模块只负责一件事这也是它和普通脚本最大的区别Listener负责定时拉取目标用户的动态列表做增量发现。Parser负责动态内容解析判断是否为抽奖动态并提取参与条件。Scheduler负责任务调度和去重决定哪些动态需要处理。Notifier负责通知推送把解析结果通过Server酱、钉钉机器人或邮件发出去。Executor负责执行具体互动操作默认不启用只在配置中显式打开时才工作。模块之间通过内部事件队列解耦。Listener发现新动态后把原始数据扔进队列Parser消费队列产出解析结果Scheduler根据结果生成任务Notifier收到任务后通知用户。这样做的好处是如果某个环节异常其他模块不会跟着崩。3.2 任务调度与增量更新设计调度上我用了APScheduler它是一个很成熟的Python定时任务框架。每个用户一个独立任务每隔三分钟拉取一次最新动态。为什么是三分钟而不是更短因为B站动态列表接口本身有缓存拉的太频繁不仅容易触发频率限制而且拿到的数据不一定是最新的。三分钟对我来说是稳定性和时效性的平衡点。增量更新依靠动态ID去重。每拉取一次列表把所有动态ID存入一个set新动态只要不在这个集合里就进入处理流程。这里有一个细节B站动态ID是递增的趋势但同一个动态被编辑后ID不变。如果你只记录已处理的ID可能会导致已处理动态被编辑成抽奖文案后漏掉。解决方法是同时记录“处理时间”和“动态ID”只对最近24小时内出现过、且再次出现时文案哈希值变化的动态做重新解析。这个功能不是一开始就有的是踩了几天漏抽奖的坑之后补上的。多用户拉取时还需要考虑接口频率。我这里采用了均匀分散策略把所有用户任务随机分布在一个时间窗口内而不是整点同时触发。否则三个用户同时发起请求很容易被限流。3.3 登录态维护与风险控制B站动态列表接口的部分数据不需要登录也能访问但涉及关注、转发等操作时必须要有有效的Cookie。这个项目里的做法是让用户手动从浏览器复制SESSDATA和bili_jct写入配置文件。这里有个很重要的安全问题不要输出日志里的Cookie。最初版本我把请求头直接放进调试日志打印出来后很久都没注意。后来偶然翻日志发现Cookie完整暴露在文件里吓出一身冷汗。修复方案是把请求头单独封装日志里只打印用户ID的前几位和登录状态不打印完整凭据。风控上有一条铁律所有自动化请求必须带User-Agent并且请求间隔要加入随机抖动。不要用恒定的0.5秒间隔那比每秒3次请求更像机器行为。我用的是0.8到1.5秒之间的随机值操作类接口再额外增加1到2秒延迟。这不是为了破坏什么规则而是给自己减少不必要的麻烦。4. 实操过程与部署指南4.1 运行环境与依赖准备项目基于Python 3.10异步HTTP客户端用httpx定时任务用APScheduler日志用loguru。安装依赖的命令很简单pip install httpx apscheduler loguru pyyaml配置文件用YAML格式主要为了可读性。运行入口在main.py启动后会加载配置、初始化各模块然后启动调度器。如果你打算部署在服务器上建议配合systemd或supervisor做进程守护毕竟定时任务进程如果挂了没人知道监控就失去意义。4.2 配置文件核心项解析一个最小可用的config.yaml长这样users: - uid: 1234567 name: 示例UP主 enabled: true interval_seconds: 180 keywords: - 抽奖 - 抽送 - 揪一位 exclude_words: - 已开奖 - 公示 notifier: provider: serverchan send_key: your-send-key executor: enabled: false max_daily_actions: 20 min_interval_seconds: 5里面的executor就是之前说的半自动执行模块。默认是关闭状态。即使打开了我也设置了每日动作上限并且每个操作之间至少间隔5秒。4.3 核心代码片段抽奖规则解析下面这段是Parser里最核心的函数作用是把一条动态的文本内容转换成语义化的参与条件import re AWARD_KEYWORDS [抽奖, 抽送, 送周边, 揪一位, 抽一位] EXCLUDE_WORDS [已开奖, 开奖结果, 公示, 活动结束] def parse_raffle_info(text: str) - dict | None: # 先做排除词过滤 if any(word in text for word in EXCLUDE_WORDS): return None # 再判断是否是潜在抽奖动态 if not any(keyword in text for keyword in AWARD_KEYWORDS): return None info { need_follow: bool(re.search(r关注(我|本UP|账号), text)), need_forward: bool(re.search(r转发|转赞, text)), need_comment: bool(re.search(r评论|留言|回复, text)), need_at: bool(re.search(r|艾特, text)), need_like: bool(re.search(r点赞|一键三连, text)), need_favorite: bool(re.search(r收藏, text)), } return info这段代码看着简单但已经能覆盖一半以上的抽奖动态。你可以根据自己的需求扩充关键词表。需要提醒的是正则表达式里的中文分词依赖关键词的拼写习惯比如“关注UP主”和“关注我”需要分别覆盖到。4.4 通知推送与用户体验解析结果最终要送达用户手里。我在通知消息里会同时包含原始动态链接、参与条件摘要、下一步动作提示。Server酱推送示例标题新的抽奖动态 正文 UP主示例UP主 动态ID123456789 参与条件需要关注、转发、评论 截止时间未指定 前往查看https://t.bilibili.com/123456789推送内容不需要太复杂关键是让用户看到消息时能快速判断是否需要处理。有些用户关心的不是距离开奖还有多久而是自己是否已经参与了。所以在执行模块开启时我会在每天固定时间检查已参与动态的状态把“已参与”“待参与”分类列出。5. 常见问题与排查技巧5.1 接口返回403或412基本是风控拦截遇到403时第一反应不要是换IP而是检查Cookie是否有效。B站的风控往往是先校验Cookie再校验IP。Cookie过期、被踢下线都会导致403。412则是更典型的“请求行为异常”说明请求频率过高或者Header特征过于单一。排查思路是先把请求频率降到最低比如每次拉取间隔拉大到5分钟然后手动用浏览器访问一次接口确认Cookie可用。如果手动访问正常而程序访问异常重点检查请求头。必须包含浏览器常用的Referer、User-Agent、Origin等字段。5.2 动态漏抓或重复处理漏抓的常见原因是对offset处理不当。新版接口返回的offset是一个字符串不是简单的数字页数。如果你自己做了分页可能会因为offset过期导致漏掉中间的动态。重复处理则和去重集合的内存生命周期有关。如果你把去重集合放在进程内存里进程重启后集合清空重启那一刻会把之前所有动态重新当作新动态处理。解决方法是把已处理动态ID持久化到本地SQLite或Redis启动时加载进去。5.3 定时任务不生效或时间对不上APScheduler默认使用系统时区。如果服务器是UTC时间而 B站动态里返回的时间戳是北京时间你在配置里写“每天10点检查已参与状态”实际触发时点会差8个小时。这个问题排查起来很隐蔽因为你盯着服务器本地时间看可能是正常的。我的建议是显式设置调度器的时区from apscheduler.schedulers.asyncio import AsyncIOScheduler scheduler AsyncIOScheduler(timezoneAsia/Shanghai)同时解析动态文案里的开奖时间时要把B站返回的秒级时间戳统一转换为带时区的日期对象不要直接用本地时间格式化否则不同机器上跑会得到不同结果。5.4 多账号同时运行时的频率叠加如果你用同一个Cookie跑多个账号本质上是多个身份共用一个IP和会话频率限制会叠加。我建议多账号场景下为每个账号配置独立的Cookie同时把每个账号的请求间隔错开。不要一个账号的请求任务结束两秒后另一个账号立刻发起请求。最简单的做法是在调度器里为不同账号设置不同的interval_seconds并且加一个全局的随机初始延迟。6. 边界思考与后续扩展6.1 自动化参与不是越自动越好这个项目做的时间越久我越觉得“自动参与”不是核心信息整理和提醒才是。真正被用户需要的是“知道什么时候该做什么”而不是让程序替自己做决定。B站抽奖本身是一个注重用户互动的场景如果所有人都是用机器去抢体验会变得很糟。所以我很坚持半自动模式也建议所有想复制这个项目的人把它当作学习组件和提醒工具来用而不是用来规避平台规则。如果确实需要开启自动互动请务必限制频率、控制每日操作总数并且确认每个操作都符合你账号的正常使用习惯。工具本身是中性的但使用方式会影响工具能走多远。6.2 这个组件可以继续长成什么样目前BiliRaffle已经能够稳定运行后续还可以扩展几个方向中奖率统计记录每次参与抽奖的动态、开奖时间、是否中奖形成个人数据报表。抽奖倒计时根据动态里写的开奖时间去做倒计时提醒避免开奖后忘记查。多平台适配把“动态抽取”逻辑抽离出来可以适配微博、小红书等类似场景。私信通知通过B站私信API发送提醒减少对第三方推送服务的依赖。最后一个方向我建议优先做因为它能彻底摆脱“还得让用户去申请Server酱Key”的依赖。这个组件陆陆续续改了三个月最大的体会是不要把“自动化”想成是“替人做决定”而是帮人节省注意力。它每天跑在我的服务器上真正的作用不只是提醒我参与抽奖而是让我不用再花几十秒甚至几分钟去翻那些无关动态。最后再分享一个小技巧监听间隔不要设得太短B站动态推送本身有延迟设成3分钟比30秒更稳而且几乎不会触发风控。先让组件稳定跑起来再慢慢优化细节。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价