B站视频ID从AV到BV的进化史:我是怎么在API开发里被坑哭又救回来的
说实话,刚接触B站API开发的时候,我整个人是懵圈的。那时候我还年轻,觉得写代码嘛,不就是调个接口,拿个数据,再渲染个页面,完事?太简单了。直到有一天,我想写个脚本去爬取某个UP主的历史视频列表,结果发现以前那种直接拼凑 av123456 这种URL的方式,突然就不灵了。页面跳转过去,要么报错,要么直接404。我去查文档,发现B站搞了个大动作,把原来那种纯数字的AV号(AID),换成了一串看起来像乱码的BV号(BVID)。比如以前是 av170001,现在变成了 BV1GJ411x7h1。这不仅仅是换个名字那么简单。这背后涉及到底层数据库索引的变化、安全性的提升,还有开发者社区的一片哀嚎。今天,我就想跟大家掏心窝子聊聊,我是怎么在这个“双轨制”的坑里摔了一跤,又是怎么通过重构代码,把这个问题彻底解决的。如果你也在做B站相关的开发,或者对这种ID转换机制感兴趣,这篇文章你应该能看进去。先说说为什么B站要搞这么一出。早期的AV号,其实就是数据库里的自增ID。比如第一个视频是av1,第二个是av2。这种ID有个巨大的安全隐患:任何人只要遍历数字,就能把B站所有的视频都爬一遍。这就好比你的家门钥匙是1号、2号、3号这样排下去的,小偷只要拿着钥匙试一遍,你家就没了。所以,B站引入了BV号。BV号基于Base58编码,还加上了校验位和混淆算法。你看那个 BV1GJ411x7h1,它看起来随机,但实际上它里面藏着原始的AV号。这种设计既保证了安全性,防止了恶意爬取,又保留了数据的可追溯性。但是,对于开发者来说,这就成了噩梦。因为B站的历史接口很多还是用AV号作为OID(Object ID)的,比如评论接口、弹幕接口。而新的视频详情接口,可能优先要求BV号。这就导致了一个尴尬的局面:你手里拿着BV号,想调评论接口,得先把它转成AV号;你手里拿着AV号,想调新的视频信息接口,又得把它转成BV号。如果每次调用都去请求B站的服务器帮你转换,那网络延迟就受不了了。而且,频繁请求转换接口,容易被B站的风控判定为异常行为,直接封IP。所以,最聪明的做法,就是在本地实现这个转换算法。这里就要提到一个非常优秀的开源项目:bilibili-api。这个项目由MoyuScript维护,它在GitHub和Gitee上都有镜像。它最核心的贡献之一,就是提供了一个本地化的、高性能的AV/BV互转方案。我研究了一下它的源码,发现这个转换算法其实挺巧妙的。它不是简单的查表,而是通过一系列位运算和字符置换来实现的。核心逻辑在 bilibili_api/utils/aid_bvid_transformer.py 这个文件里。咱们来看看它是怎么干的。首先,它定义了一些常量。比如 XOR_CODE 是一个异或掩码,MASK_CODE 是位掩码,BASE 是58,因为Base58编码嘛。还有一个 BV_LEN 是12,因为BV号固定是12位。转换的核心函数有两个:bvid2aid 和 aid2bvid。咱们先看 bvid2aid,也就是把BV号转回AV号。`python def bvid2aid(bvid: str) -> int:"""BV号转AV号"""# 首先,BV号的字符顺序是经过置换的,不能直接解码# 需要把特定的位置交换回来bvid = list(bvid)# 这里交换了第3和第9位,第4和第7位# 注意Python列表索引从0开始,所以这里是索引3,9和4,7bvid[3], bvid[9] = bvid[9], bvid[3]bvid[4], bvid[7] = bvid[7], bvid[4] # 去掉前缀 "BV1",因为前缀是固定的,不参与数值计算bvid = bvid[3:] tmp = 0# Base58解码for i in bvid:idx = data.index(i.encode()) # data是Base58的字符集tmp = tmp * BASE + idx # 最后通过异或和掩码还原出原始的AV号return (tmp & MASK_CODE) ^ XOR_CODE `这段代码看起来有点硬核,但逻辑很清晰。它先做“逆向置换”,把打乱的字符顺序还原,然后当作一个Base58的大整数进行解码,最后通过异或运算还原出原始的整数ID。反过来,aid2bvid 则是逆过程。`python def aid2bvid(aid: int) -> str:"""AV号转BV号"""# 初始化一个字节数组,填充默认值bytes = [b"B", b"V", b"1", b"0", b"0", b"0", b"0", b"0", b"0", b"0", b"0", b"0"]bv_idx = BV_LEN - 1 # 先进行异或和掩码处理,得到编码前的数值tmp = (MAX_AID | aid) ^ XOR_CODE # Base58编码while int(tmp) != 0:bytes[bv_idx] = data[int(tmp % BASE)]tmp //= BASEbv_idx -= 1 # 还原字符置换bytes[3], bytes[9] = bytes[9], bytes[3]bytes[4], bytes[7] = bytes[7], bytes[4] # 拼接成字符串return "".join([i.decode() for i in bytes]) `你会发现,这两个函数是对称的。这种设计非常优雅,而且速度极快。因为在本地进行位运算,比发起HTTP请求快了几个数量级。但是,光有转换函数还不够。在实际开发中,我们更需要的是一个“智能”的对象,它能自动处理这些细节,让我们开发者不用操心。这就是 bilibili-api 中 Video 类的魅力所在。在 bilibili_api/video.py 中,Video 类的构造函数非常贴心。你可以只传BV号,也可以只传AV号,甚至都不传(如果后续再设置的话)。`python class Video:def __init__(self, bvid: Union[None, str] = None, aid: Union[None, int] = None, credential: Union[None, Credential] = None,):# ID检查:bvid和aid必须提供其中之一if bvid is not None:self.set_bvid(bvid)elif aid is not None:self.set_aid(aid)else:raise ArgsException("请至少提供bvid和aid中的其中一个参数。") def set_bvid(self, bvid: str) -> None:"""设置bvid并自动计算对应的aid"""if not re.search("^BV[a-zA-Z0-9]{10}$", bvid):raise ArgsException("bvid提供错误,必须是以BV开头的纯字母和数字组成的12位字符串。")self.__bvid = bvid# 关键一步:自动转换self.__aid = bvid2aid(bvid) def set_aid(self, aid: int) -> None:"""设置aid并自动计算对应的bvid"""if aid raise ArgsException("aid不能小于或等于0。")self.__aid = aid# 关键一步:自动转换self.__bvid = aid2bvid(aid) `这个设计简直太棒了。这意味着,无论你的数据源给的是AV还是BV,你都可以统一用 Video 对象来包裹它。当你需要调用评论接口时,直接调用 video_obj.get_aid() 就能拿到AV号;当你需要调用视频详情接口时,调用 video_obj.get_bvid() 就能拿到BV号。这种“隐式转换”的方案,极大地降低了开发者的认知负担。你不需要在代码里到处写 if bvid.startswith("BV"): ... else: ... 这种判断逻辑,也不用担心忘记转换导致接口报错。当然,凡事都有两面性。隐式转换虽然方便,但在调试的时候,如果你发现数据不对,可能一时半会儿反应不过来是转换出了问题,还是API返回的问题。所以,我建议大家在开发阶段,可以适当打印一下中间变量,确认转换结果是否符合预期。比如,你可以写一个简单的验证函数:`python def validate_video_identifier(identifier: str) -> Tuple[bool, str, Optional[int]]:"""验证视频标识符并返回类型和转换结果"""if identifier.startswith("BV") and len(identifier) == 12:# 验证BV号格式if re.match(r"^BV[a-zA-Z0-9]{10}$", identifier):try:aid = bvid2aid(identifier)return True, "bvid", aidexcept:return False, "invalid", Noneelif identifier.startswith("av"):# 处理AV号try:aid = int(identifier[2:])if aid > 0:return True, "aid", aidexcept:passreturn False, "unknown", None `这个函数可以帮你快速排查问题。比如,当你拿到一个奇怪的字符串,不确定它是AV还是BV,或者格式有误,这个函数能给你明确的反馈。在实际项目中,我还发现了一个性能优化的点。如果你的应用需要处理大量的视频ID转换,比如批量解析一个UP主的所有视频,那么频繁的函数调用可能会成为瓶颈。虽然本地计算很快,但也不是零成本。这时候,缓存就派上用场了。Python的 functools.lru_cache 装饰器是神器。`python from functools import lru_cache@lru_cache(maxsize=1024) def cached_bvid2aid(bvid: str) -> int:"""带缓存的BV到AV转换"""return bvid2aid(bvid)@lru_cache(maxsize=1024) def cached_aid2bvid(aid: int) -> str:"""带缓存的AV到BV转换"""return aid2bvid(aid) `加上缓存后,重复的转换请求直接从内存中读取结果,速度几乎是瞬间完成的。对于大多数场景,1024的缓存大小已经足够了。毕竟,一个UP主的视频数量通常不会超过这个数,而且热点视频会被反复访问,缓存命中率很高。说到这里,我想再聊聊B站API的整体架构设计。bilibili-api 项目采用了一种分层架构。应用层提供统一的 Video 类,转换层负责底层的算法实现,API适配层则负责根据目标接口的要求,自动选择正确的标识符格式。这种设计思想,其实值得所有API封装库借鉴。很多第三方库,要么只支持BV,要么只支持AV,要么要求开发者手动转换,体验都很差。而 bilibili-api 通过这种“透明化”的处理,让开发者感觉不到底层的变化,这才是好库该有的样子。当然,技术总是在发展的。B站的标识符系统未来会不会再变?很有可能。随着数据量的爆炸式增长,Base58编码可能也会遇到瓶颈。未来可能会出现更复杂的分布式ID生成方案,比如雪花算法的变种,或者基于区块链的不可篡改ID。但无论如何,核心思想不会变:既要保证唯一性和安全性,又要兼顾兼容性和性能。对于咱们开发者来说,面对这种变化,最好的策略就是“拥抱变化,但保持抽象”。不要在你的业务逻辑里硬编码任何ID格式。就像我上面说的,封装一个 Video 对象,或者类似的对象,把所有的ID操作都封装在里面。这样,即使B站明天把BV号改成CV号,你只需要修改封装层的一个函数,业务代码一行都不用改。最后,我想分享一点个人感悟。做API开发,尤其是这种大厂平台的API,往往充满了坑。B站的反爬策略、接口的频繁变更、标识符的诡异转换,每一个都可能让你debug到深夜。但正是这些挑战,逼着我们写出更健壮、更优雅、更抽象的代码。当你看着自己的代码,能够优雅地处理各种边缘情况,能够无缝兼容新旧系统,那种成就感,是写“Hello World”无法比拟的。所以,如果你正在做B站相关的开发,不妨试试 bilibili-api 这个库。它不仅能帮你解决AV/BV转换的问题,还能帮你处理登录状态、弹幕解析、评论获取等一系列复杂操作。它的文档虽然不算特别详细,但源码非常清晰,值得细细研读。毕竟,站在巨人的肩膀上,我们才能看得更远。希望这篇文章能帮到正在坑里挣扎的你。如果有什么疑问,或者有更好的优化建议,欢迎在评论区留言

相关新闻

PostgreSQL高可用实战:Patroni日常维护命令大全(附常见问题排查)

PostgreSQL高可用实战:Patroni日常维护命令大全(附常见问题排查)

在PostgreSQL高可用架构中,Patroni作为一款开源的集群管理工具,已经成为许多企业数据库架构的核心组件。它不仅简化了PostgreSQL集群的部署流程,更重要的是提供了自动化的故障转移和集群管理能力。然而,随着Patroni在生产环境中的广泛应用,DBA们逐渐发现,仅仅掌握基础部署…

2026/8/5 14:55:34 阅读更多 →
9个理由告诉你为什么这款免费商用字体值得拥有:Outfit几何字体深度解析

9个理由告诉你为什么这款免费商用字体值得拥有:Outfit几何字体深度解析

9个理由告诉你为什么这款免费商用字体值得拥有:Outfit几何字体深度解析 【免费下载链接】Outfit-Fonts The most on-brand typeface 项目地址: https://gitcode.com/gh_mirrors/ou/Outfit-Fonts 你是否正在寻找一款既专业又完全免费的商用字体?Ou…

2026/8/5 14:54:34 阅读更多 →
别再盲目扫了!这款开源神器afrog,让漏洞检测快准狠(附保姆级教程)

别再盲目扫了!这款开源神器afrog,让漏洞检测快准狠(附保姆级教程)

各位安全圈的兄弟们,还有那些在一线摸爬滚打的运维老铁们,大家好。今天咱们不聊那些虚头巴脑的大道理,直接来点干货。相信大家在日常工作中,都遇到过这种崩溃时刻:手里拿着个老旧的扫描器,跑个全量扫描要半天,出来的报告一堆误报,看得人眼瞎;或者为了测几个特定的组件…

2026/8/5 14:54:34 阅读更多 →

最新新闻

novel-downloader架构深度解析:模块化设计实现原理与高性能小说下载实践

novel-downloader架构深度解析:模块化设计实现原理与高性能小说下载实践

novel-downloader架构深度解析:模块化设计实现原理与高性能小说下载实践 【免费下载链接】novel-downloader 一个可扩展的通用型小说下载器。 项目地址: https://gitcode.com/gh_mirrors/no/novel-downloader 在数字内容快速迭代的今天,小说作品的…

2026/8/5 15:33:59 阅读更多 →
jwt库算法全解析:HS、RS、ES到EdDSA的选择与实现

jwt库算法全解析:HS、RS、ES到EdDSA的选择与实现

jwt库算法全解析:HS、RS、ES到EdDSA的选择与实现 【免费下载链接】jwt Safe, simple and fast JSON Web Tokens for Go 项目地址: https://gitcode.com/gh_mirrors/jwt14/jwt JSON Web Token(JWT)是现代应用中广泛使用的身份验证和信息…

2026/8/5 15:33:59 阅读更多 →
本地化创作者工具部署指南:从环境配置到API集成全流程解析

本地化创作者工具部署指南:从环境配置到API集成全流程解析

这次我们来看一个名为“粉丝空间站”的项目。从名称和有限的材料来看,这很可能是一个面向内容创作者或社群运营者的本地化工具,旨在帮助用户高效管理、生成或与粉丝相关内容进行互动。这类工具的核心价值在于将一些需要云端处理或手动操作的任务&#xf…

2026/8/5 15:33:59 阅读更多 →
Flutter与鸿蒙跨平台Entity适配实战

Flutter与鸿蒙跨平台Entity适配实战

1. 项目背景与核心价值 在跨平台开发领域,Flutter凭借其出色的渲染性能和一致的UI体验已成为移动端开发的主流选择。而鸿蒙HarmonyOS作为新一代分布式操作系统,其全场景能力与高性能特性为开发者带来了全新机遇。将Flutter的entity组件适配到鸿蒙平台&am…

2026/8/5 15:33:59 阅读更多 →
告别流水账:价值导向的周报撰写思维与三段论框架实践

告别流水账:价值导向的周报撰写思维与三段论框架实践

1. 为什么你的周报总像流水账?从“交差”到“价值”的思维转变又到周五下午,是不是感觉比周一早上还焦虑?不是因为工作没做完,而是因为那份每周都要交的“作业”——工作周报。很多人提起写周报就头疼,要么是“周一开会…

2026/8/5 15:33:59 阅读更多 →
AI智能体开发实战:从开源模型部署到安全架构设计

AI智能体开发实战:从开源模型部署到安全架构设计

1. 从“龙虾”到“智能体”:一场技术路线的全民大讨论 最近,一个叫“AI龙虾”的词突然在技术圈和开源社区火了起来。如果你在搜索引擎里输入“OpenClaw”,会发现大量关于安装、部署、报错和讨论的帖子,热度高得有点反常。这个听起…

2026/8/5 15:32:59 阅读更多 →

日新闻

Java缓存框架:JetCache

Java缓存框架:JetCache

TOC 一、简介 JetCache 是一个 Java 缓存抽象框架,为不同的缓存解决方案提供了统一的使用方式。 它提供的注解比 Spring Cache 更加强大。 JetCache 的注解支持原生 TTL、两级缓存以及在分布式环境中的自动刷新功能,同时你也可以通过代码直接操作 Cach…

2026/8/5 0:00:43 阅读更多 →
AD 铺铜设置十字连接,过孔全连接,新版AD的简单设置

AD 铺铜设置十字连接,过孔全连接,新版AD的简单设置

需求:通孔焊盘 十字花;过孔 Via 实心直连;贴片焊盘按需设置 AD 测试版本AD24 很多工程师踩坑:全部统一十字,导致接地过孔阻抗高、大电流发热! 一、快捷键打开规则 PCB 界面按下:D R 展开…

2026/8/5 0:00:43 阅读更多 →
AI素描转换技术深度拆解(2024最新论文+工业级落地代码):从Stable Diffusion ControlNet到LoRA微调全链路解析

AI素描转换技术深度拆解(2024最新论文+工业级落地代码):从Stable Diffusion ControlNet到LoRA微调全链路解析

更多请点击: https://kaifayun.com 第一章:AI生成素描效果 AI生成素描效果是计算机视觉与风格迁移技术融合的典型应用,其核心在于将彩色照片或RGB图像转换为具有手绘质感、明暗对比强烈、边缘清晰的单色素描图像。该过程通常依赖于深度学习模…

2026/8/5 0:00:43 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/5 15:00:43 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/5 13:13:56 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/5 10:20:36 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/4 13:38:24 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/4 11:09:16 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/4 13:38:40 阅读更多 →