B站字幕提取全攻略:从手动抓包到Python自动化脚本实现

发布时间:2026/7/29 8:18:00

B站字幕提取全攻略:从手动抓包到Python自动化脚本实现 1. 项目概述为什么我们需要提取B站字幕做视频剪辑、内容学习或者二次创作的朋友估计都遇到过这个需求想把B站视频里的字幕单独弄出来。可能是为了做笔记把精彩的讲解整理成文字也可能是为了翻译把中文视频配上外文字幕又或者你是个UP主想借鉴一下同行的文案结构。直接手打效率太低而且B站网页和客户端通常不提供直接下载字幕的按钮。这时候一个能稳定、高效提取字幕的方法就成了刚需。我最近就因为要做一个知识分享系列需要批量处理几十个B站科普视频的字幕手动操作根本不可能于是把市面上常见的方法都折腾了一遍。从在线的工具网站到浏览器的开发者工具抓包再到用Python脚本解析踩了不少坑也总结出了一套目前根据我的测试环境亲测有效、且可持续性比较好的方案。这个方法的核心是绕开官方不提供的直接下载接口通过技术手段找到视频背后真正的字幕数据源通常是JSON格式然后将其转换为我们常用的SRT字幕格式。整个过程不需要复杂的爬虫对抗更多的是对网页结构和数据流的理解。无论你是完全不懂编程的小白还是有一定技术基础想了解原理的开发者这篇文章都会给你一个清晰的路径。我会从最简单的“开箱即用”工具讲起再到手动获取的详细步骤最后深入讲解用Python实现自动化的原理和代码你可以根据自己的情况选择合适的方法。2. 核心思路与方案选型字幕数据藏在哪里在动手之前我们得先搞清楚B站字幕的工作原理这样才能知道从哪里“下手”。B站视频的字幕无论是UP主上传的还是AI自动生成的最终在网页上显示时都不是以图片形式叠加的而是通过Web技术动态加载和渲染的文本。这些文本数据必然要从B站的服务器传输到你的浏览器。2.1 字幕数据的常见来源通过分析B站的页面加载过程字幕数据主要来自以下几个可能的接口视频信息接口 (view接口)当你打开一个B站视频页面时浏览器会请求一个包含视频所有元数据的接口其中可能内嵌了字幕列表信息包括字幕ID和语言。专用字幕接口 (subtitle接口)更常见的是页面会使用视频的cid内容ID或bvid视频ID去单独请求一个字幕文件。这个接口返回的数据就是我们最终需要的核心——一个结构化的JSON对象。播放器配置信息有时字幕信息也会在播放器的初始化配置数据中。对于我们提取者来说最稳定、最直接的目标就是那个返回结构化JSON数据的subtitle接口。我们的核心任务就是找到这个接口的请求地址获取到JSON数据然后将其解析、转换成SRT格式。2.2 几种实现方案的利弊分析知道了目标接下来看看有哪些路可以走方案原理优点缺点适用人群在线工具/浏览器插件工具背后集成了抓取和转换逻辑用户只需输入视频链接。最简单几乎零门槛点点鼠标就行。1. 有失效风险依赖工具作者的维护。2. 可能存在广告、收费或次数限制。3. 无法批量处理隐私数据需上传到第三方服务器。临时、单次提取且对技术无要求的用户。手动抓包开发者工具在浏览器中打开开发者工具F12监控网络请求手动找到并下载字幕JSON文件再用工具转换。完全免费可控性强能最直观地理解数据获取过程。不依赖第三方服务。步骤稍多需要一点耐心和学习成本。每个视频都需要重复操作。想了解原理、偶尔提取字幕且不排斥动手的技术爱好者。Python脚本自动化编写脚本自动模拟请求、解析视频页、获取cid、请求字幕接口、处理JSON并生成SRT。一次性投入永久受益。可批量处理效率极高。高度自定义可集成到其他工作流中。需要基本的Python编程环境和理解代码的能力。需要频繁或批量提取字幕的用户以及开发者。注意无论哪种方案其有效性都建立在B站前端接口未发生重大变更的基础上。如果某天发现方法失效大概率是接口地址或参数格式变了届时需要重新分析网络请求。我个人从手动抓包入门最终转向了Python自动化因为批量需求是实实在在的痛点。下面我就从手动抓包这个承上启下的方法开始详细讲解它能帮你透彻理解整个过程为后续的脚本编写打下坚实基础。3. 手动抓包提取法一步步找到字幕JSON这个方法不需要安装特殊软件只需要你电脑上有一个现代浏览器Chrome、Edge、Firefox等。其核心就是利用浏览器自带的“开发者工具”来监听网页的所有网络请求从中筛选出我们需要的字幕数据。3.1 详细操作步骤步骤一打开目标视频并启动开发者工具用浏览器打开你想提取字幕的B站视频页面。按下键盘上的F12键或右键点击页面选择“检查”打开开发者工具。切换到“网络” (Network)标签页。为了更清晰地捕捉数据建议先点击标签页上的红色圆形按钮或按CtrlE清空当前的记录然后勾选上“保留日志” (Preserve log)。步骤二触发字幕加载并寻找请求在视频播放器下方找到字幕选择按钮通常是一个“字幕”或“CC”图标。如果视频有字幕包括AI生成点击它并选择一种语言如“中文自动生成”。这个操作会触发浏览器向B站服务器请求具体的字幕数据。此时你的“网络”标签页会刷出一系列新的请求。我们需要在这些请求中找到字幕文件。步骤三筛选并定位字幕接口在“网络”标签页的筛选栏Filter中输入关键词如subtitle、caption或json。这能快速过滤出可能的请求。仔细浏览筛选后的请求列表。目标请求通常具有以下特征名称 (Name)可能包含subtitle、caption等字样。类型 (Type)通常是fetch或xhr。地址 (URL)URL中很可能包含subtitle或api.bilibili.com等路径。一个常见的模式是https://api.bilibili.com/x/player/v2?cidxxxaidxxx之类的但更直接的是https://api.bilibili.com/x/player/wbi/v2/subtitle?...这种。点击这个疑似请求在右侧面板中查看“预览” (Preview)或“响应” (Response)标签页。如果你看到了一个结构清晰的JSON数据里面包含body字段而body里是一段段带有from开始时间、to结束时间、content字幕内容的数组那么恭喜你找到了步骤四下载并保存JSON数据在找到的正确请求上右键点击选择“复制” - “复制链接地址” (Copy - Copy link address)或“复制为cURL”。但更简单的方式是直接查看响应内容。在“响应” (Response)标签页你应该能看到完整的JSON文本。全选CtrlA、复制CtrlC这段文本。打开一个文本编辑器如记事本、VS Code、Sublime Text将内容粘贴进去保存为一个.json文件例如subtitle.json。步骤五将JSON转换为SRT格式现在你有了原始数据但它不是通用的字幕格式。我们需要将其转换为.srt格式这种格式能被绝大多数播放器和剪辑软件识别。使用在线转换工具推荐给新手搜索“JSON to SRT converter”能找到很多在线网站。将你保存的subtitle.json文件内容粘贴到输入框或者直接上传文件网站会自动转换并允许你下载.srt文件。务必注意隐私避免上传敏感视频的字幕。使用本地脚本更安全可控你可以使用一个简单的Python脚本来转换。假设你的JSON结构里字幕列表在data[body]里每个条目有from秒、to秒、content字段。下面是一个极简的转换脚本示例import json # 1. 读取你保存的JSON文件 with open(subtitle.json, r, encodingutf-8) as f: data json.load(f) # 2. 假设字幕数据在 data[body] 中请根据你实际抓取的数据结构调整路径 # 例如有时可能在 data[data][body] 或 data[subtitle][body] subtitles data.get(body, []) # 如果不在body尝试打印data.keys()看看结构 # print(data.keys()) # 3. 转换并写入SRT文件 with open(output.srt, w, encodingutf-8) as srt_file: for i, sub in enumerate(subtitles, start1): start_time sub[from] # 单位秒 end_time sub[to] # 单位秒 content sub[content] # 将秒转换为SRT时间格式HH:MM:SS,mmm def sec_to_srt_time(sec): hrs int(sec // 3600) mins int((sec % 3600) // 60) secs int(sec % 60) msec int((sec - int(sec)) * 1000) return f{hrs:02d}:{mins:02d}:{secs:02d},{msec:03d} srt_start sec_to_srt_time(start_time) srt_end sec_to_srt_time(end_time) # 写入SRT块 srt_file.write(f{i}\n) srt_file.write(f{srt_start} -- {srt_end}\n) srt_file.write(f{content}\n\n)运行这个脚本需要安装Python就能在本地生成output.srt文件。3.2 实操心得与常见问题找不到subtitle请求首先确认视频确实有字幕包括AI字幕。然后在清空网络日志后尝试刷新页面或者切换一下字幕语言确保动作被记录。有时接口名可能不包含“subtitle”尝试过滤“json”或查看所有XHR请求通过预览内容来判断。JSON结构看不懂在开发者工具的“预览”窗格JSON数据通常是折叠的。你可以点击展开观察数据结构。核心是找到包含时间戳和文本内容的数组。如果上述脚本的data[body]路径不对就在脚本里添加print(json.dumps(data, indent2, ensure_asciiFalse))来漂亮地打印整个JSON然后找到正确的路径。时间格式不对确认B站返回的时间单位是秒通常是小数。上述转换函数能正确处理。如果发现字幕不同步检查一下时间戳计算是否正确。“保留日志”很重要如果不勾选页面刷新或导航时之前的请求记录会被清空你可能就抓不到加载字幕的那个请求了。手动方法虽然每一步都很清晰但处理多个视频时非常繁琐。接下来我们就进入自动化阶段用Python脚本一键搞定所有流程。4. Python自动化脚本实现原理与代码解析当你需要处理几十上百个视频时手动抓包就成了体力活。编写一个Python脚本让程序自动完成“获取视频信息-定位字幕接口-下载并转换”的全流程是最高效的解决方案。这里我将拆解一个相对稳定且考虑了常见问题的脚本。4.1 环境准备与依赖库首先确保你的电脑安装了Python 3.6及以上版本。我们需要安装几个关键的库requests用于发送HTTP请求获取网页和API数据。jsonPython标准库用于解析JSON数据。re正则表达式库用于从网页源码中提取关键ID。安装命令非常简单在命令行中执行pip install requests4.2 脚本核心步骤拆解一个健壮的自动化脚本应该包含以下模块1. 获取视频的bvid和cidB站视频有两个重要IDbvid如BV1xx411c7mh是视频的唯一标识出现在网址中cid是分P章节的标识一个bvid可能对应多个cid多P视频。字幕接口通常需要cid。 我们可以通过解析视频页面HTML或者调用B站的公开API来获取这些ID。从页面源码提取是一种直接且不易过时的方法。2. 请求字幕列表接口获取字幕ID有了cid我们可以请求一个字幕列表接口获取该视频所有可用字幕的信息包括每种语言的字幕IDsubtitle_id。3. 使用字幕ID请求具体的字幕JSON数据用上一步得到的subtitle_id去请求最终的字幕内容接口拿到包含时间轴和文本的JSON数据。4. 解析JSON并转换为SRT格式这部分逻辑与手动方法中的转换脚本类似将获取到的JSON数据解析并按照SRT格式写入文件。4.3 完整脚本示例与逐行解读下面是一个整合了以上步骤并加入了错误处理和简单重试机制的Python脚本示例。请将其保存为bilibili_subtitle_downloader.py。import requests import json import re import time from urllib.parse import urlparse def get_bvid_and_cid(url): 从B站视频URL中提取bvid并通过API获取cid。 # 解析URL提取bvid (BV号) parsed urlparse(url) path parsed.path bvid_match re.search(r(BV[0-9A-Za-z]{10}), path) if not bvid_match: raise ValueError(无法从URL中提取有效的BV号。) bvid bvid_match.group(0) print(f提取到BVID: {bvid}) # 使用B站API通过bvid获取视频信息包含cid # 这个API相对稳定但未来可能变化 info_api_url fhttps://api.bilibili.com/x/web-interface/view?bvid{bvid} 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 } try: resp requests.get(info_api_url, headersheaders, timeout10) resp.raise_for_status() # 检查HTTP错误 info_data resp.json() if info_data[code] ! 0: raise Exception(fAPI返回错误: {info_data.get(message)}) # 获取第一个分P的cid通常是最主要的 cid info_data[data][cid] title info_data[data][title] print(f获取到CID: {cid}, 视频标题: {title}) return bvid, cid, title except requests.exceptions.RequestException as e: print(f请求视频信息失败: {e}) # 备用方案尝试从旧版页面源码中查找cid稳定性较差 print(尝试备用方案从页面源码提取...) page_resp requests.get(url, headersheaders, timeout10) cid_match re.search(rcid:(\d), page_resp.text) if cid_match: cid cid_match.group(1) print(f从页面源码提取到CID: {cid}) return bvid, cid, Unknown Title else: raise Exception(无法获取视频CID请检查链接或网络。) def get_subtitle_list(bvid, cid): 获取视频的字幕列表返回字幕信息。 subtitle_list_api fhttps://api.bilibili.com/x/player/v2?bvid{bvid}cid{cid} headers { User-Agent: Mozilla/5.0 ..., # 同上 Referer: fhttps://www.bilibili.com/video/{bvid} } resp requests.get(subtitle_list_api, headersheaders) data resp.json() if data[code] 0 and data[data][subtitle][subtitles]: subtitles_info data[data][subtitle][subtitles] print(f找到 {len(subtitles_info)} 个字幕轨道。) for idx, sub in enumerate(subtitles_info): print(f [{idx}] 语言: {sub[lan_doc]} (ID: {sub[id]})) return subtitles_info else: print(未找到字幕列表或视频无字幕。) return [] def download_subtitle_json(subtitle_id, cid, bvid): 根据字幕ID下载具体的字幕JSON数据。 # 这个接口地址和参数可能会变化这是当前可用的模式之一 subtitle_api_url fhttps://api.bilibili.com/x/player/wbi/v2/subtitle?subtitle_id{subtitle_id} # 注意新接口可能需要额外的签名参数(wbi签名)上述简单接口可能不稳定。 # 更稳定的方法是使用web接口它通常不需要复杂签名。 # 备用接口https://api.bilibili.com/x/player/wbi/v2/subtitle/web?subtitle_id... # 如果上述接口失效请按第3节方法抓包获取最新的有效接口。 headers { User-Agent: Mozilla/5.0 ..., Referer: fhttps://www.bilibili.com/video/{bvid} } # 添加常见参数有些接口需要 params { subtitle_id: subtitle_id, cid: cid, bvid: bvid } resp requests.get(subtitle_api_url, headersheaders, paramsparams) data resp.json() # 打印一下数据结构方便调试 # print(json.dumps(data, indent2, ensure_asciiFalse)) if data[code] 0: # 字幕正文通常在 data[data][body] 里 body data[data][body] return body else: print(f下载字幕失败响应: {data}) return None def json_to_srt(subtitle_body, output_filenameoutput.srt): 将字幕JSON body转换为SRT格式文件。 with open(output_filename, w, encodingutf-8-sig) as f: # utf-8-sig 解决某些播放器乱码 for i, item in enumerate(subtitle_body, start1): from_time item[from] to_time item[to] content item[content].strip() # 转换时间格式 def sec_to_srt(t): hours int(t // 3600) minutes int((t % 3600) // 60) seconds int(t % 60) milliseconds int((t - int(t)) * 1000) return f{hours:02d}:{minutes:02d}:{seconds:02d},{milliseconds:03d} start_srt sec_to_srt(from_time) end_srt sec_to_srt(to_time) f.write(f{i}\n) f.write(f{start_srt} -- {end_srt}\n) f.write(f{content}\n\n) print(f字幕已保存为: {output_filename}) def main(): video_url input(请输入B站视频链接: ).strip() try: # 1. 获取基础ID bvid, cid, title get_bvid_and_cid(video_url) # 2. 获取字幕列表 subtitle_list get_subtitle_list(bvid, cid) if not subtitle_list: print(程序退出。) return # 3. 让用户选择这里默认选第一个通常是中文 choice 0 if len(subtitle_list) 1: try: choice int(input(f请输入要下载的字幕编号 (0-{len(subtitle_list)-1})默认[0]: ) or 0) except ValueError: choice 0 selected_sub subtitle_list[choice] print(f正在下载字幕: {selected_sub[lan_doc]}...) # 4. 下载字幕JSON subtitle_body download_subtitle_json(selected_sub[id], cid, bvid) if subtitle_body: # 5. 转换为SRT safe_title re.sub(r[\\/*?:|], _, title) # 清理文件名非法字符 output_file f{safe_title}_{selected_sub[lan_doc]}.srt json_to_srt(subtitle_body, output_file) else: print(字幕内容为空或下载失败。) except Exception as e: print(f程序运行出错: {e}) # 建议用户使用手动抓包法作为后备 print(\n自动脚本可能因接口更新而失效。) print(建议使用文章第3部分介绍的‘手动抓包法’进行提取该方法更底层适应性更强。) if __name__ __main__: main()4.4 脚本使用与自定义说明运行脚本在命令行中进入脚本所在目录运行python bilibili_subtitle_downloader.py。根据提示输入视频链接即可。接口失效处理脚本中最脆弱的环节是download_subtitle_json函数中的API地址。如果B站更新了接口这里可能会返回错误。此时的最佳策略是回归到“手动抓包法”用开发者工具抓取到最新的、有效的字幕接口URL和必要的参数如wbi签名参数然后替换脚本中的subtitle_api_url和params。这是自动化脚本维护的常态。批量处理你可以修改main函数从一个文本文件中读取多个视频链接用循环遍历处理实现批量下载。错误处理脚本中包含了基本的网络请求超时和JSON解析错误处理。对于生产环境你可能需要增加重试机制和更详细的日志记录。5. 常见问题排查与进阶技巧即使按照步骤操作你也可能会遇到一些棘手的情况。这里我汇总了一些常见问题及其解决方案。5.1 问题排查速查表问题现象可能原因解决方案手动抓包时找不到任何字幕相关请求1. 视频本身无字幕包括AI字幕。2. 字幕已内嵌到视频流中较少见。3. 网络请求被过滤或未触发。1. 确认视频播放器有字幕开关且已开启。2. 清空网络日志刷新页面重新点击字幕按钮。3. 在Network筛选栏尝试搜索“json”或“subtitle”并检查所有XHR请求。Python脚本报错无法获取cid或bvid1. 视频链接格式不正确。2. B站API接口发生变化。3. 网络问题或请求被限制。1. 确保链接是标准的B站视频页链接含BV号。2. 使用手动抓包法从页面源码中搜索cid:来验证当前结构。3. 在脚本中增加print(resp.text)打印原始响应分析数据结构。脚本能获取列表但下载字幕JSON失败字幕内容接口URL或参数已更新。这是最常见的问题。立即使用手动抓包法抓取最新的有效请求更新脚本中的subtitle_api_url和请求参数特别是注意是否有w_rid和wts这类签名参数。转换后的SRT文件时间轴错乱1. 时间戳单位不是秒。2. JSON中的时间戳格式有误。3. 转换函数计算错误。1. 检查原始JSON数据中from和to字段的值确认是秒如 123.456。2. 调试转换函数sec_to_srt打印中间值核对。SRT文件在播放器中显示乱码文件编码问题。确保保存SRT文件时使用UTF-8编码特别是Windows记事本默认可能是ANSI。在Python中使用encodingutf-8-sig打开文件可以添加BOM头兼容更多软件。批量处理时被IP限制或封禁请求频率过高触发了B站的反爬机制。1. 在请求间增加随机延时如time.sleep(random.uniform(1, 3))。2. 使用代理IP池复杂度较高。3. 降低处理速度模拟人工操作。5.2 进阶技巧与注意事项优先选择“AI生成字幕”对于没有UP主上传字幕的视频B站提供的“AI生成字幕”准确率已经相当高是提取的主要来源。在抓包或脚本中它通常对应lan_doc为“中文自动生成”的轨道。处理多P视频一个bvid可能对应多个cid分集。上述脚本默认获取第一个cid。如果你需要所有分集字幕需要先从视频信息API的data[pages]字段中获取所有分P的cid列表然后循环处理。字幕翻译获取到SRT后你可以利用翻译API如Google Translate, DeepL等或本地翻译工具快速生成外文字幕文件这对于内容出海非常有用。法律与道德边界提取字幕用于个人学习、笔记、无障碍访问是合理的。但请务必尊重UP主的著作权不要将提取的字幕用于商业用途、重新分发或制作盗版视频。技术是中立的但使用技术的人需要负责任。保持更新网页技术日新月异本文介绍的方法在2024年中测试有效。如果未来失效核心思路抓包找接口不会变只是具体的接口地址和参数需要你通过开发者工具重新抓取分析。掌握这个“渔”比拿到现成的“鱼”更重要。这个从手动到自动的完整流程不仅解决了B站字幕提取的问题更提供了一套应对类似网页数据抓取需求的通用思路观察 - 定位 - 获取 - 解析 - 转换。

相关新闻