1. 项目概述一个B站UP主动态追踪器的诞生最近在捣鼓一个挺有意思的小玩意儿我把它叫做“B站UP主动态追踪器”。说白了这就是一个能帮你自动监控Bilibili上你关注的UP主有没有发布新视频、新动态或者直播开播的小工具。灵感来源于我自己作为一个老B站用户关注了上百个UP主每天手动去刷新主页、查看动态效率实在太低还经常错过一些喜欢的UP主半夜“诈尸”更新的视频。这个项目Artistkisa/bilibili-up-update-tracker核心目标就是解决这个痛点。它不是一个复杂的全功能B站客户端而是一个轻量级、专注的“哨兵”。你可以把它想象成一个24小时不休息的私人助理它只干一件事盯紧你指定的UP主列表一旦有风吹草动新内容发布就立刻通过你预设的方式比如邮件、微信、Telegram机器人通知你。这样一来你就不用再被信息流淹没或者因为错过更新而懊恼了。它适合谁呢首先是像我这样的深度B站用户关注列表很长有强烈的信息筛选需求。其次是内容创作者或运营人员需要及时追踪竞品或同领域UP主的更新动态。再者对于一些学习类、知识类UP主的粉丝及时获取更新意味着能第一时间跟进学习。这个工具的技术栈并不高深主要涉及网络请求、数据解析、定时任务和消息推送非常适合有一定Python基础的朋友用来练手也能给完全的新手展示一个完整的小项目是如何从想法到落地的。2. 核心设计思路与架构选型2.1 需求拆解与技术选型逻辑做一个追踪器听起来简单但拆开来看核心流程就四步获取UP主信息 - 解析最新动态 - 与历史记录对比 - 发送通知。每一步的技术选型都直接关系到项目的稳定性、易用性和可维护性。首先如何获取UP主信息最直接的想法当然是调用B站的官方API。但经过调研B站对未登录状态和公开API的请求有一定频率限制且部分关键API可能需要鉴权。对于个人小工具最稳定、最通用的方式其实是模拟浏览器请求直接抓取UP主的个人空间页面。这里我选择了requests库来处理HTTP请求配合BeautifulSoup4来解析HTML页面。为什么不直接用API因为公开API可能变动而网页结构相对稳定且不需要处理复杂的签名和令牌对于我们的核心需求——获取视频、动态、直播列表——完全够用。其次如何识别“新”内容这就需要本地持久化存储上一次检查时的状态。最简单的方案就是用一个文件如JSON记录每个UP主最新一条内容的唯一标识如视频的BV号、动态的ID和发布时间。每次检查时将线上获取的最新内容ID与本地记录的对比如果不一致就说明有更新。数据库如SQLite当然更强大但对于初期版本JSON文件更轻量无需额外服务读写也方便。然后如何定时检查我们不可能手动运行脚本。在服务器上最经典的就是cron定时任务。但在项目内为了跨平台和易于集成我使用了Python内置的schedule库或者更简单的time.sleep循环。考虑到健壮性我选择了schedule它能更清晰地管理定时任务规则。最后也是体验最关键的一环如何通知通知渠道必须可靠、及时且对用户友好。我设计了多通道支持邮件SMTP最通用几乎所有邮箱都支持。配置好发件邮箱建议使用QQ邮箱、163邮箱的SMTP服务和接收邮箱即可。Server酱微信通知国内开发者很喜欢的工具通过关注其公众号绑定后可以用API向自己的微信发送消息非常方便。Telegram Bot对于有海外环境的用户Telegram机器人的API稳定且功能强大推送格式也丰富。 我通过抽象一个Notifier基类让每种通知方式实现自己的send方法这样后续扩展新的通知渠道如钉钉、Slack会非常容易。2.2 项目目录结构设计一个清晰的结构是项目可维护的基础。我的目录结构如下bilibili-tracker/ ├── config.yaml # 配置文件存放UP主列表、通知设置、检查间隔等 ├── history.json # 数据存储文件记录每个UP主的最新内容状态 ├── main.py # 主程序入口 ├── core/ # 核心逻辑模块 │ ├── __init__.py │ ├── fetcher.py # 负责抓取和解析UP主页面 │ ├── comparator.py # 负责比较新旧内容判断是否更新 │ ├── notifier.py # 通知发送模块的基类和具体实现 │ └── storage.py # 负责读写 history.json ├── notify_services/ # 具体通知服务实现 │ ├── __init__.py │ ├── email_notifier.py │ ├── wechat_notifier.py │ └── telegram_notifier.py └── utils/ # 工具函数 ├── __init__.py └── logger.py # 日志记录便于排查问题使用config.yaml而不是config.py是为了将配置与代码分离用户无需修改Python代码就能调整设置更安全也更友好。history.json是项目的“记忆中枢”它的结构设计至关重要。3. 核心模块深度解析与实现细节3.1 页面抓取与解析Fetcher模块这是整个项目的“眼睛”。我们的目标是从一个UP主的空间主页例如https://space.bilibili.com/123456中提取出视频、动态、直播这三类信息。实现步骤与难点构造请求头这是绕过反爬的基础。需要模拟一个真实的浏览器请求至少包含User-Agent。我通常会使用一个常见的Chrome浏览器User-Agent字符串。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: https://www.bilibili.com/ }获取并解析页面使用requests.get获取HTML然后用BeautifulSoup解析。关键在于找到正确的CSS选择器。B站的页面结构比较复杂而且可能经常微调。我通过浏览器开发者工具仔细分析了UP主空间页面的结构。视频列表通常位于一个ID为submit-video-list的div下的li标签中。每个li包含视频的标题、BV号>{ 123456: { video: { identifier: BV1xx411c7LU, publish_time: 2023-10-27 20:00:00, title: 最新视频标题 }, dynamic: { identifier: 1234567890123456789, publish_time: 2023-10-27 21:30:00, text: 最新动态内容摘要... }, live: { is_living: false, room_id: 213 } } }这种结构使得查询和更新都非常高效。3.3 多渠道通知实现Notifier模块通知是用户感知项目的直接方式必须稳定、及时、信息清晰。我采用了策略模式将通知发送抽象成独立的服务。以邮件通知为例关键配置和实现配置获取从config.yaml读取SMTP服务器地址、端口、发件邮箱、授权码注意不是邮箱密码、接收邮箱列表。notifier: email: enabled: true smtp_server: smtp.qq.com smtp_port: 465 sender: your_emailqq.com password: your_authorization_code # QQ邮箱获取的授权码 receivers: - receiver1example.com - receiver2example.com邮件构造使用Python的smtplib和email库。邮件主题要清晰如【B站追踪】UP主“老番茄”发布了新视频。正文内容采用HTML格式可以更美观地展示视频标题、封面图以链接形式、直达链接和发布时间。def send(self, update): msg MIMEMultipart(alternative) msg[Subject] f【B站追踪】{update.up_name}发布了新{update.content_type} msg[From] self.sender msg[To] , .join(self.receivers) # 构造HTML正文... html_part MIMEText(html_body, html, utf-8) msg.attach(html_part) # 连接服务器并发送 with smtplib.SMTP_SSL(self.smtp_server, self.smtp_port) as server: server.login(self.sender, self.password) server.send_message(msg)Server酱和Telegram Bot的实现思路类似Server酱向其提供的API地址发送一个简单的HTTP POST请求包含title和desp(描述) 字段即可微信端就能收到。Telegram Bot首先需要通过BotFather创建一个Bot获取Token。然后使用requests调用Telegram Bot API的sendMessage方法将消息发送到指定的聊天ID你的私人聊天或群组。实操心得通知内容的信息密度很重要。不要只发“XXX更新了”而要把关键信息一次性给全UP主名、内容类型、标题、直达链接、发布时间。对于视频可以附上封面图链接对于动态可以截取前100字作为预览。这样用户一眼就能决定是否立即查看提升了工具的价值。4. 完整部署与运行流程4.1 环境准备与配置详解假设你已经在本地或一台云服务器如腾讯云轻量应用服务器、阿里云ECS上准备好了Python环境建议3.7及以上。克隆项目与安装依赖git clone https://github.com/Artistkisa/bilibili-up-update-tracker.git cd bilibili-up-update-tracker pip install -r requirements.txtrequirements.txt文件应包含requests2.25.1 beautifulsoup44.9.3 PyYAML5.4.1 schedule1.1.0 tenacity8.0.1 # 用于重试编写配置文件config.yaml这是最重要的步骤。你需要根据注释仔细填写。# 要监控的UP主列表key为自定义名称方便识别value为B站用户MID空间网址最后的数字 up_list: 老番茄: 777536 罗翔说刑法: 517327498 手工耿: 280793434 # 检查间隔秒。不建议设置过短建议300秒5分钟以上避免给B站服务器造成压力 check_interval: 300 # 通知配置 notifier: # 邮件通知 email: enabled: false # 设为true启用 smtp_server: smtp.qq.com smtp_port: 465 sender: your_emailqq.com password: your_auth_code # 注意是授权码 receivers: - your_main_emailexample.com # Server酱微信通知 wechat: enabled: false # 设为true启用 sendkey: your_sendkey # 在Server酱官网获取 # Telegram Bot通知 telegram: enabled: false # 设为true启用 bot_token: your_bot_token # 通过BotFather获取 chat_id: your_chat_id # 你的Telegram用户ID或群组ID如何获取UP主的MID打开UP主的B站空间主页地址栏URL中space.bilibili.com/后面的数字就是MID。如何获取邮箱授权码以QQ邮箱为例登录后进入“设置”-“账户”找到“POP3/IMAP/SMTP服务”项生成授权码。如何获取Server酱的SendKey访问Server酱官网用GitHub登录后即可获得。如何获取Telegram的Chat ID可以先给Bot发条消息然后访问https://api.telegram.org/botYourBOTToken/getUpdates就能看到包含chat.id的响应。4.2 主程序逻辑与运行方式主程序main.py的流程是一个清晰的循环import time import schedule from core.fetcher import BilibiliFetcher from core.comparator import UpdateComparator from core.storage import JsonStorage from notify_services import get_enabled_notifiers # 一个工厂函数根据配置返回启用的通知器列表 def job(): 定时执行的任务 storage JsonStorage(history.json) fetcher BilibiliFetcher() comparator UpdateComparator(storage) notifiers get_enabled_notifiers() # 从配置加载 config load_config(config.yaml) for up_name, up_mid in config[up_list].items(): print(f正在检查 {up_name} ({up_mid})...) # 1. 抓取 updates fetcher.fetch_all(up_mid, up_name) # 2. 比对 new_updates comparator.compare(up_mid, updates) # 3. 通知 for update in new_updates: for notifier in notifiers: try: notifier.send(update) print(f已通过 {notifier.name} 发送通知: {update.title}) except Exception as e: print(f{notifier.name} 通知发送失败: {e}) # 4. 更新存储 storage.update(up_mid, updates) if __name__ __main__: # 立即运行一次 job() # 然后按配置间隔定时运行 schedule.every(config[check_interval]).seconds.do(job) while True: schedule.run_pending() time.sleep(1)运行与后台常驻直接运行在终端执行python main.py。程序会立即检查一次然后每隔设定的间隔循环执行。按CtrlC可以终止。后台运行Linux/Mac使用nohup命令让它在后台运行并将日志输出到文件nohup python main.py tracker.log 21 。使用进程管理工具对于生产环境更推荐使用systemd(Linux) 或supervisor来管理进程可以实现开机自启、崩溃重启、日志轮转等功能。4.3 配置系统服务以systemd为例在Linux服务器上创建一个系统服务可以让追踪器更稳定地运行。创建服务文件sudo vim /etc/systemd/system/bilibili-tracker.service写入以下内容根据你的实际路径修改[Unit] DescriptionBilibili UP Update Tracker Afternetwork.target [Service] Typesimple Useryour_username WorkingDirectory/path/to/bilibili-up-update-tracker ExecStart/usr/bin/python3 /path/to/bilibili-up-update-tracker/main.py Restarton-failure RestartSec10 StandardOutputjournal StandardErrorjournal [Install] WantedBymulti-user.target启用并启动服务sudo systemctl daemon-reload sudo systemctl enable bilibili-tracker.service sudo systemctl start bilibili-tracker.service查看状态和日志sudo systemctl status bilibili-tracker.service sudo journalctl -u bilibili-tracker.service -f5. 常见问题排查与优化经验在实际部署和运行中你肯定会遇到各种各样的问题。下面是我踩过坑后总结的一些典型问题及其解决方法。5.1 抓取失败或数据解析错误问题表现日志中频繁出现requests.exceptions.RequestException或AttributeError(BeautifulSoup找不到对象)。可能原因与解决方案IP被暂时限制这是最常见的问题。B站对高频请求会进行限制。解决首要方法是大幅增加检查间隔我建议至少300秒5分钟一次。对于监控几十个UP主这个频率完全足够。优化在fetcher.py的请求函数中加入随机延迟time.sleep(random.uniform(1, 3))模拟人类操作。进阶如果确实需要高频可以考虑使用代理IP池但这大大增加了项目复杂度背离了轻量化的初衷。网页结构变更B站前端改版导致我们写的CSS选择器失效。解决这是无法避免的。需要定期维护代码。当发现抓取不到数据时用浏览器开发者工具重新分析页面结构更新fetcher.py中的选择器或API接口地址。预防将选择器字符串、API URL模板等易变部分提取到配置文件或常量文件中方便统一修改。动态数据接口变更动态数据通过API获取接口地址或参数可能变化。解决同样需要重新抓包分析。在浏览器中打开UP主动态页按F12进入“网络”(Network)选项卡过滤XHR/Fetch请求寻找包含动态数据的请求观察其URL和参数格式。5.2 通知发送失败邮件通知失败SMTP连接错误检查smtp_server和smtp_port是否正确。QQ邮箱SSL端口是465或587。认证失败99%的情况是密码填错了。请务必使用邮箱的授权码而不是登录密码。检查发件邮箱是否已开启SMTP服务。被接收方邮件服务器拒收如果发件邮箱是免费邮箱且发送量突然增大可能被判定为垃圾邮件。可以尝试在邮件正文中加入“此邮件为自动发送的更新通知请勿直接回复”等说明或者使用更具信誉度的邮箱服务。Server酱/Telegram通知失败配置错误仔细检查sendkey或bot_token和chat_id是否复制完整有无多余空格。网络问题Server酱和Telegram的API服务器在海外国内服务器直接访问可能不稳定或超时。可以考虑在请求时设置合理的超时时间如10秒并添加重试机制。5.3 历史记录文件异常问题表现history.json文件损坏、格式错误导致程序无法读取或对比出错。原因与解决程序异常中断在写入文件时程序崩溃可能导致JSON文件不完整。解决在storage.py的update方法中采用“先写临时文件再替换原文件”的策略。这是原子操作可以避免文件损坏。def update(self, up_mid, latest_updates): # ... 更新内存中的数据 ... # 先写入临时文件 temp_file self.file_path .tmp with open(temp_file, w, encodingutf-8) as f: json.dump(self.data, f, ensure_asciiFalse, indent2) # 原子替换 os.replace(temp_file, self.file_path)手动编辑错误用户直接修改history.json导致语法错误。解决程序启动时可以尝试读取JSON文件如果解析失败则记录错误并尝试从备份中恢复如果你实现了备份功能或者初始化一个空的历史记录。同时在日志中明确警告用户不要手动修改该文件。5.4 性能与扩展性考量当监控的UP主数量增加到几百甚至上千时简单的循环和文件存储可能会遇到瓶颈。优化方向异步抓取使用asyncio和aiohttp库可以并发地对所有UP主进行抓取而不是一个一个顺序执行能极大缩短单次检查的总耗时。数据库存储当数据量变大JSON文件的读写和查询效率会变低。可以迁移到轻量级的SQLite数据库甚至更专业的如PostgreSQL。数据库能更方便地支持查询历史记录、统计更新频率等高级功能。任务队列将“抓取”、“比对”、“通知”拆解成独立的任务放入消息队列如Redis中由不同的工作进程消费。这能提高系统的并发处理能力和可靠性。分布式部署如果需要监控的UP主数量极其庞大可以考虑将UP主列表分片部署多个追踪器实例每个实例负责一部分UP主。当然对于99%的个人用户场景监控几十到一两百个UP主当前这个基于文件、同步请求的架构已经绰绰有余简单可靠才是第一要义。6. 项目进阶与个性化改造这个基础框架搭建好后就有了无限的扩展可能。你可以根据自己的需求把它改造成更强大的工具。1. 增加更多内容类型监控专栏文章监控UP主发布的专栏更新。收藏夹监控特定公开收藏夹里是否有新视频加入。评论区高赞回复监控UP主在自己视频下的高赞回复需要处理鉴权。2. 丰富通知内容和格式聚合通知不要一有更新就发一条可以每小时或每天聚合一次将所有更新整理成一份“简报”发送减少打扰。富媒体通知Telegram Bot支持发送图片。可以在通知里直接附上视频封面图下载到本地或使用图床链接。自定义通知模板允许用户在配置文件中自定义通知的标题和正文模板满足个性化需求。3. 增加Web管理界面使用Flask或FastAPI搭建一个简单的Web界面让用户可以通过浏览器添加/删除UP主、查看更新历史、手动触发检查而不用去修改YAML配置文件和重启程序。4. 实现“智能过滤”不是所有更新都值得通知。可以增加过滤规则例如关键词过滤只通知标题或动态内容中包含特定关键词如“教程”、“发布”、“抽奖”的更新。视频时长过滤只通知时长大于10分钟的视频过滤掉短视频。动态类型过滤只通知“转发动态”或“原创动态”。5. 与其他工具集成RSS生成为每个监控的UP主生成一个RSS订阅源这样你就可以用任何RSS阅读器来订阅了。Discord/钉钉/Slack通知参照已有的通知器模式很容易添加新的通知渠道。数据导出与分析将更新历史定期导出分析你关注的UP主的活跃时间段、更新频率等。这个项目的魅力就在于它从一个简单的需求出发代码结构清晰每个模块职责分明使得后续的扩展和维护变得非常容易。你可以只花一两个小时就搭好基础版用起来也可以把它当作一个练手项目逐步添加上面提到的各种高级功能在这个过程中深入学习HTTP通信、数据解析、任务调度、消息队列、Web开发等多个方面的知识。