
前阵子在群里看到有人问“B站视频怎么批量下载网上那些解析站是怎么做的”接着又有人甩出“查成分工具”“充电视频解析”这类词。我当时就意识到很多人并不是真的缺工具而是搞不懂B站网页端那一大堆参数和API接口到底是怎么回事。只要你把URL里的参数看懂了把常见接口的调用逻辑摸清了那些所谓的“工具”绝大部分你都能自己写出来。这篇小教程不搞大而全的源码框架就围绕一件事展开B站的网页版参数和API接口从URL拆解到实际请求再到几个热门工具的原理还原。适合想入门爬虫、想自己做B站小工具、或者单纯想弄明白“解析站到底做了什么”的读者。文章里会穿插Python示例但我尽量让你不贴代码也能看懂逻辑。1. 先搞懂B站URL里的那些“参数”到底是什么1.1 从一次“想下载视频”说起假设你现在就想把一个B站视频下载到本地。你复制了地址栏链接大概是这样的https://www.bilibili.com/video/BV1xx411c7XX?p2t30spm_id_from333.999.0.0如果你直接拿这个链接去请求能拿到页面但拿不到视频文件本身。因为真正的视频地址藏在页面里需要API接口根据参数去换。所以第一步你得能看懂这个URL里哪些参数是干什么用的。很多时候工具没效果不是你代码写错了而是参数不对。我见过不少新手在网上搜“B站API”搜到一两个接口就开干结果请求返回一串看不懂的JSON最后卡在“怎么从响应里找到视频地址”这一步。根本原因就是没建立“参数→接口→响应”这个整体认知。1.2 一个视频页URL的完整拆解拿上面那个URL举例拆开来看参数示例值含义是否需要手动设置bvidBV1xx411c7XX视频唯一IDB站现在的通行标识必须p2分P序号表示第几个分P可选t30播放进度单位秒用于自动跳转可选spm_id_from333.999.0.0流量来源追踪参数可选vd_source一串随机字符渠道来源参数用于统计可选bvid是核心几乎所有视频相关接口都要用到它。它和早期的av号是一一对应的接口里也经常返回aidav号的数字形式所以你在请求里写bvidBV1xx411c7XX或者aid170001效果一样但现在官方更推荐用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?bvidBV1xx411c7XXcid123456fnval16qn125光看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/playurlview接口是我个人使用频率最高的。你只要传一个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之后你才能继续去请求播放地址。所以标准链路是bvid→view接口 →cid→playurl接口 → 视频流地址。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接口参数有type1表示视频类型oid填视频cidpn和ps控制分页。如果你想分析某个视频的评论情感倾向或者做词云这个接口是主力。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_list、dm_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为4K120为2K116为1080P60112为1080P fourk: 1 } play_data session.get(play_api, paramsparams).json() video_url play_data[data][dash][video][0][baseUrl] audio_url play_data[data][dash][audio][0][baseUrl]fnval16和qn125是这里最关键的参数。fnval16表示要求返回DASH格式意思是视频和音频分离——视频流只有画面没有声音音频流只有声音没有画面。设置qn125时要留意你账号的清晰度权限没有大会员时直接要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.m4s和audio.m4s。下一步用ffmpeg把它们合并成一个完整的MP4ffmpeg -i video.m4s -i audio.m4s -c copy output.mp4到这里一个最小化的B站视频下载流程就跑通了。整个流程的逻辑链非常清晰bvid p→view接口→cid→playurl接口→音视频流地址→ 下载 →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 敏捷开发里的“必要参数”思路做工具时我习惯先列一个“必要参数清单”再对着接口文档逐一核对。比如下载工具的必要参数是bvid和cid而qn、fnval属于可调参数。这样一旦请求失败排查范围会小很多。很多开源项目里的参数比我上面写的要多得多比如platformhtml5、high_quality1、devicephone之类。这些参数不是没用而是它们要么是为特定客户端设计的要么是历史遗留。新手别照抄要以自己实际测试为准。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失效登录过期重新从浏览器复制Cookie5.6 顺手提一下“B站网页版修改快捷键”热搜词里有“b站网页版修改快捷键”这其实是B站网页播放器的一个快捷键设置页面。顺带说一句B站在网页端的快捷键体系是通过本地存储保存的不是通过API。所以如果你想去改它思路是操作浏览器的localStorage而不是调接口。理解了“网页功能≠全部走API”这个道理很多困惑都会解开。最后再说点实在的我在实际写B站相关脚本的过程中最深的一个体会是接口文档不重要重要的是参数语义。B站官方没有公开过正式的API文档所有接口地址、参数说明都是社区开发者通过抓包总结出来的。所以网上流传的“接口大全”随时可能过期你要学会自己打开浏览器开发者工具找到Network面板里那一个个XHR请求自己看参数、看响应。另一个经验是能请求到结果不代表你理解了过程。建议你亲手把view接口、playurl接口的返回JSON完整看一遍不急着写代码先弄清楚每个字段是什么意思。这个“读JSON”的能力比背十个接口路径都管用。最后建议你从小需求入手练手比如写一个脚本把自己最近投币过的视频信息导成表格或者统计某个UP主最近一年视频的播放量趋势。整个过程会强迫你搞懂参数、签名、分页、异常处理等这些基本功练扎实了再回来看“解析站”们的原理你会发现一切都很透明。