资讯动态

Python自动化追踪B站UP主更新:从爬虫到消息推送的完整实践

发布时间:2026/8/15 5:41:53 来源:尧图企业网站定制
1. 项目概述与核心价值最近在折腾一个挺有意思的小项目起因是我关注了上百个B站UP主但发现一个挺头疼的问题我经常错过一些我真正想看的UP主的新视频。B站APP的推荐流信息太杂而手动去每个UP主主页翻看又太费时间。就在我琢磨着有没有什么自动化工具能解决这个痛点时我在GitHub上发现了Artistkisa/bilibili-up-update-tracker这个项目。简单来说这是一个专门用来追踪B站UP主更新动态的工具它能够定期检查你指定的UP主是否发布了新视频并通过你设定的方式比如邮件、Telegram机器人等及时通知你。这个工具的核心价值在于它解决了信息过载时代下的“精准订阅”问题。对于像我这样的深度B站用户或者内容创作者、市场分析人员来说及时获取特定领域UP主的更新动态至关重要。无论是为了学习、竞品分析还是纯粹的娱乐追更手动追踪的效率都太低下了。这个项目用技术手段实现了自动化监控把我们从重复的“刷新-查看”劳动中解放出来让我们能把精力集中在内容消费本身。它就像一个为你定制的、永不疲倦的“更新雷达”只关注你关心的频道过滤掉所有无关的噪音。2. 项目架构与核心组件解析2.1 整体设计思路bilibili-up-update-tracker的设计思路非常清晰遵循了经典的“数据获取-处理-通知”流水线模式。整个项目可以看作一个轻量级的、专为B站场景设计的爬虫与消息推送系统的结合体。它的目标不是做一个功能庞杂的B站客户端而是聚焦于“更新追踪”这一个核心功能并将其做到极致。这种单一职责的设计使得项目结构清晰易于理解和二次开发。项目的运行逻辑可以拆解为以下几个核心环节目标管理维护一个需要追踪的UP主列表通常以B站UID形式存储。数据抓取定期例如每10分钟、每小时访问B站API或网页获取列表中每个UP主的最新视频信息。状态比对将本次抓取到的最新视频信息如视频BVID、发布时间与本地存储的上一次记录进行比对。更新判断如果发现新的视频记录即本次抓取的“最新视频”与本地记录的“最新视频”不一致则判定为有更新。消息生成与推送根据更新内容生成包含视频标题、链接、封面等信息的通知消息并通过配置好的渠道如邮件、Webhook发送出去。状态更新将本地存储的UP主最新视频信息更新为刚发现的新视频为下一次比对做准备。这个闭环流程确保了追踪的持续性和准确性。整个系统的健壮性依赖于B站数据接口的稳定性、比对逻辑的准确性以及通知渠道的可靠性。2.2 核心组件与技术栈要实现上述流程项目依赖几个关键的技术组件网络请求与数据解析这是项目的基石。通常使用像requests、aiohttp这样的HTTP库来模拟请求获取B站的数据。数据源可能是公开的API如space.bilibili.com/ajax/member/getSubmitVideos或通过解析UP主主页HTML。解析环节则会用到json模块处理API返回的数据或者用BeautifulSoup、lxml等库解析HTML。这里有一个关键点需要处理好B站的反爬机制比如请求头User-Agent, Referer的模拟、Cookies的管理对于某些需要登录态的信息以及请求频率的控制避免对B站服务器造成压力或被封禁IP。数据存储需要一个轻量级的方式来持久化存储每个UP主“上一次检查到的最新视频”状态。简单的实现可以用文件如JSON、SQLite数据库来存储。例如一个up_status.json文件记录着{“UID_123456”: {“latest_bvid”: “BV1xx”, “latest_pubdate”: 1625097600}}。更复杂的版本可能会用到SQLite甚至Redis以支持更快的查询和更复杂的状态管理比如追踪历史更新记录。定时任务调度追踪需要定期执行。最直接的方式是使用操作系统的定时任务如Linux的cronWindows的任务计划程序来周期性地运行脚本。在Python项目中更优雅的方式是使用schedule或apscheduler这样的库在脚本内部实现定时循环使得整个项目可以作为一个常驻服务运行。消息通知模块这是与用户交互的出口。项目的实用性很大程度上取决于通知的及时性和便利性。常见的实现包括邮件通知 (SMTP)通过smtplib库配置发件邮箱如QQ邮箱、163邮箱或企业邮箱、SMTP服务器和授权码将更新信息以邮件形式发出。这是最通用、门槛较低的方式。Telegram Bot利用Telegram Bot API用户与Bot互动添加订阅Bot主动推送更新。这种方式即时性强交互性好适合移动端用户。Server酱、PushPlus等第三方推送服务调用这些服务提供的API可以将消息推送到微信、钉钉等平台。Webhook将更新信息以结构化数据JSON的形式POST到一个预设的URL。这种方式非常灵活可以对接自己的服务器、自动化工具如Zapier、IFTTT或即时通讯软件的自建机器人。配置管理一个良好的项目应该将所有可配置项如UP主UID列表、检查间隔、通知渠道的密钥/Token、发件邮箱信息等外置通常通过一个配置文件如config.yaml或config.ini或环境变量来管理。这样无需修改代码即可调整项目行为也便于在不同环境部署。3. 从零开始实现一个简易追踪器理解了核心思路后我们可以动手实现一个基础版本。这个版本将使用Python实现通过B站API获取数据、用JSON文件存储状态、并通过邮件发送通知的功能。3.1 环境准备与依赖安装首先确保你的系统安装了Python 3.7或以上版本。然后创建一个新的项目目录并初始化虚拟环境推荐以隔离依赖mkdir bilibili-tracker cd bilibili-tracker python -m venv venv # Windows: venv\Scripts\activate # Linux/Mac: source venv/bin/activate安装必要的Python库pip install requests schedule这里我们选择requests用于网络请求schedule用于实现简单的定时任务。对于生产环境apscheduler是更强大的选择。3.2 核心代码实现接下来我们创建几个核心文件。1. 配置文件 (config.yaml)# 需要追踪的UP主列表值为B站UID up_list: - 546195 # 老番茄 - 777536 # 某幻君 - 1580990 # 罗翔说刑法 # 检查间隔秒 check_interval: 600 # 每10分钟检查一次 # 邮件通知配置 email: enabled: true smtp_server: smtp.qq.com # 以QQ邮箱为例 smtp_port: 587 sender_email: your_emailqq.com sender_password: your_authorization_code # 注意是授权码不是邮箱密码 receiver_email: receiverexample.com重要提示邮箱密码处请务必使用“授权码”。以QQ邮箱为例需要在设置-账户中开启SMTP服务并生成专属授权码。直接使用登录密码通常会失败。2. 状态存储与加载模块 (storage.py)import json import os STATUS_FILE up_status.json def load_status(): 加载UP主状态 if not os.path.exists(STATUS_FILE): return {} try: with open(STATUS_FILE, r, encodingutf-8) as f: return json.load(f) except (json.JSONDecodeError, IOError): return {} def save_status(status): 保存UP主状态 with open(STATUS_FILE, w, encodingutf-8) as f: json.dump(status, f, ensure_asciiFalse, indent2) def update_up_status(uid, latest_bvid, latest_title, latest_pubdate): 更新单个UP主的状态 status load_status() status[str(uid)] { latest_bvid: latest_bvid, latest_title: latest_title, latest_pubdate: latest_pubdate } save_status(status)3. B站数据获取模块 (bilibili_client.py)import requests import time def get_up_latest_video(uid): 通过B站API获取UP主最新视频信息 参考API: https://api.bilibili.com/x/space/arc/search?mid{uid}ps1 url fhttps://api.bilibili.com/x/space/wbi/arc/search # 注意B站API时有更新参数可能变化。当前需要mid用户ID和ps每页数量 params { mid: uid, ps: 1, # 只取最新一条 pn: 1, # 第一页 order: pubdate # 按发布时间排序 } headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36, Referer: fhttps://space.bilibili.com/{uid} } try: response requests.get(url, paramsparams, headersheaders, timeout10) response.raise_for_status() data response.json() if data[code] 0 and data[data][list][vlist]: video data[data][list][vlist][0] return { bvid: video[bvid], title: video[title], pubdate: video[created], # 时间戳 author: video[author] } else: print(f获取UID {uid} 数据失败或暂无视频: {data.get(message)}) return None except requests.exceptions.RequestException as e: print(f请求UID {uid} API时出错: {e}) return None except (KeyError, IndexError) as e: print(f解析UID {uid} 返回数据时出错: {e}, 原始数据: {data}) return None4. 邮件通知模块 (notifier.py)import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart import yaml def load_config(): with open(config.yaml, r, encodingutf-8) as f: return yaml.safe_load(f) def send_email_notification(up_name, video_info): 发送邮件通知 config load_config() email_cfg config.get(email, {}) if not email_cfg.get(enabled, False): return sender email_cfg[sender_email] receiver email_cfg[receiver_email] password email_cfg[sender_password] subject f【B站追更】{up_name} 发布了新视频 body f html body h2{up_name} 更新啦/h2 pstrong视频标题/strong{video_info[title]}/p pstrong发布时间/strong{time.strftime(%Y-%m-%d %H:%M:%S, time.localtime(video_info[pubdate]))}/p pstrong视频链接/stronga hrefhttps://www.bilibili.com/video/{video_info[bvid]}点击观看/a/p br psmall此邮件由B站UP主更新追踪器自动发送。/small/p /body /html msg MIMEMultipart(alternative) msg[From] sender msg[To] receiver msg[Subject] subject msg.attach(MIMEText(body, html, utf-8)) try: server smtplib.SMTP(email_cfg[smtp_server], email_cfg[smtp_port]) server.starttls() # 启用TLS加密 server.login(sender, password) server.sendmail(sender, receiver, msg.as_string()) server.quit() print(f邮件通知已发送给 {receiver}) except Exception as e: print(f发送邮件失败: {e})5. 主循环与调度 (main.py)import schedule import time from datetime import datetime import yaml from bilibili_client import get_up_latest_video from storage import load_status, update_up_status from notifier import send_email_notification def check_updates(): 执行一次检查任务 print(f[{datetime.now().strftime(%Y-%m-%d %H:%M:%S)}] 开始检查更新...) with open(config.yaml, r, encodingutf-8) as f: config yaml.safe_load(f) up_list config[up_list] current_status load_status() for uid in up_list: print(f 检查 UID: {uid}) latest_video get_up_latest_video(uid) if not latest_video: continue up_name latest_video[author] latest_bvid latest_video[bvid] # 检查是否有更新 if str(uid) in current_status: stored_bvid current_status[str(uid)].get(latest_bvid) if stored_bvid latest_bvid: print(f {up_name} 暂无新视频) continue else: print(f !! 发现更新: {up_name} - {latest_video[title]}) # 发送通知 send_email_notification(up_name, latest_video) else: # 首次运行记录状态但不通知 print(f 首次记录 {up_name} 的最新视频: {latest_video[title]}) # 更新状态 update_up_status(uid, latest_bvid, latest_video[title], latest_video[pubdate]) print(本轮检查完成。\n) def main(): # 立即执行一次 check_updates() # 配置定时任务 interval config.get(check_interval, 600) schedule.every(interval).seconds.do(check_updates) print(f追踪器已启动每 {interval} 秒检查一次。) while True: schedule.run_pending() time.sleep(1) if __name__ __main__: main()3.3 首次运行与测试按照注释填写config.yaml中的邮箱配置使用授权码和你想追踪的UP主UID。在项目根目录下运行python main.py。程序会立即检查一次并在控制台打印日志。如果发现新视频或首次运行会尝试发送邮件。检查你的收件箱包括垃圾邮件箱查看是否收到通知。至此一个最基础的、功能完整的B站UP主更新追踪器就搭建完成了。它虽然简陋但涵盖了核心逻辑。Artistkisa/bilibili-up-update-tracker项目的开源版本其原理与此类似但通常包含了更健壮的异常处理、更多的通知渠道如Telegram Bot、Web管理界面以及Docker部署支持。4. 高级功能扩展与优化思路基础版本跑通后我们可以从稳定性、易用性和功能性上进行大量优化这也是开源项目迭代的方向。4.1 提升稳定性与健壮性异常处理与重试机制网络请求可能失败API可能变更。需要在数据获取函数中加入更完善的异常捕获和重试逻辑。例如使用tenacity库为请求添加指数退避重试。from tenacity import retry, stop_after_attempt, wait_exponential retry(stopstop_after_attempt(3), waitwait_exponential(multiplier1, min4, max10)) def get_up_latest_video_retry(uid): return get_up_latest_video(uid)API失效应对B站的API接口并非完全公开稳定可能变更或增加鉴权。一个备选方案是使用“无头浏览器”如playwright或selenium来模拟浏览器访问UP主主页然后解析HTML。虽然更重但通常更稳定。也可以准备多个API备用一个失败则尝试另一个。状态存储升级将JSON文件换成SQLite数据库。可以轻松存储更长时间的历史记录方便查询某个UP主过去一段时间的更新频率甚至实现“标记已读”、“按标签分类UP主”等功能。import sqlite3 conn sqlite3.connect(tracker.db) c conn.cursor() # 创建表 c.execute(CREATE TABLE IF NOT EXISTS updates (uid TEXT, bvid TEXT, title TEXT, pubdate INTEGER, notified INTEGER DEFAULT 0)) conn.commit()4.2 丰富通知渠道与交互方式集成Telegram Bot通过BotFather创建一个新的Telegram Bot获取Token。使用python-telegram-bot库。用户可以向Bot发送/subscribe UID来订阅Bot将UID存入数据库。在check_updates函数中当发现更新时除了发邮件也遍历订阅了该UP主的用户调用bot.send_message(chat_iduser_chat_id, textupdate_msg)。 这种方式交互性极强是很多开源项目的首选。支持Webhook这提供了最大的灵活性。在配置文件中添加一个webhook URL。当有更新时将视频信息组装成JSON格式用requests.post发送到该URL。这样你可以用这个Webhook触发其他自动化流程比如自动下载视频、转发到Discord/Slack、记录到Notion数据库等。def send_webhook_notification(webhook_url, video_info): payload { event: bilibili_update, data: video_info } requests.post(webhook_url, jsonpayload, timeout5)消息模板化允许用户自定义通知消息的格式。可以在配置文件中增加一个message_template字段使用类似Jinja2的语法让用户自由定义标题和正文支持变量如{{up_name}},{{video_title}},{{video_url}}。4.3 构建用户友好的管理界面对于非技术用户命令行和配置文件不够友好。可以增加一个简单的Web管理界面。使用轻量级Web框架如Flask或FastAPI。设计几个核心接口GET /api/ups获取当前订阅的UP主列表及其最新视频状态。POST /api/ups添加一个新的UP主订阅输入UID或主页链接。DELETE /api/ups/uid取消订阅。GET /api/history获取更新历史记录。GET /提供一个简单的HTML页面展示上述信息并提供添加/删除的表单。部署这个Web服务可以运行在本地局域网也可以部署到云服务器配合反向代理如Nginx和进程管理如systemd或Supervisor使其在后台稳定运行。4.4 部署与运维考量容器化部署使用Docker和Docker Compose。创建一个Dockerfile来定义Python环境、安装依赖、复制代码。再编写一个docker-compose.yml来定义服务、挂载配置文件和数据卷用于持久化状态数据库。这样在任何支持Docker的机器上一句docker-compose up -d就能启动服务极大简化了部署。日志记录使用Python的logging模块替代print将日志输出到文件并设置日志轮转方便问题排查。监控与告警除了视频更新通知还可以为追踪器本身设置监控。例如如果连续多次检查失败或者服务进程意外退出可以通过另一个监控通道如Server酱发送告警给管理员。5. 常见问题与实战排坑指南在实际搭建和运行过程中你几乎一定会遇到下面这些问题。这里是我踩过坑后总结的经验。5.1 数据获取失败API变更与反爬问题现象脚本运行一段时间后突然无法获取到数据返回空列表或错误码。排查与解决手动验证API首先在浏览器中直接访问脚本中使用的API URL带上参数查看返回的JSON数据是否正常。如果浏览器访问也出错说明API可能已变更或需要额外的参数如wbi签名。检查请求头B站对请求头有基本校验。确保你的User-Agent是常见的浏览器标识并正确设置Referer为UP主空间页。处理WBI签名B站部分API启用了WBI签名验证。如果你发现API返回-403或提示签名错误就需要实现签名算法。这需要从网页中提取img_key和sub_key并对参数进行排序和MD5签名。这是一个相对复杂的步骤通常需要参考最新的B站逆向工程资料。遇到此情况一个暂时的规避方案是回退到HTML解析。切换数据源如果某个API不稳定准备好备选方案。例如主用space.bilibili.com/ajax/member/getSubmitVideos备用api.bilibili.com/x/space/arc/search再备用HTML解析。在代码中实现降级逻辑。控制请求频率过于频繁的请求会导致IP被暂时限制。务必在配置中设置合理的检查间隔如10-30分钟一次对于大量UP主可以考虑错峰检查。5.2 通知发送失败渠道配置问题邮件发送失败错误smtplib.SMTPAuthenticationError99%的情况是密码错误。请再次确认使用的是授权码不是邮箱登录密码。QQ邮箱/163邮箱等需要先在网页邮箱设置中开启SMTP服务并生成授权码。发件邮箱地址填写正确。错误连接超时或被拒绝检查smtp_server和smtp_port是否正确。常见端口有465(SSL) 和587(TLS)。我们的示例使用了587和starttls()。如果使用465端口则需要用SMTP_SSL。邮件被收进垃圾箱优化邮件内容。使用规范的From/To头正文不要过于简单可以加入UP主名称、视频标题等个性化信息。如果可能使用域名邮箱而非免费邮箱发送成功率更高。Telegram Bot 无响应Bot没有收到消息检查你是否已经向Bot发送过/start命令来激活对话。Bot能收到命令但无法主动推送确保你保存了用户的chat_id。当用户向Bot发送任意消息时在python-telegram-bot的更新对象update中可以通过update.effective_chat.id获取到这个唯一的chat_id并将其与用户的订阅关系一起存入数据库。推送消息时必须使用这个chat_id。5.3 状态管理与误报问题有时UP主删除了最新视频或者发布了“动态”而非视频导致脚本误判为“新视频”。解决方案更精确的比对不要只比对最新的BVID。可以同时比对BVID发布时间戳。因为BVID可能重用极罕见但时间戳是递增的。如果发现本地记录的时间戳比获取到的“最新视频”时间戳还新说明UP主可能删除了视频此时应更新本地记录但不发送通知。区分内容类型仔细分析API返回的数据结构。B站的“稿件”可能包含视频、专栏、音频等。确保你筛选的是typeid或typename为视频类型的条目避免将专栏更新误报为视频更新。引入“确认窗口”对于首次发现的“新视频”不立即通知而是等待下一次检查周期。如果连续两个周期都检测到同一个“新”视频再发送通知。这可以过滤掉一些临时状态如视频审核中、UP主立即删除等。5.4 性能与扩展性问题当订阅的UP主数量达到几百上千时串行检查耗时很长可能超过设定的间隔。优化方案异步请求使用asyncio和aiohttp库将所有的网络请求改为异步并发。这可以极大缩短单次检查的总耗时尤其适合UP主数量多的情况。import aiohttp import asyncio async def fetch_up(session, uid): async with session.get(api_url, params{mid: uid}) as resp: return await resp.json() async def check_all_ups(up_list): async with aiohttp.ClientSession() as session: tasks [fetch_up(session, uid) for uid in up_list] results await asyncio.gather(*tasks, return_exceptionsTrue) # 处理results分布式检查如果UP主数量极其庞大可以考虑将UP主列表分片由多个工作进程或不同的服务器节点分别负责一部分UP主的检查并通过一个中心服务汇总结果并发送通知。搭建这样一个工具的过程本身就是一次非常棒的全栈实践涵盖了网络爬虫、数据存储、任务调度、消息推送、甚至简单的Web开发。当你成功运行起自己的追踪器并准时收到心仪UP主的更新推送时那种“自动化”带来的满足感是单纯使用现成APP无法比拟的。更重要的是你完全掌控了自己的订阅流数据隐私和定制自由度都掌握在自己手中。

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

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

免费获取报价