B站API与视频下载全解析:从URL参数到接口调用实战
2026/9/18 5:06:17 网站建设 项目流程

前阵子在群里看到有人问:“B站视频怎么批量下载?网上那些解析站是怎么做的?”接着又有人甩出“查成分工具”“充电视频解析”这类词。我当时就意识到,很多人并不是真的缺工具,而是搞不懂B站网页端那一大堆参数和API接口到底是怎么回事。只要你把URL里的参数看懂了,把常见接口的调用逻辑摸清了,那些所谓的“工具”绝大部分你都能自己写出来。

这篇小教程不搞大而全的源码框架,就围绕一件事展开:B站的网页版参数和API接口,从URL拆解到实际请求,再到几个热门工具的原理还原。适合想入门爬虫、想自己做B站小工具、或者单纯想弄明白“解析站到底做了什么”的读者。文章里会穿插Python示例,但我尽量让你不贴代码也能看懂逻辑。

1. 先搞懂B站URL里的那些“参数”到底是什么

1.1 从一次“想下载视频”说起

假设你现在就想把一个B站视频下载到本地。你复制了地址栏链接,大概是这样的:

https://www.bilibili.com/video/BV1xx411c7XX?p=2&t=30&spm_id_from=333.999.0.0

如果你直接拿这个链接去请求,能拿到页面,但拿不到视频文件本身。因为真正的视频地址藏在页面里,需要API接口根据参数去换。所以第一步,你得能看懂这个URL里哪些参数是干什么用的。很多时候工具没效果,不是你代码写错了,而是参数不对。

我见过不少新手在网上搜“B站API”,搜到一两个接口就开干,结果请求返回一串看不懂的JSON,最后卡在“怎么从响应里找到视频地址”这一步。根本原因就是没建立“参数→接口→响应”这个整体认知。

1.2 一个视频页URL的完整拆解

拿上面那个URL举例,拆开来看:

参数示例值含义是否需要手动设置
bvidBV1xx411c7XX视频唯一ID,B站现在的通行标识必须
p2分P序号,表示第几个分P可选
t30播放进度,单位秒,用于自动跳转可选
spm_id_from333.999.0.0流量来源追踪参数可选
vd_source一串随机字符渠道来源参数,用于统计可选

bvid是核心,几乎所有视频相关接口都要用到它。它和早期的av号是一一对应的,接口里也经常返回aid(av号的数字形式),所以你在请求里写bvid=BV1xx411c7XX或者aid=170001效果一样,但现在官方更推荐用bvid

p参数在分P视频里特别重要。很多人下载多P视频只下到第一P,就是因为只传了bvid没传p。而进一步说,API内部真正识别分P靠的不是p本身,而是通过p去查询该分P对应的cidcid才是每个分P自己的唯一ID。这个关系后面实操部分会用到。

spm_id_from这种参数,属于“追踪参数”。简单说,B站用它来统计你是从哪个页面进来的,比如从搜索页进来就是search,从首页推荐进来就是333.999.0.0这类。普通用户用不上,但如果你在做流量分析,能通过它判断用户来源。

1.3 参数不止在URL里,还在请求体里

这里要澄清一个很多人的误区:B站网页版的参数不只在URL问号后面,POST请求的Form Data里、请求头Header里,都塞满了参数。比如视频的点赞、投币、评论操作,很多都是POST请求,参数藏在请求体里。

以取流(获取视频播放地址)为例,在浏览器开发者工具里能看到:

https://api.bilibili.com/x/player/playurl?bvid=BV1xx411c7XX&cid=123456&fnval=16&qn=125

光看URL地址栏里的页面参数是不够的,你得学会看XHR请求里的Query String Parameters。这些参数决定了接口返回什么格式的数据。

2. 搞懂B站API的“常用接口全家桶”与鉴权分层

看完参数再看接口。B站的接口多得数不清,但对做小工具来说,真正高频的其实就那十几个。我把它们按功能分个类,对应的路径也列出来,这样你以后遇到需求就知道该找谁。

2.1 视频信息类接口:一切操作的起点

  • 视频详情:GET https://api.bilibili.com/x/web-interface/view
  • 视频状态(播放量、点赞、硬币等):GET https://api.bilibili.com/x/web-interface/stat
  • 视频播放地址:GET https://api.bilibili.com/x/player/playurl

view接口是我个人使用频率最高的。你只要传一个bvid,它会返回视频标题、简介、UP主信息、分区、所有分P的cid列表、时长、封面图等。这基本上就是B站视频的“身份证全集”。

举个例子,请求view接口后你会在JSON里看到类似这样的结构(简化):

{ "code": 0, "data": { "bvid": "BV1xx411c7XX", "title": "视频标题", "pubdate": 1600000000, "owner": {"mid": 123456, "name": "UP主名"}, "pages": [ {"page": 1, "cid": 111111, "part": "P1标题"}, {"page": 2, "cid": 222222, "part": "P2标题"} ] } }

注意看pages数组,每个分P有自己的cid。拿到cid之后,你才能继续去请求播放地址。所以标准链路是:bvidview接口 →cidplayurl接口 → 视频流地址。

2.2 弹幕和评论接口:做文本分析的富矿

  • 弹幕:GET https://api.bilibili.com/x/v2/dm/web/seg.so
  • 评论:GET https://api.bilibili.com/x/v2/reply

弹幕接口比较特殊,它返回的不是JSON,而是一种二进制流格式(protobuf),直接请求会看到一堆乱码。你需要用protobuf解析规则去解码,或者用一些现成的库。分段弹幕接口的oid参数就是视频的cid,还有个segment_index表示弹幕分段的序号,从1开始。

评论接口反而是标准的JSON接口,参数有type=1表示视频类型,oid填视频cidpnps控制分页。如果你想分析某个视频的评论情感倾向或者做词云,这个接口是主力。

2.3 用户信息和作品列表接口

  • 用户名片:GET https://api.bilibili.com/x/web-interface/card
  • 用户投稿列表:GET https://api.bilibili.com/x/space/wbi/arc/search

传一个mid(用户ID),能看到用户的昵称、头像、粉丝数、签名等。而arc/search接口能列出该用户的所有公开投稿视频。

这里要注意,查询某个用户的历史投稿,虽然通常习惯用mid参数,但实际请求中往往需要携带WBI签名后的dm_img_listdm_img_str等参数组合。这类接口对风控要求比较高,频繁调用容易触发验证码。

2.4 鉴权分层:哪些能裸调,哪些要穿衣服

如果你用过一段时间B站接口,会看到三种典型的返回错误:-403-412-352。它们基本对应了B站的三层鉴权逻辑:

返回码含义常见原因
-403访问被拒绝请求头缺失、签名过期、当前账号权限不足
-412请求被拦截触发风控,IP被限制,需要验证码
-352风控校验失败缺少WBI签名或签名错误

从访问权限上看,B站接口大致分三层:

  • 第一层:完全公开,只靠参数就能请求,比如view接口大部分数据不登录也能拿。
  • 第二层:需要登录Cookie,比如高清晰度视频流(1080P以上)、点赞投币等操作接口。
  • 第三层:需要WBI签名,比如部分space接口、search接口。

WBI签名是B站网页端的一个“防爬”机制,原理不复杂:从nav接口拿到一个mixin_key,然后把请求参数按照一定规则排序、拼接、计算MD5,得到一个w_rid参数,同时带上wts时间戳。相当于给每个请求加了一个动态签名。我自己的经验是,写工具时能避开WBI就尽量避开,比如用户投稿列表可以尝试通过view接口配合其他公开数据替代,如果确实需要,就参考现成的B站开源SDK里的实现,不必自己从头硬啃。

3. 实操:用参数和API拼出一个“取流下载”流程

理论看再多,不如动手走一遍。这一节我们完成一个最小可用的下载流程:拿到一个bvid,解析出视频流地址,然后把视频和音频下载到本地。

3.1 必备工具与约定

语言用Python,依赖库主要就是requests。为了绕过简单的防盗链,我们还需要手动构造请求头。这里约定一下:

  • User-Agent:伪装成浏览器。
  • Referer:必须设置为https://www.bilibili.com/,否则视频流请求会被拒绝。

3.2 第一步:根据bvid获取cid

先把视频信息拉下来:

import requests session = requests.Session() session.headers.update({ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Referer": "https://www.bilibili.com/" }) bvid = "BV1xx411c7XX" view_api = "https://api.bilibili.com/x/web-interface/view" resp = session.get(view_api, params={"bvid": bvid}).json() data = resp["data"] cid = data["pages"][0]["cid"] # 取第一个分P

这一步里params参数会自动帮你拼Query String,注意requests库会对参数做URL编码,这正好省去手动编码的麻烦。

3.3 第二步:请求playurl获取视频流地址

拿到cid之后,请求playurl接口:

play_api = "https://api.bilibili.com/x/player/playurl" params = { "bvid": bvid, "cid": cid, "fnval": 16, # 16 表示请求DASH格式 "qn": 125, # 清晰度:125为4K,120为2K,116为1080P60,112为1080P "fourk": 1 } play_data = session.get(play_api, params=params).json() video_url = play_data["data"]["dash"]["video"][0]["baseUrl"] audio_url = play_data["data"]["dash"]["audio"][0]["baseUrl"]

fnval=16qn=125是这里最关键的参数。fnval=16表示要求返回DASH格式,意思是视频和音频分离——视频流只有画面没有声音,音频流只有声音没有画面。设置qn=125时,要留意你账号的清晰度权限,没有大会员时直接要4K流可能会被降级或返回错误码。这个细节很多人第一次都会忽略。

3.4 第三步:下载音视频并合并

video_content = session.get(video_url).content audio_content = session.get(audio_url).content with open("video.m4s", "wb") as f: f.write(video_content) with open("audio.m4s", "wb") as f: f.write(audio_content)

下载完你会得到两个文件,video.m4saudio.m4s。下一步用ffmpeg把它们合并成一个完整的MP4:

ffmpeg -i video.m4s -i audio.m4s -c copy output.mp4

到这里,一个最小化的B站视频下载流程就跑通了。整个流程的逻辑链非常清晰:bvid + pview接口cidplayurl接口音视频流地址→ 下载 →ffmpeg合并

3.5 进阶:处理分P、清晰度与请求频率

如果你要下载多P视频,注意pages数组的顺序和p参数一一对应。写循环时依次取每个分P的cid,再重复第二步就行。

清晰度这块我再补充一句。qn参数并不是越高越好,还要看视频本身支持的最高清晰度和账号权限。判断方法很简单:看playurl返回的accept_description列表,比如["高清 1080P", "高清 720P"],这就是当前账号能拿到的全部档位。

请求频率方面,如果你需要批量处理,建议在每次请求之间加time.sleep(1),不要并发请求太猛。B站的风控对短时间高频请求非常敏感,我见过一个脚本因为循环里没加延时,跑了不到两分钟IP直接触发-412

4. 那些热门小工具到底是怎么实现的

搞懂了上面的链路,你再回头看网上流传的各种B站小工具,就会有一种“原来如此”的感觉。下面聊几个典型的热搜词。

4.1 m4s文件合并工具:就是封装了ffmpeg

很多人第一次接触m4s文件,是因为B站客户端缓存或者直接下载DASH流之后,发现文件播不了。其实m4s就是一种无封装的音视频流格式,本质上和mp4里的编码数据差别不大,只是剥掉了容器外壳。

所谓“m4s文件合并工具”,核心工作就是调用ffmpeg做remux。网上一些图形化的合并工具,只是把我在3.4节里写的命令行封装成了可视化界面。如果你在命令行里手输过那条ffmpeg命令,你就已经超过了90%的“工具使用者”。

顺带一提,有些工具还能直接处理“下载下来只有视频没有声音”的问题,那是因为它只抓了video流没抓audio流,合并自然无从谈起。

4.2 查成分工具:本质是聚合公开接口数据

“查成分”是B站社区里一个很有趣的玩法。输入一个UID,工具会分析这个用户的点赞、投币、收藏、关注列表,然后生成一个“成分分布”,比如“关注了哪些领域的UP主”“经常看什么类型的视频”。

这类工具的实现思路也很直白:

  • 先通过card接口拿用户基本信息和关注数。
  • 再通过space系列的关注列表接口,拉取最近关注的UP主。
  • 然后根据这些UP主的视频分区、标签做聚合统计。

整个过程没有任何“黑科技”,就是把公开接口返回的数据做了个透视表。难点在于:

  • 接口有频率限制,做批量分析时得控制节奏。
  • 用户如果设置了隐私,很多数据拉不到。
  • 关注列表很长时,分页参数和排序参数要处理好。

我做过一个简单的版本,核心逻辑不到200行Python,效果已经够用。所以如果你看到某些“查成分”网站收费,要知道它贵在维护和界面,而不是技术本身。

4.3 充电视频解析的原理边界

关于充电专属视频,我必须先把态度说清楚:这篇文章不教学如何绕过付费,也不鼓励任何人去破解付费内容。但从技术角度,理解它的权限机制是合理的。

充电专属视频在接口层面和普通视频的区别,主要体现在数据返回上。当你请求一个充电专属视频的playurl接口时,接口会先判断当前账号是否有观看权限。没有权限的话,返回数据里的dash字段会是空的,或者整体返回code为非0的错误信息。

网上有些人说“能解析充电视频”,实现思路无非是:

  • 拿一个已经充电且有权限的账号Cookie去请求。
  • 或者找到缓存时的临时授权地址。

这些手段本质上都在“借用权限”,既不合法,也随时会被风控识别。了解这个原理的意义在于:当你自己开发B站相关工具时,遇到“接口正常但dash为空”的情况,能迅速想到可能是权限问题,而不是代码写错了。

4.4 敏捷开发里的“必要参数”思路

做工具时我习惯先列一个“必要参数清单”,再对着接口文档逐一核对。比如下载工具的必要参数是bvidcid,而qnfnval属于可调参数。这样一旦请求失败,排查范围会小很多。

很多开源项目里的参数比我上面写的要多得多,比如platform=html5high_quality=1device=phone之类。这些参数不是没用,而是它们要么是为特定客户端设计的,要么是历史遗留。新手别照抄,要以自己实际测试为准。

5. 调用B站API容易踩的坑与应对建议

接口本身不难,真正劝退新手的往往是下面这些“软性问题”。我把这几年积累的经验一次性列出来。

5.1 请求头:User-Agent和Referer是生命线

请求头是B站第一道防线。很多人的请求代码用默认UA甚至裸requests.get,返回一上来就是-412,这就是UA被识别了。

我自己的标准配置是:

headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Referer": "https://www.bilibili.com/", }

尤其Referer这一项,视频流地址的请求必须带,否则即使拿到了baseUrl,下载时也会被防盗链拒绝,返回403。这算是B站最顽固的防盗链策略之一。

5.2 清晰度、Cookie和大会员的关系

没有登录态时,大多数视频最高只能拿480P,少数甚至只有360P。想要1080P乃至更高,账号必须登录,部分高码率还需要大会员。

处理方式就是在请求时带上Cookie请求头,从浏览器里复制下来粘贴到代码里即可。但注意Cookie会过期,长期运行的脚本需要定期更新。如果你只写一个自己用的小工具,这是最省事的方案。

5.3 缓存时间戳与临时链接有效期

playurl接口拿到的baseUrl是有有效期的,通常只有几分钟到一两个小时。我之前遇到过这样的情况:批量下载任务排队到一半,前面下载太慢,后面的链接就过期失效了。

解决思路是:不要一次性把所有分P的baseUrl都取出来存着,而是下载前才现取对应分P的地址。这样每个链接都是新鲜的,过期概率小很多。

5.4 不要碰“批量注册”“批量点赞”这类黑产脚本

我知道写到这里一定会有人说“那点评赞这种怎么做”。我的建议是:不要做。B站的风控体系会从设备指纹、IP、行为模式多个维度检测异常,这类脚本封号风险极高,而且也没有正当使用场景。

个人学习时的合理用法是:备份自己的公开数据、做数据分析可视化、给喜欢的视频做离线弹幕词云。这些方向既能学到东西,也不触碰红线。

5.5 常见错误速查表

现象最可能原因排查方法
接口返回-404视频不存在、bvid传错、被UP主删除先用浏览器打开视频确认
返回-403请求头缺失、无权限补全Referer和UA,检查账号登录态
返回-412请求频繁、IP被风控降低频率,更换IP,过段时间再试
dash字段为空权限不足或视频格式不支持检查账号是否登录,切换fnval
播放地址下载403Referer缺失确认请求头里加了Referer: https://www.bilibili.com/
Cookie失效登录过期重新从浏览器复制Cookie

5.6 顺手提一下“B站网页版修改快捷键”

热搜词里有“b站网页版修改快捷键”,这其实是B站网页播放器的一个快捷键设置页面。顺带说一句,B站在网页端的快捷键体系是通过本地存储保存的,不是通过API。所以如果你想去改它,思路是操作浏览器的localStorage,而不是调接口。理解了“网页功能≠全部走API”这个道理,很多困惑都会解开。

最后再说点实在的

我在实际写B站相关脚本的过程中,最深的一个体会是:接口文档不重要,重要的是参数语义。B站官方没有公开过正式的API文档,所有接口地址、参数说明都是社区开发者通过抓包总结出来的。所以网上流传的“接口大全”随时可能过期,你要学会自己打开浏览器开发者工具,找到Network面板里那一个个XHR请求,自己看参数、看响应。

另一个经验是:能请求到结果不代表你理解了过程。建议你亲手把view接口、playurl接口的返回JSON完整看一遍,不急着写代码,先弄清楚每个字段是什么意思。这个“读JSON”的能力,比背十个接口路径都管用。

最后建议你从小需求入手练手,比如写一个脚本,把自己最近投币过的视频信息导成表格,或者统计某个UP主最近一年视频的播放量趋势。整个过程会强迫你搞懂参数、签名、分页、异常处理,等这些基本功练扎实了,再回来看“解析站”们的原理,你会发现一切都很透明。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询