哔哩哔哩(B 站)作为国内领先的视频社区,其item_get_video接口是获取单条视频精细化详情的核心工具,可返回视频播放地址、分集信息、互动数据、UP 主信息等关键内容,广泛应用于视频聚合平台、内容数据分析、二次创作素材调研、舆情监测等场景。
本攻略从接口认知、前置准备、实操对接、调试优化到合规上线,提供全流程结构化指导,兼顾入门易用性与生产级稳定性,助力开发者高效完成对接。
一、接口核心认知:功能与适配场景
1. 接口定位与核心价值
- 核心功能:输入 B 站视频 AV 号 / BV 号 / 视频 ID,即可获取该视频的基础信息、播放数据、互动数据、UP 主信息、分集列表等全量详情,部分接口还支持返回视频字幕、分 P 时长、版权信息等进阶字段。
- B 站平台特性
- 数据覆盖:支持番剧、国创、UP 主自制视频、直播回放等全品类视频,新视频收录延迟 5-10 分钟;
- 专属字段:包含 B 站独有的弹幕数、投币数、收藏数、充电数 等互动指标,以及分区标签、创作激励状态等平台特色字段;
- 权限分层:基础字段(标题、播放量)支持普通权限,进阶字段(播放链接、字幕)需企业级或专项权限;
- 多格式兼容:支持 AV 号(旧格式)、BV 号(新格式)、video_id(接口专用 ID)三种标识查询。
- 典型应用场景
- 视频聚合工具:接入 B 站视频详情,为用户提供一站式视频检索与播放入口;
- 内容数据分析:采集视频互动数据,分析不同分区内容的用户偏好、爆款视频特征;
- 二次创作调研:获取视频标签、简介等信息,辅助创作者定位选题方向;
- 舆情监测:追踪品牌 / 事件相关视频的传播数据(播放量、评论数),掌握舆论走向;
- 番剧运营分析:获取番剧分集播放数据,评估剧集热度与用户追更意愿。
2. 核心参数与返回字段
(1)请求参数(必填 + 可选,按优先级排序)
| 参数名称 | 类型 | 是否必填 | 说明 | 应用示例 |
|---|---|---|---|---|
| appkey | string | 是 | 接口调用密钥,由 B 站开放平台 / 合规服务商分配 | bilibili_123abc |
| secret | string | 是 | 签名密钥,用于请求合法性校验(不可泄露) | bilibili_def456 |
| video_id | string | 是 | 视频标识,支持 AV 号(av123456)、BV 号(BV1xx411c7m9)、接口专用 video_id | BV1xx411c7m9 |
| need_page | int | 否 | 是否返回分 P 信息,默认 1(返回) | 1(返回分 P)、0(仅返回主视频) |
| need_danmu | int | 否 | 是否返回弹幕相关数据,默认 0(不返回) | 1(返回弹幕数 / 弹幕关键词) |
| need_up_info | int | 否 | 是否返回 UP 主详细信息,默认 1(返回) | 0(仅返回 UP 主 ID / 昵称) |
| timestamp | long | 是 | 请求时间戳(毫秒级,有效期 5 分钟) | 1735689600000 |
| sign | string | 是 | 签名值(按 B 站规则生成,核心校验项) | 32 位 MD5 大写串 |
注意事项
- 视频标识优先级:
video_id传入 BV 号时,接口会自动转换为内部 ID,无需手动解析;- 权限关联:
need_danmu=1需额外申请弹幕数据权限,普通账号默认不开放。
(2)返回核心字段(按业务场景分类)
| 字段分类 | 核心字段 | 说明 |
|---|---|---|
| 视频基础信息 | bvid | 视频 BV 号(对外唯一标识) |
| aid | 视频 AV 号(旧标识,部分场景兼容) | |
| title | 视频标题(含分区前缀 / 营销文案) | |
| cover_url | 视频封面图 URL(高清) | |
| duration | 视频总时长(秒,分 P 视频为所有分 P 总和) | |
| pubdate | 视频发布时间(时间戳 / 格式化时间) | |
| cid | 视频分 P 标识(单 P 视频 cid 唯一,多 P 视频每个分 P 对应一个 cid) | |
| desc | 视频简介(UP 主自定义文案) | |
| tags | 视频标签列表(如 "原神""教程""搞笑") | |
| category | 视频分区(如 "游戏 - 原神""知识 - 科普") | |
| 播放与互动数据 | view | 累计播放量 |
| danmaku | 累计弹幕数 | |
| reply | 评论数 | |
| favorite | 收藏数 | |
| coin | 投币数 | |
| like | 点赞数 | |
| share | 转发数 | |
| charge | 充电数(用户对 UP 主的打赏) | |
| current_rank | 全站实时排名(部分热门视频有值) | |
| 分 P 信息(need_page=1 时返回) | pages | 分 P 列表,包含分 P 标题、时长、cid |
| page_count | 分 P 总数 | |
| UP 主信息 | mid | UP 主 ID |
| name | UP 主昵称 | |
| face | UP 主头像 URL | |
| follower | UP 主粉丝数 | |
| level | UP 主等级(1-6 级) | |
| official_verify | 认证类型(个人 / 企业 / 官方) | |
| 其他字段 | copyright | 版权类型(1 = 原创,2 = 转载) |
| state | 视频状态(0 = 正常,-1 = 审核中,-2 = 已下架) | |
| play_url | 视频播放链接(需权限,部分接口仅返回跳转链接) |
3. 接口限制与注意事项
-
调用频率限制
账号类型 调用频率 适用场景 个人开发者 5 次 / 分钟 个人素材调研、小型分析工具 企业开发者 30 次 / 分钟 商业数据分析、内容聚合平台 -
数据缓存规则:视频基础信息缓存 1 小时,互动数据(播放量 / 点赞数)缓存 5 分钟,热门视频缓存时效缩短至 1 分钟;
-
内容限制:已下架 / 违规视频、隐私视频(仅粉丝可见)、未过审视频不会返回;番剧等版权内容仅返回基础信息,无播放链接;
-
合规要求:禁止通过接口获取视频源文件进行盗播,播放链接需跳转至 B 站站内,二次创作需遵守 B 站版权规则。
二、对接前准备:权限与环境搭建
1. 获取接口权限(两种接入方式)
B 站item_get_video接口无公开免费接入渠道,需通过官方开放平台 或合规第三方服务商获取权限,具体对比如下:
| 接入方式 | 操作步骤 | 优缺点 |
|---|---|---|
| B 站开放平台(官方) | 1. 登录B站开发平台;2. 完成账号认证(个人实名认证 / 企业营业执照认证);3. 创建应用,选择 "内容数据 / 视频服务" 类目;4. 申请item_get_video接口权限,提交业务用途说明;5. 审核通过后,在应用详情页获取appkey和secret |
优点:数据权威、字段完整、合规性强;缺点:审核严格(企业需提供业务证明)、周期长(3-7 个工作日)、部分字段(播放链接)需专项授权 |
| 第三方合规服务商 | 1. 选择口碑合规的服务商(如聚合数据、APISpace);2. 注册账号并完成实名认证;3. 购买 B 站视频接口套餐;4. 在服务商后台获取appkey和接口调用地址 |
优点:接入快(10 分钟完成)、无需复杂资质、调试工具完善;缺点:部分进阶字段(弹幕关键词)需付费升级、调用次数有配额限制 |
风险提示:严禁使用非法爬虫接口,违反 B 站用户协议及《网络安全法》,存在账号封禁、法律追责风险。
2. 技术环境准备
(1)支持语言与协议
- 协议:HTTPS(强制,保障数据传输安全);
- 开发语言:支持 Python、Java、PHP、Go 等所有主流语言,推荐Python(数据处理便捷,适配多场景解析需求)。
(2)必备工具与依赖
| 工具类型 | 推荐工具 | 用途 |
|---|---|---|
| 调试工具 | Postman | 快速验证接口可用性,排除代码逻辑干扰 |
| 在线 MD5 工具 | 校验签名生成正确性 | |
| B 站 BV 号 / AV 号转换器 | 验证视频标识有效性 | |
| 开发依赖 | requests(Python) | 发送 HTTP 请求 |
| hashlib(Python) | 生成接口签名 | |
| pandas(Python) | 批量整理视频数据 | |
| jsonpath-ng | 快速解析嵌套 JSON 响应 | |
| 辅助工具 | Redis | 缓存视频详情,减少重复请求 |
| logging | 记录接口调用日志,便于问题追溯 |
三、实操步骤:接口对接全流程(Python 示例)
步骤 1:理解 B 站接口签名规则
B 站官方接口签名采用MD5 加密 ,第三方服务商通常沿用类似规则,核心逻辑为参数排序 + 拼接密钥 + MD5 加密,具体步骤如下:
- 剔除参数中的
sign字段(若存在); - 将剩余参数按参数名 ASCII 升序排序;
- 拼接为
key1=value1&key2=value2&...的字符串; - 在字符串末尾拼接
&secret=你的secret; - 对拼接后的字符串进行 MD5 加密,生成 32 位大写字符串即为
sign。
签名示例
假设参数:appkey=bilibili_123abc、video_id=BV1xx411c7m9、timestamp=1735689600000、secret=bilibili_def456
- 排序后参数:
appkey、timestamp、video_id; - 拼接字符串:
appkey=bilibili_123abc×tamp=1735689600000&video_id=BV1xx411c7m9&secret=bilibili_def456; - MD5 加密后得到
sign:A1B2C3D4E5F67890123456789ABCDEF0。
步骤 2:完整代码实现(Python)
(1)依赖安装
bash
pip install requests pandas jsonpath-ng
(2)核心代码(含签名生成、接口调用、数据解析)
python
import requests
import hashlib
import time
import json
import pandas as pd
from urllib.parse import urlencode
from jsonpath_ng import parse
import logging
# 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
# 日志配置(记录接口调用与错误信息)
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[logging.FileHandler("bilibili_item_get_video.log"), logging.StreamHandler()]
)
# 接口配置(替换为自身的appkey、secret、接口地址)
CONFIG = {
"appkey": "你的appkey",
"secret": "你的secret",
"api_url": "https://api.example.com/bilibili/item_get_video", # 官方/服务商接口地址
"save_path": "B站视频详情.xlsx"
}
def generate_sign(params: dict, secret: str) -> str:
"""生成B站接口签名(MD5 32位大写)"""
# 移除sign字段(若存在)
params.pop("sign", None)
# 按参数名ASCII升序排序
sorted_params = sorted(params.items(), key=lambda x: x[0])
# 拼接参数字符串并追加secret
param_str = urlencode(sorted_params, encoding="utf-8") + f"&secret={secret}"
# MD5加密并转大写
md5 = hashlib.md5()
md5.update(param_str.encode("utf-8"))
return md5.hexdigest().upper()
def parse_bilibili_data(raw_data: dict) -> dict:
"""解析B站视频原始数据,标准化输出格式"""
# 提取UP主信息
up_info = raw_data.get("owner", {}) or raw_data.get("up_info", {})
# 提取分P信息
page_info = raw_data.get("pages", [])
page_count = len(page_info) if page_info else 1
page_titles = [page.get("part", "") for page in page_info] if page_info else [raw_data.get("title", "")]
# 格式化时间
pubdate = raw_data.get("pubdate", 0)
pubdate_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(pubdate)) if pubdate else ""
return {
"BV号": raw_data.get("bvid", ""),
"AV号": raw_data.get("aid", ""),
"视频标题": raw_data.get("title", ""),
"封面链接": raw_data.get("pic", raw_data.get("cover_url", "")),
"总时长(分:秒)": f"{raw_data.get('duration', 0)//60}:{raw_data.get('duration', 0)%60:02d}",
"发布时间": pubdate_str,
"视频分区": raw_data.get("tname", raw_data.get("category", "")),
"视频标签": ",".join(raw_data.get("tags", [])),
"视频简介": raw_data.get("desc", ""),
"版权类型": "原创" if raw_data.get("copyright", 2) == 1 else "转载",
"视频状态": "正常" if raw_data.get("state", 0) == 0 else "审核中" if raw_data.get("state") == -1 else "已下架",
"播放量": raw_data.get("view", 0),
"弹幕数": raw_data.get("danmaku", 0),
"评论数": raw_data.get("reply", 0),
"收藏数": raw_data.get("favorite", 0),
"投币数": raw_data.get("coin", 0),
"点赞数": raw_data.get("like", 0),
"转发数": raw_data.get("share", 0),
"充电数": raw_data.get("charge", 0),
"分P总数": page_count,
"分P标题": "|".join(page_titles),
"UP主ID": up_info.get("mid", ""),
"UP主昵称": up_info.get("name", up_info.get("uname", "")),
"UP主头像": up_info.get("face", ""),
"UP主粉丝数": up_info.get("follower", 0),
"UP主等级": up_info.get("level", 0),
"认证类型": up_info.get("official_verify", {}).get("type", -1),
"播放链接": raw_data.get("play_url", "需跳转B站站内"),
"请求时间": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
}
def bilibili_item_get_video(
video_id: str,
need_page: int = 1,
need_up_info: int = 1,
need_danmu: int = 0
) -> dict:
"""
调用B站item_get_video接口,获取视频详情
:param video_id: BV号/AV号/接口video_id
:param need_page: 是否返回分P信息
:param need_up_info: 是否返回UP主详情
:param need_danmu: 是否返回弹幕数据
:return: 标准化的视频详情
"""
# 1. 构建基础参数
params = {
"appkey": CONFIG["appkey"],
"video_id": video_id,
"need_page": need_page,
"need_up_info": need_up_info,
"need_danmu": need_danmu,
"timestamp": int(time.time() * 1000)
}
# 2. 生成签名
params["sign"] = generate_sign(params, CONFIG["secret"])
try:
# 3. 发送POST请求
response = requests.post(
url=CONFIG["api_url"],
data=json.dumps(params),
headers={"Content-Type": "application/json"},
timeout=15,
verify=True
)
response.raise_for_status() # 抛出HTTP异常
result = response.json()
# 4. 解析响应
if result.get("code") == 0 or result.get("status") == "success":
raw_video = result.get("data", result.get("result", {}))
if not raw_video:
logging.warning(f"无视频数据返回(视频ID:{video_id})")
return {"success": False, "error_msg": "无视频数据"}
standard_data = parse_bilibili_data(raw_video)
return {
"success": True,
"data": standard_data,
"error_msg": ""
}
else:
error_msg = result.get("msg", result.get("message", "接口调用失败"))
logging.error(f"接口返回错误(视频ID:{video_id}):{error_msg}(code={result.get('code')})")
return {"success": False, "error_msg": error_msg}
except requests.exceptions.RequestException as e:
logging.error(f"网络请求异常(视频ID:{video_id}):{str(e)}")
return {"success": False, "error_msg": f"网络异常:{str(e)}"}
except Exception as e:
logging.error(f"数据解析异常(视频ID:{video_id}):{str(e)}")
return {"success": False, "error_msg": f"解析异常:{str(e)}"}
def batch_get_video_detail(video_ids: list, **kwargs) -> list:
"""批量获取多个视频的详情"""
all_videos = []
for idx, vid in enumerate(video_ids):
logging.info(f"正在获取第{idx+1}个视频(ID:{vid})")
result = bilibili_item_get_video(vid,** kwargs)
if result["success"]:
all_videos.append(result["data"])
logging.info(f"视频{vid}获取成功")
else:
logging.error(f"视频{vid}获取失败:{result['error_msg']}")
# 控制调用频率(个人用户间隔12秒,企业用户间隔2秒)
time.sleep(12)
return all_videos
def save_video_detail(videos: list, save_path: str = CONFIG["save_path"]):
"""将视频详情保存为Excel"""
if not videos:
logging.warning("无视频数据可保存")
return
df = pd.DataFrame(videos)
# 增量保存,避免覆盖历史数据
try:
history_df = pd.read_excel(save_path, engine="openpyxl")
df = pd.concat([history_df, df], ignore_index=True).drop_duplicates(subset=["BV号"])
except FileNotFoundError:
pass
df.to_excel(save_path, index=False, engine="openpyxl")
logging.info(f"视频详情已保存至{save_path}(共{len(df)}条数据)")
# 封装好API供应商demo url=https://console.open.onebound.cn/console/?i=Lex
# 调用示例
if __name__ == "__main__":
# 单视频获取示例
single_video_result = bilibili_item_get_video(video_id="BV1xx411c7m9")
if single_video_result["success"]:
print("B站视频详情:")
for k, v in single_video_result["data"].items():
print(f"{k}:{v}")
else:
print(f"获取失败:{single_video_result['error_msg']}")
# 批量获取示例
# video_list = ["BV1xx411c7m9", "BV1yt411g7qK", "av123456"]
# batch_result = batch_get_video_detail(video_list)
# save_video_detail(batch_result)
四、调试与问题排查:快速解决对接异常
1. 优先用 Postman 调试(排除代码干扰)
- 构造请求 :新建 POST 请求,填写接口 URL,请求头设置
Content-Type: application/json; - 填写参数 :在请求体中输入
appkey、video_id、timestamp等必填项,按需补充need_page等可选参数; - 生成签名 :用在线 MD5 工具手动计算
sign,填入参数; - 发送请求:查看响应结果,验证接口可用性。
2. 高频问题排查表
| 问题现象 | 常见原因 | 解决方案 |
|---|---|---|
| 签名错误(401) | 1. 参数排序错误;2. secret不匹配;3. 时间戳过期;4. 中文未 URL 编码 |
1. 按 ASCII 升序排序参数;2. 核对secret与后台一致;3. 校准本地时间(误差≤5 分钟);4. 确保urlencode处理特殊字符 |
| 权限不足(403) | 1. 未申请item_get_video接口权限;2. 无分 P / 弹幕数据权限;3. 调用频率超限 |
1. 在开放平台确认接口已开通;2. 申请对应进阶权限;3. 增加请求间隔,降低调用频率 |
| 参数错误(400) | 1. video_id格式错误(非 BV/AV 号);2. need_page等参数非 0/1;3. 字段类型错误 |
1. 验证video_id有效性(B 站官网可查询);2. 确保参数为 0/1 整数;3. 检查参数类型(如timestamp为数字) |
| 无数据返回 | 1. 视频 ID 无效 / 已下架;2. 视频为隐私 / 版权受限内容;3. 接口未收录该视频 | 1. 核对视频 ID,在 B 站官网确认视频状态;2. 排除番剧等版权内容;3. 更换服务商或申请官方专项权限 |
| 字段缺失(如无播放链接) | 1. 无播放权限;2. 番剧等版权内容限制;3. 接口版本不支持 | 1. 申请 B 站站内播放跳转权限;2. 仅展示基础信息,引导用户跳转 B 站;3. 升级接口版本 |
五、进阶优化:生产级稳定性提升
1. 性能优化
- 异步并发请求 :批量获取多视频时,使用
aiohttp实现异步请求,控制并发数≤5(避免频率超限),效率比同步提升 4-6 倍; - 智能缓存策略 :用 Redis 缓存视频详情,缓存 key 为
bilibili_视频BV号,基础信息缓存 1 小时,互动数据缓存 5 分钟,减少重复请求; - 数据复用 :通过
item_get_video获取的cid(分 P 标识),可联动 B 站其他接口获取分 P 播放数据,避免重复调用。
2. 数据质量优化
- 数据去重 :按
BV号去重,避免同一视频多次入库; - 异常值过滤:过滤播放量为 0、状态为下架的无效数据;
- 字段补全:对缺失的分区 / 标签字段,通过视频标题关键词自动补充(如标题含 "原神" 则补充分区 "游戏 - 原神")。
3. 合规与安全
- 密钥管理 :生产环境将
appkey和secret存储在环境变量 / 配置中心(如 Nacos),禁止硬编码,定期轮换密钥; - 数据合规:视频数据仅用于合规业务,播放链接需跳转 B 站站内,二次创作需获得 UP 主授权,禁止盗播 / 商用;
- 日志审计:详细记录接口调用的参数、响应、错误信息,保留至少 7 天日志,便于合规审计与问题追溯。
六、扩展场景:接口联动与功能升级
- 联动
item_search_video接口 :先通过关键词搜索获取视频 ID 列表,再批量调用item_get_video获取详情,实现 "搜索 - 详情" 全链路; - 爆款视频分析模型 :结合
播放量、点赞率(点赞 / 播放)、投币率等指标,构建爆款评分公式,自动筛选优质内容; - 实时监控告警 :用
APScheduler定时调用接口,监控目标视频的播放量 / 评论数变化,触发舆情 / 爆款告警。