
直接说结论B站这套参数和API的东西就是搞B站周边开发绕不开的核心。你在网上看到的查成分工具、m4s合并工具、充电视频解析脚本、甚至一些AI小助手本质上全是靠B站网页端和APP端暴露出来的那些接口在跑。如果你对“参数”和“API”这两个词还停留在“听过但不知道怎么用”的阶段这篇教程就是给你准备的。我会从最简单的URL参数拆起一路讲到接口鉴权、WBI签名、弹幕拉取最后直接带你把一个能用的“查成分小工具”跑通。不整虚的全是实操。1. 先从B站URL参数说起链接里的字母和数字是干嘛的1.1 BV号、av号、cid到底怎么区分先看一个最常见的视频链接https://www.bilibili.com/video/BV1xx411c7mD?p2vd_sourceabcdefg这里面最主要的就是BV1xx411c7mD这就是B站视频的“身份证”官方叫bvid。2020年之前B站用的是av号纯数字比如av170001。现在两者都在用但接口里更推荐bvid因为它是经过编码的别人一眼看不出视频发布时间和序号。你可能会问av号好好的为什么要改成BV号直接原因就是av号太容易被遍历了纯数字自增意味着爬虫可以一个接一个把全站视频都抓一遍平台没法做风控。BV号本质上是av号经过base58编码再打乱顺序的结果具体算法是av号先和一个固定数字做异或再经过位运算和base58映射最后得到一串看起来随机的字符。不过现在官方已经给了反转接口你完全不需要自己实现那套编码解码。再说cid这个是视频分P的唯一ID。一个视频如果有多P每一P都有自己独立的cid。你调用播放地址、弹幕接口时真正起作用的是cid而不是bvid。所以参数之间的关系是这样的拿到bvid后先通过视频信息接口把整个合集的所有分P和对应cid列表取出来再根据p参数选中具体某一P的cid最后用这个cid去要播放地址和弹幕。1.2 p参数、t参数、autoplay参数这些小东西URL里除了BV号和cid还有一堆看起来不起眼的参数最典型的是以下几种p2指定分P的序号比如一个视频有10P你要直接跳到第2P就在URL里加?p2。有些工具脚本解析下载时也是靠这个参数来确定要下载哪个分P。t120指定视频开始播放的时间位置单位是秒。比如?t120表示从第120秒开始播放这个在分享某个精彩片段时非常实用。autoplay0禁止自动播放。默认情况下从收藏夹或推荐点进去可能会自动播放加上这个参数可以强制不自动播放。danmaku0隐藏弹幕加载视频时直接把弹幕关掉。vd_source访问来源统计参数B站靠它追踪用户是从哪个渠道进来的一般不影响视频内容本身。这些参数别看简单实际写工具时经常用得到。比如你想做“从第N秒开始下载转GIF”的脚本就完全可以通过URL里的t参数来定位起始时间你想做批量抓取多P视频的下载器就必须处理好p参数和cid的映射关系。很多人忽略这一点写出来的脚本只在单P视频上能用一遇到合集就崩溃。1.3 UID和用户页参数从链接看UP主用户空间的URL和视频页完全不一样https://space.bilibili.com/170001这里的170001就是用户UIDB站所有用户维度接口——粉丝数、关注数、投稿列表、动态流、充电专属视频——都要拿这个UID来查。几乎所有“查成分”工具的核心就是围绕这个UID去调B站的各种用户接口。有意思的是B站部分页面还支持动态参数比如https://space.bilibili.com/170001/dynamic会直接跳转到动态页/upload/video会跳到投稿页/article会跳到专栏页。你在网页端见到的这些路径本质上就是B站前端路由的参数化结果。理解这个结构之后你做用户数据采集时就知道该往哪个URL打请求了。2. B站公开API地图这些接口分别能干什么2.1 视频信息接口一切视频操作的起点只要你拿到一个bvid第一步基本都是调视频信息接口https://api.bilibili.com/x/web-interface/view?bvidBV1xx411c7mD这个接口返回的是JSON格式里面包含了你能想到的所有视频元信息data.aid视频的av号data.cid默认分P的ciddata.pages所有分P的数组每个元素包含cid、page、part分P标题data.ownerUP主信息包括mid、name、facedata.stat播放量、弹幕数、点赞数、投币数、收藏数、分享数data.desc视频简介data.pubdate发布时间戳实测下来这个接口的稳定性非常好只需要带一个最基本的User-Agent头就能返回数据。但要注意如果视频已经被删除或撞了版权变成“仅限会员观看”返回的code可能是-404。还有一类视频是“充电专属”返回字段里会出现badgepay这个标记表示不是所有人都能看到完整内容的。这个接口是所有B站开发者的老朋友我自己的工具链里它有90%以上的调用占比。不管你是做数据统计、视频下载还是内容筛选第一步永远是它。2.2 视频流地址接口真正拿到播放地址的地方视频能不能下载、能拿到多高清晰度全看playurl接口https://api.bilibili.com/x/player/playurl?bvidBV1xx411c7mDcid111222qn64fnval16这里cid是必填的必须传视频具体分P的cid。fnval是关键参数我一般直接填16这个值代表返回DASH格式也就是把视频画面和音频分开返回。qn代表清晰度64是1080P80是1080P高码率但高清晰度通常要登录Cookie大会员才能解锁4K和杜比。用DASH格式返回后你会拿到两个列表dash.video和dash.audio。每个列表里有多个不同编码和清晰度的分片地址每个分片文件就是传说中的m4s文件。这也就是为什么你在网上会看到一堆“m4s文件合并工具”——因为直接下载下来的视频流和音频流是分开的必须合并才能播放。这里提醒一句playurl接口拿到的下载地址有效时间很短一般几小时到一天不等而且有防盗链校验直接复制到浏览器地址栏不一定能下载成功需要在请求里带上Referer头。写代码时千万别把这一点漏了否则就是各种403。2.3 弹幕接口XML和JSON两种格式的坑B站弹幕接口有两个版本都很有用老版本是XML格式https://api.bilibili.com/x/v1/dm/list.so?oid110222这个接口直接返回弹幕XML解析起来很方便但整个视频所有弹幕一次性拉完数据量大了以后加载很慢。新版本是分段JSON接口https://api.bilibili.com/x/v2/dm/web/seg.so?type1oid110222segment_index1segment_index按分钟分段一个视频被切成了很多个时间片每个时间片的弹幕单独拉取。好处是省流量坏处是你得先知道视频总分钟数再循环去拉。我第一次写弹幕分析工具时没搞明白这个把segment_index忘写了结果只有前几分钟的弹幕排查了半天才发现问题。弹幕数据里比较有用的字段是progress弹幕出现在视频中的时间点毫秒、mode弹幕类型滚动/顶部/底部、color弹幕颜色、mid发送者UID哈希但注意这个值做过处理不是完整UID。做弹幕情感分析或者高能片段提取主要用的就是progress字段。2.4 用户信息、动态和关注接口查成分的基础查成分工具能查到的信息基本都来自这几个接口# 用户基本信息 https://api.bilibili.com/x/web-interface/card?mid170001 # 用户关注列表 https://api.bilibili.com/x/relation/followings?vmid170001pn1ps50 # 用户动态列表 https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?host_mid170001card接口返回粉丝数、关注数、性别、等级、签名等基本信息。followings接口能一页一页翻关注列表配合ps参数控制每页条数。动态接口返回用户发的所有动态包括转发、图文、视频更新等。抖音那句“关注列表决定你是谁”放在B站查成分场景里也是成立的。很多人会通过拉取目标用户关注了哪些UP主来判断他的立场和喜好。但要注意关注列表接口现在对未登录用户做了限制翻不了几页就会要求登录。实际开发时建议带上自己账号的Cookie能明显提高成功率。3. 实战写一个能跑的B站小工具3.1 需求拆解输入UID查“成分”网上热度很高的“B站输入uid查成分工具”说白了就是一个整合接口的页面。我们今天的实战目标就更明确一点输入用户的UID输出他的基本信息、粉丝数、关注数、最近发布的视频列表、以及最近动态。拆解一下只需要三步调card接口拿基础信息。调space投稿接口拿最近视频。调dynamic接口拿最近动态。3.2 请求头配置和WBI签名B站接口请求最基础的三样东西User-Agent、Referer、Cookie。UA我一般用浏览器的完整UAReferer填https://www.bilibili.com/Cookie至少要带buvid3和b_nut这两个是B站的匿名访问标识很多接口没有它们直接拒绝。但有一批用户维度的接口对风控更严格光有UA和Cookie还不够还得带WBI签名。WBI签名的过程是这样的先把所有参数按key的字典序排序拼接成字符串然后在这个字符串末尾加上一个固定的盐值ea1db124af3c7062474693fa704f4ff8再做MD5得到w_rid同时在请求里带上当前Unix时间戳wts。最后把w_rid和wts作为附加参数拼到URL里。这套签名看起来复杂写起来其实就几行代码import time import hashlib from urllib.parse import urlencode def wbi_sign(params: dict, salt: str ea1db124af3c7062474693fa704f4ff8) - dict: params dict(params) params[wts] int(time.time()) # 按key字典序排序 items sorted(params.items()) query urlencode(items) params[w_rid] hashlib.md5((query salt).encode()).hexdigest() return params实测下来有的接口必须签名有的不签名也能返回但为了稳定我还是全部加上。这里再提醒一句盐值不是永久固定的B站偶尔会更新如果某天你发现签名接口全部报错可以打开B站网页版随便点开一个视频在开发者工具里找到所有w_rid开头的请求从URL里反推当前盐值。3.3 完整代码流程演示我用Python写一个小例子核心逻辑大概长这样import requests session requests.Session() session.headers.update({ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://www.bilibili.com/, }) def get_user_card(mid: int) - dict: url https://api.bilibili.com/x/web-interface/card resp session.get(url, params{mid: mid}) data resp.json() if data[code] 0: return data[data] else: raise RuntimeError(f接口报错: {data[code]} {data[message]}) def get_recent_videos(mid: int, page_size: int 10) - list: url https://api.bilibili.com/x/space/wbi/arc/search params {mid: mid, pn: 1, ps: page_size, order: pubdate} params wbi_sign(params) resp session.get(url, paramsparams) data resp.json() if data[code] 0: return data[data].get(list, {}).get(vlist, []) else: raise RuntimeError(f接口报错: {data[code]} {data[message]}) if __name__ __main__: mid 170001 card get_user_card(mid) print(fUP主: {card[name]}, 粉丝: {card[fans]}, 关注: {card[attention]}) videos get_recent_videos(mid) for v in videos: print(f视频: {v[title]} (bvid{v[bvid]}))这里唯一需要解释的是/x/space/wbi/arc/search这个接口它是查用户投稿列表的属于需要WBI签名的接口。如果不用签名大概率返回-403。实际跑起来之后输入一个UID几秒钟就能拉回用户画像和近期投稿完全满足查成分的需求。3.4 接口报错后怎么快速定位问题开发过程中最常见的报错就那几种我遇到的基本都能对上号code-412请求被风控拦截了。一般是请求频率太高或者IP有异常解决方案是降低频率、加随机延时、清理无效Cookie。code-101未登录。有些接口必须带登录Cookie不带直接报这个。登录后的Cookie里最关键的是SESSDATA字段。code-403权限不足或者是WBI签名不对。先检查签名逻辑再检查账号权限。code-404视频不存在、已删除、或者当前账号无权限看充电视频。排查的顺序我总结过先看参数是否完整再看Cookie是否有效然后核对签名最后看请求头。90%的问题都是出在这四个环节上。4. 参数和API的高级玩法m4s合并、充电视频、倍速4.1 m4s文件为什么存在怎么合并前面提到playurl接口的fnval16会返回DASH格式视频流和音频流是分离的。B站为什么要这么做因为DASH是流媒体自适应协议可以根据用户网速动态切换清晰度而且音视频分离后可以在不重新编码视频的情况下单独切换音轨、字幕。但代价就是每个分片文件不是标准的MP4容器而是m4s格式电脑上的大多数播放器直接打不开。合并m4s其实非常简单用ffmpeg一条命令就够ffmpeg -i video.m4s -i audio.m4s -c copy output.mp4-c copy表示不重新编码直接拷贝流速度飞快一个几十分钟的视频几秒钟就合并完了。需要注意如果视频有封面、弹幕、字幕等附加流可能还需要加-map 0:v -map 1:a来指定映射否则ffmpeg会挑第一个视频流和第一个音频流。网上那些m4s合并工具的底层逻辑就是这个。如果你自己写只需要把playurl接口返回的dash.video[0].baseUrl和dash.audio[0].baseUrl下载下来再调ffmpeg合并就行。工具本身不复杂难点在于处理不同编码AV01、HEVC、AVC和不同音频格式AAC、杜比、高音质的兼容性。4.2 充电视频解析的正确打开方式B站的“充电专属视频”热度一直很高相关的解析网站和工具层出不穷。先说清楚原理这类视频调用/x/web-interface/view接口时data.badgepay字段会是true同时视频状态也会带一个rights.elec的标记。如果你尝试用playurl接口拿播放地址B站校验当前账号没有充电记录就会返回-403或者直接返回空数据。但如果你真的充过电用自己账号的Cookie去请求就能正常拿到DASH流后续处理和普通视频一样。换句话说这类工具的核心其实是“鉴权”而不是“破解”。平台在服务端做了权限校验正常的下载都能完成。这里必须多说一句不要想着绕过权限校验去抓别人的充电视频这在平台规则上属于违规行为账号很容易被风控甚至封禁。自己写工具自用、备份自己购买的内容完全没问题但公开传播和破解就踩线了。你能从别人的开源项目里学到很多接口调用思路但没必要去复刻那些灰色玩法。4.3 网页端倍速、快捷键和自定义参数“B站1.75倍速设置方法”、“网页版修改快捷键”这两个热词其实就是前端播放器的参数和事件处理问题。B站播放器默认提供0.5、0.75、1.0、1.25、1.5、2.0这几个倍速档位但如果你直接在浏览器控制台里找到video元素然后设置video.playbackRate 1.75就能突破档位限制。更进一步你可以用浏览器书签脚本或者油猴脚本在播放页加载后自动执行const video document.querySelector(video); video.playbackRate 1.75;快捷键方面B站播放器注册了一批默认键盘事件比如空格是播放/暂停D键是切换弹幕F键是全屏。想改成自己喜欢的键位可以通过拦截键盘事件来实现document.addEventListener(keydown, function (e) { if (e.key d) { // 跳过默认的弹幕开关改成别的操作 e.preventDefault(); // do something else } }, true);这里用到的是浏览器事件捕获机制在B站自己的处理函数之前把事件截获掉。道理不复杂但需要你对前端事件流有一定理解。4.4 常见AI接口报错和B站接口报错的对照写B站工具这几年我还经常在社区里看到有人把AI接口的报错和B站接口的报错混在一起问。比如“api error: 400 invalid schema for function artifact”这其实是调用某些大模型接口时参数schema校验失败意思是传给AI的参数结构不符合定义而不是B站的问题。这类问题排查思路和B站接口一样先看参数类型对不对再看必填项是否齐全。AI接口的schema错误往往是因为少传了name、parameters这些字段或者在parameters里用了错误的JSON格式。我自己的习惯是先打印出完整请求体和官方文档示例对比一遍90%的错误都能自己看出来。5. 常见问题与排查技巧实录5.1 请求频繁被风控的应对思路B站的风控不会提前通知你表现就是某一次请求开始所有接口突然返回-412。这个状态码的意思是请求被Web应用防火墙拦截了通常是IP被暂时加入了黑名单。我的应对思路是这几个降低请求频率同一IP的并发请求控制在每秒1-2次以内。每次请求之间加随机延时比如time.sleep(random.uniform(0.5, 1.5))。清理之前请求中带过的无效Cookie因为有些无效Cookie反而会触发风控。如果只是临时触发等待10-30分钟一般会自动恢复。换一个网络出口再等一段时间也能解决部分IP维度的问题。不要小看频率控制这个问题很多人的工具刚写完时跑得好好的挂了几个小时后突然所有接口都返回-412就是因为没控制频率。我写批量采集脚本时永远会先做一小批测试再放开全量爬。5.2 SESSDATA失效怎么提前感知登录Cookie里的SESSDATA是有有效期的B站网页端登录的SESSDATA一般几个月有效但过期时间不固定。一旦过期所有需要登录的接口都会返回-101。提前感知的方法是在程序启动时先请求一次https://api.bilibili.com/x/web-interface/nav这个接口会返回当前登录状态。如果data.isLogin是false直接退出并提示重新登录。这样比等到真正调业务接口时才报错要友好得多。另外补充一个细节bili_jct这个Cookie是CSRF令牌调POST接口或者需要写操作的接口时会用到调GET接口时一般用不上。5.3 参数类型对不上导致的400错误B站接口虽然整体很宽容但有个别接口对参数类型有严格要求。比如mid必须传int不能传字符串ps不能超过50pn必须大于等于1。如果你传了错误类型返回值可能是code-400或者code400。排查方法就是在调用前打印完整的请求URLresp session.get(url, paramsparams) print(resp.url) # 关键打印实际请求的URL然后肉眼检查URL里的参数有没有被错误编码、类型对不对。这个方法救了我不下十次很多看起来像“签名错误”的报错最后发现是参数类型问题。5.4 视频下载后无法播放大全下载下来的m4s文件合并好后无法播放这个问题的根源往往是视频流和音频流编码不兼容。比如视频流是AV1编码音频流是AAC这在旧版播放器上可能会出问题。解决办法有几个按优先级排序在playurl接口里通过fnval和fourk参数组合指定优先返回HEVC或者AVC编码的视频流。用ffmpeg合并时加上-strict experimental参数让格式兼容性更好。最终极的办法是-c:v libx264 -c:a aac重新编码但这样会损失画质且耗时较长。我个人的习惯是优先用dash.video列表里codecs字段包含avc的那个流兼容性好体积也在可接受范围内。写在最后B站参数和API这套东西其实没有你想象中那么难难的是把一个个零散的接口串成一个能解决问题的工具。多翻翻网页版开发者工具里的请求记录、多看看社区里的开源项目比死记文档管用得多。我自己踩过最大的坑就是盲目追求“最新接口”而忽略了基础参数的使用结果绕了一大圈发现官方文档里早就写好了。如果你准备动手写自己的工具建议先把这个页面的view接口跑通再往playurl和弹幕扩展循序渐进很快就上手了。