哔哩哔哩 item_search_video - 根据关键词获取视频列表接口对接全攻略:从入门到精通

哔哩哔哩(B 站)的 item_search_video 接口是通过关键词批量检索平台视频列表的核心工具,支持按分区、发布时间、播放量、UP 主类型等多维度筛选,返回视频基础信息、互动数据、UP 主信息等关键内容。该接口广泛适用于内容聚合平台搭建、视频选题调研、行业数据分析、舆情监测等场景。

本攻略从接口认知、前置准备、实操对接、调试优化到合规上线,提供结构化的全流程指导,兼顾入门易用性与生产级稳定性,助力开发者高效完成对接。

一、接口核心认知:功能与适配场景

1. 接口定位与核心价值

  • 核心功能 :输入搜索关键词(支持多关键词组合),筛选 B 站全品类视频(番剧、UP 主自制、直播回放等),支持分区过滤、时间范围筛选、排序规则自定义,返回分页视频列表;可联动 item_get_video 接口获取单视频精细化详情。
  • B 站平台特性
    • 数据覆盖:收录 B 站 90% 以上公开视频,涵盖游戏、知识、生活、娱乐等 30 + 分区,新视频收录延迟 5-10 分钟;
    • 专属筛选维度 :支持按分区(如游戏 - 原神)、UP 主认证类型(个人 / 企业 / 官方)、视频类型(原创 / 转载) 筛选,适配精细化检索需求;
    • 互动数据前置:搜索结果直接返回播放量、点赞数、弹幕数等核心互动指标,无需二次调用;
    • 多关键词逻辑 :支持空格分隔(AND 逻辑,同时含多个关键词)、竖线 | 分隔(OR 逻辑,含任一关键词)。
  • 典型应用场景
    1. 内容聚合工具:搭建垂直领域视频平台(如 "Python 教程""美食探店" 专区),按关键词聚合 B 站相关视频;
    2. 选题调研:UP 主通过关键词检索,分析同类视频的热度、标签、互动数据,辅助确定创作方向;
    3. 行业数据分析:按行业关键词(如 "新能源汽车评测")采集视频数据,统计分区热度、用户偏好;
    4. 舆情监测:追踪品牌 / 事件关键词相关视频,实时监控播放量、评论数变化,掌握舆论走向。

2. 核心参数与返回字段

(1)请求参数(必填 + 可选,按优先级排序)
参数名称 类型 是否必填 说明 应用示例
appkey string 接口调用密钥,由 B 站开放平台 / 合规服务商分配 bilibili_abc123
secret string 签名密钥,用于请求合法性校验(不可泄露) bilibili_def456
keyword string 搜索关键词,支持多关键词组合(AND 用空格,OR 用 ` `) Python教程 零基础、` 旅行 vlog 美食探店 `
category string 视频分区筛选,值为分区英文名(需参考 B 站分区字典) game(游戏)、knowledge(知识)、life(生活)
time_range string 发布时间范围,默认all(全部) 1day(1 天内)、7days(7 天内)、30days(30 天内)、custom(自定义,需配合 start/end_date)
start_date string 自定义开始日期(time_range=custom 时必填),格式YYYY-MM-DD 2025-01-01
end_date string 自定义结束日期(time_range=custom 时必填),格式YYYY-MM-DD 2025-12-31
sort_type string 排序方式,默认relevance(相关度优先) play(播放量倒序)、pubtime(发布时间倒序)、like(点赞数倒序)、danmaku(弹幕数倒序)
up_type string UP 主认证类型,默认all(全部) personal(个人认证)、enterprise(企业认证)、official(官方认证)
copyright int 版权类型,默认0(全部) 1(原创)、2(转载)
page_no int 页码,默认1,最大支持100 1510
page_size int 每页视频数,默认20,最大支持50 203050
timestamp long 请求时间戳(毫秒级,有效期 5 分钟,避免重复请求) 1735689600000
sign string 签名值(按 B 站规则生成,核心校验项) 32 位 MD5 大写串

注意事项

  1. 分区参数category需与 B 站官方分区英文名一致,可通过服务商文档获取分区字典;
  2. 时间范围优先级:custom模式下,start_dateend_date必须同时传入,且时间跨度不超过 1 年;
  3. 排序方式play对应的是近 30 天播放量,非累计播放量,适配爆款视频筛选。
(2)返回核心字段(按业务场景分类)
字段分类 核心字段 说明
视频基础信息 bvid 视频 BV 号(对外唯一标识)
title 视频标题(含分区前缀、营销文案)
cover_url 视频封面图 URL(高清)
duration 视频时长(秒)
pubdate 发布时间(时间戳 / 格式化字符串)
category 视频分区(如 "游戏 - 原神")
tags 视频标签列表(如 "Python""教程""零基础")
copyright 版权类型(1 = 原创,2 = 转载)
state 视频状态(0 = 正常,-1 = 审核中,-2 = 已下架)
互动数据 view 近 30 天播放量
like 点赞数
danmaku 弹幕数
favorite 收藏数
coin 投币数
share 转发数
UP 主信息 up_id UP 主 ID
up_name UP 主昵称
up_avatar UP 主头像 URL
up_type UP 主认证类型
up_fans UP 主粉丝数(部分接口需企业权限)
分页信息 total 关键词匹配视频总数
page_no 当前页码
page_total 总页码

3. 接口限制与注意事项

  • 调用频率限制

    账号类型 调用频率 适用场景
    个人开发者 5 次 / 分钟 个人选题调研、小型数据分析
    企业开发者 30 次 / 分钟 商业内容聚合、舆情监测系统
  • 数据缓存规则 :搜索结果缓存 30 分钟,热门关键词(如 "原神""演唱会")缓存缩短至 10 分钟;企业用户可申请refresh=1强制刷新(需额外权限);

  • 内容限制:已下架 / 违规视频、隐私视频(仅粉丝可见)、未过审视频不会返回;番剧等版权内容仅返回基础信息,无播放链接;

  • 合规要求:禁止通过接口批量抓取视频源文件,搜索结果需标注 "数据来源:哔哩哔哩",二次传播需遵守 B 站版权规则。

二、对接前准备:权限与环境搭建

1. 获取接口权限(两种接入方式)

B 站 item_search_video 接口无公开免费接入渠道,需通过官方开放平台合规第三方服务商获取权限,具体对比如下:

接入方式 操作步骤 优缺点
B 站开放平台(官方) 1. 登录 B站开放平台;2. 完成账号认证(个人实名认证 / 企业营业执照认证);3. 创建应用,选择 "内容数据 / 视频搜索" 类目;4. 提交 item_search_video 接口申请,附业务用途说明;5. 审核通过后,在应用详情页获取 appkeysecret 优点:数据权威、字段完整、合规性强;缺点:审核严格(企业需提供业务证明)、周期长(3-7 个工作日)、部分字段需专项授权
第三方合规服务商 1. 选择口碑合规的服务商(如聚合数据、APISpace);2. 注册账号并完成实名认证;3. 购买 B 站视频搜索接口套餐;4. 在服务商后台获取 appkey 和接口调用地址 优点:接入快(10 分钟完成)、无需复杂资质、调试工具完善;缺点:部分进阶字段(如 UP 主粉丝数)需付费升级、调用次数有配额限制

风险提示:严禁使用非法爬虫接口,违反 B 站《用户协议》及《网络安全法》,存在账号封禁、法律追责风险。

2. 技术环境准备

(1)支持语言与协议
  • 协议:HTTPS(强制,保障数据传输安全);
  • 开发语言:支持 Python、Java、PHP、Go 等所有主流语言,推荐 Python(数据处理便捷,适配批量检索场景)。
(2)必备工具与依赖
工具类型 推荐工具 用途
调试工具 Postman 快速验证接口可用性,排除代码逻辑干扰
在线 MD5 工具 校验签名生成正确性
B 站分区字典查询工具 获取category参数的正确取值
开发依赖 requests(Python) 发送 HTTP 请求
hashlib(Python) 生成接口签名
pandas(Python) 批量整理视频列表数据
jsonpath-ng 快速解析嵌套 JSON 响应
辅助工具 Redis 缓存搜索结果,减少重复请求
logging 记录接口调用日志,便于问题追溯

三、实操步骤:接口对接全流程(Python 示例)

步骤 1:理解 B 站接口签名规则

B 站官方接口与第三方服务商接口均采用 MD5 加密签名 ,核心逻辑为参数排序 + 拼接密钥 + MD5 加密,具体步骤如下:

  1. 剔除参数中的 sign 字段(若存在);
  2. 将剩余参数按 参数名 ASCII 升序 排序;
  3. 拼接成 key1=value1&key2=value2&... 的字符串;
  4. 在字符串末尾拼接 &secret=你的secret
  5. 对拼接后的字符串进行 MD5 加密,生成 32 位大写字符串,即为 sign
签名示例

假设参数:appkey=bilibili_abc123keyword=Python教程sort_type=playtimestamp=1735689600000secret=bilibili_def456

  1. 排序后参数:appkeykeywordsort_typetimestamp
  2. 拼接字符串:appkey=bilibili_abc123&keyword=Python%E6%95%99%E7%A8%8B&sort_type=play×tamp=1735689600000&secret=bilibili_def456
  3. MD5 加密后得到 sign3A9F7C2D1E0B86453210FEDCBA789654

步骤 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
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_search_video.log"), logging.StreamHandler()]
)

# 接口配置(替换为自身的appkey、secret、接口地址)
CONFIG = {
    "appkey": "你的appkey",
    "secret": "你的secret",
    "api_url": "https://api.example.com/bilibili/item_search_video",  # 官方/服务商接口地址
    "save_path": "B站视频搜索列表.xlsx"
}

def generate_sign(params: dict, secret: str) -> str:
    """生成B站接口签名(MD5 32位大写)"""
    # 1. 移除sign字段
    params.pop("sign", None)
    # 2. 按参数名ASCII升序排序
    sorted_params = sorted(params.items(), key=lambda x: x[0])
    # 3. 拼接参数字符串并追加secret
    param_str = urlencode(sorted_params, encoding="utf-8") + f"&secret={secret}"
    # 4. MD5加密
    md5 = hashlib.md5()
    md5.update(param_str.encode("utf-8"))
    return md5.hexdigest().upper()

def standardize_video_data(raw_video: dict) -> dict:
    """标准化视频数据,统一输出格式"""
    # 格式化发布时间
    pubdate = raw_video.get("pubdate", 0)
    pubdate_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(pubdate)) if pubdate else ""
    # 格式化视频时长
    duration = raw_video.get("duration", 0)
    duration_str = f"{duration//60}:{duration%60:02d}"

    return {
        "搜索关键词": raw_video.get("keyword", ""),
        "BV号": raw_video.get("bvid", ""),
        "视频标题": raw_video.get("title", ""),
        "封面链接": raw_video.get("cover_url", ""),
        "视频时长": duration_str,
        "发布时间": pubdate_str,
        "视频分区": raw_video.get("category", ""),
        "视频标签": ",".join(raw_video.get("tags", [])) if raw_video.get("tags") else "",
        "版权类型": "原创" if raw_video.get("copyright", 2) == 1 else "转载",
        "视频状态": "正常" if raw_video.get("state", 0) == 0 else "已下架/违规",
        "近30天播放量": raw_video.get("view", 0),
        "点赞数": raw_video.get("like", 0),
        "弹幕数": raw_video.get("danmaku", 0),
        "收藏数": raw_video.get("favorite", 0),
        "投币数": raw_video.get("coin", 0),
        "转发数": raw_video.get("share", 0),
        "UP主ID": raw_video.get("up_id", ""),
        "UP主昵称": raw_video.get("up_name", ""),
        "UP主认证类型": raw_video.get("up_type", ""),
        "UP主粉丝数": raw_video.get("up_fans", 0),
        "请求时间": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
    }

def bilibili_item_search_video(
    keyword: str,
    category: str = None,
    time_range: str = "all",
    start_date: str = None,
    end_date: str = None,
    sort_type: str = "relevance",
    up_type: str = "all",
    copyright: int = 0,
    page_no: int = 1,
    page_size: int = 20
) -> dict:
    """
    调用B站item_search_video接口,获取关键词视频列表
    :param keyword: 搜索关键词
    :param category: 视频分区
    :param time_range: 发布时间范围
    :param start_date: 自定义开始日期
    :param end_date: 自定义结束日期
    :param sort_type: 排序方式
    :param up_type: UP主认证类型
    :param copyright: 版权类型
    :param page_no: 页码
    :param page_size: 每页条数
    :return: 标准化的视频列表数据
    """
    # 1. 校验参数合法性
    if time_range == "custom" and not (start_date and end_date):
        logging.error("time_range=custom时,start_date和end_date为必填参数")
        return {"success": False, "error_msg": "缺少自定义时间参数"}

    # 2. 构建基础参数
    params = {
        "appkey": CONFIG["appkey"],
        "keyword": keyword,
        "time_range": time_range,
        "sort_type": sort_type,
        "up_type": up_type,
        "copyright": copyright,
        "page_no": page_no,
        "page_size": page_size,
        "timestamp": int(time.time() * 1000)
    }

    # 3. 补充可选参数
    if category:
        params["category"] = category
    if time_range == "custom":
        params["start_date"] = start_date
        params["end_date"] = end_date

    # 4. 生成签名
    params["sign"] = generate_sign(params, CONFIG["secret"])

    try:
        # 5. 发送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()

        # 6. 解析响应结果
        if result.get("code") == 0 or result.get("status") == "success":
            raw_data = result.get("data", {})
            video_list = raw_data.get("item_list", [])
            total = raw_data.get("total", 0)
            page_total = raw_data.get("page_total", 1)

            # 标准化视频数据
            standard_videos = []
            for video in video_list:
                video["keyword"] = keyword  # 补充关键词字段
                standard_videos.append(standardize_video_data(video))

            return {
                "success": True,
                "data": standard_videos,
                "total": total,
                "page_no": page_no,
                "page_total": page_total,
                "error_msg": ""
            }
        else:
            error_msg = result.get("msg", result.get("message", "接口调用失败"))
            logging.error(f"接口返回错误(关键词:{keyword}):{error_msg}(code={result.get('code')})")
            return {"success": False, "error_msg": error_msg}
    except requests.exceptions.RequestException as e:
        logging.error(f"网络请求异常(关键词:{keyword}):{str(e)}")
        return {"success": False, "error_msg": f"网络异常:{str(e)}"}
    except Exception as e:
        logging.error(f"数据解析异常(关键词:{keyword}):{str(e)}")
        return {"success": False, "error_msg": f"解析异常:{str(e)}"}

def batch_get_video_list(
    keyword: str,
    max_page: int = 5,
    **kwargs
) -> list:
    """批量获取多页视频列表,控制调用频率"""
    all_videos = []
    page_no = 1
    while True:
        logging.info(f"正在获取关键词「{keyword}」第 {page_no} 页视频")
        result = bilibili_item_search_video(keyword=keyword, page_no=page_no, **kwargs)
        if not result["success"]:
            logging.error(f"第 {page_no} 页获取失败:{result['error_msg']}")
            break
        page_videos = result["data"]
        if not page_videos:
            logging.info(f"第 {page_no} 页无视频数据,批量获取结束")
            break
        all_videos.extend(page_videos)
        logging.info(f"第 {page_no} 页获取成功,新增 {len(page_videos)} 条数据(累计 {len(all_videos)} 条)")
        # 终止条件:达到最大页码或总页码
        if page_no >= max_page or page_no >= result["page_total"]:
            break
        page_no += 1
        # 控制频率(个人用户间隔12秒,企业用户间隔2秒)
        time.sleep(12)
    return all_videos

def save_video_list(videos: list, save_path: str = CONFIG["save_path"]):
    """将视频列表保存为Excel文件,支持增量去重"""
    if not videos:
        logging.warning("无视频数据可保存")
        return
    df = pd.DataFrame(videos)
    # 按BV号去重
    df = df.drop_duplicates(subset=["BV号"])
    # 增量保存
    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__":
    # 单页获取示例:搜索"Python教程 零基础",按播放量排序,知识分区,近30天
    single_page_result = bilibili_item_search_video(
        keyword="Python教程 零基础",
        category="knowledge",
        time_range="30days",
        sort_type="play",
        page_size=20
    )
    if single_page_result["success"]:
        print(f"获取到 {len(single_page_result['data'])} 条视频数据")
        for video in single_page_result["data"][:5]:  # 打印前5条
            print(f"标题:{video['视频标题']} | 播放量:{video['近30天播放量']} | UP主:{video['UP主昵称']}")
    else:
        print(f"单页获取失败:{single_page_result['error_msg']}")

    # 批量获取示例:获取前5页数据并保存
    # batch_videos = batch_get_video_list(
    #     keyword="Python教程 零基础",
    #     category="knowledge",
    #     time_range="30days",
    #     sort_type="play",
    #     max_page=5
    # )
    # save_video_list(batch_videos)

四、调试与问题排查:快速解决对接异常

1. 优先用 Postman 调试(排除代码逻辑干扰)

  1. 构造请求 :新建 POST 请求,填写接口 URL,请求头设置Content-Type: application/json
  2. 填写参数 :在请求体中输入appkeykeywordtimestamp等必填项,按需补充筛选参数;
  3. 生成签名 :用在线 MD5 工具手动计算sign,填入参数;
  4. 发送请求:查看响应结果,验证接口是否正常返回数据。

2. 高频问题排查表

问题现象 常见原因 解决方案
签名错误(401) 1. 参数排序错误;2. secret不匹配;3. 时间戳过期;4. 中文未 URL 编码 1. 按 ASCII 升序排序参数并打印验证;2. 核对secret与后台一致;3. 校准本地时间(误差≤5 分钟);4. 确保urlencode处理特殊字符
权限不足(403) 1. 未申请item_search_video接口权限;2. 普通账号使用企业字段(如 UP 主粉丝数);3. 调用频率超限 1. 在开放平台确认接口已开通;2. 移除企业专属参数或升级账号;3. 增加请求间隔,降低调用频率
参数错误(400) 1. category取值错误(非官方分区名);2. time_range=custom未传日期;3. sort_type取值非法 1. 查阅服务商文档获取正确分区字典;2. 补充start_dateend_date;3. 核对sort_type取值(参考参数表)
无视频数据返回 1. 关键词过于精准 / 无匹配视频;2. 筛选条件过于严格;3. 视频未被接口收录 1. 放宽关键词(如 "Python 零基础" 改为 "Python 教程");2. 移除分区 / 时间等筛选条件;3. 在 B 站官网搜索关键词,确认是否有相关视频
字段缺失(如无 UP 主粉丝数) 1. 账号无企业权限;2. 接口版本不支持;3. UP 主隐私设置隐藏粉丝数 1. 升级为企业账号或申请专项权限;2. 联系服务商升级接口版本;3. 忽略该字段,仅保留基础信息

五、进阶优化:生产级稳定性提升

1. 性能优化

  • 异步并发请求 :多关键词 / 多页码批量获取时,使用aiohttp实现异步请求,控制并发数≤5(避免频率超限),效率比同步提升 4-6 倍;
  • 智能缓存策略 :用 Redis 缓存关键词+筛选条件组合的搜索结果,缓存 key=bilibili_search_关键词_时间范围_分区,有效期 30 分钟;对无结果的关键词,缓存空结果(有效期 10 分钟),避免无效请求;
  • 分页智能停止 :获取第 1 页后,根据page_total计算总页码,仅请求有效页码,避免page_no超过总页码的无效请求。

2. 数据质量优化

  • 数据去重 :按BV号去重,避免同一视频多次入库;
  • 异常值过滤:过滤播放量为 0、状态为下架的无效数据;
  • 关键词扩展:结合 jieba 分词对核心关键词进行扩展(如 "Python 教程" 扩展为 "Python 零基础教程、Python 进阶教程"),提升搜索覆盖率。

3. 合规与安全

  • 密钥管理 :生产环境中,将appkeysecret存储在环境变量或配置中心(如 Nacos),禁止硬编码;定期轮换密钥(每 3 个月一次);
  • 数据合规:搜索结果仅用于合规业务,禁止商业化售卖;引用视频数据时标注来源,二次创作需获得 UP 主授权;
  • 日志审计:详细记录每次接口调用的参数、响应、错误信息,保留至少 7 天日志,便于合规审计与问题追溯。

六、扩展场景:接口联动与功能升级

  1. 联动 item_get_video 接口 :通过 item_search_video 获取bvid列表后,批量调用item_get_video获取视频分 P、字幕、播放链接等精细化详情;
  2. 爆款视频分析模型 :结合播放量点赞率(点赞 / 播放)、弹幕率等指标,构建爆款评分公式,自动筛选优质视频;
  3. 实时关键词监测 :使用APScheduler定时调用接口,监控目标关键词的视频新增量、播放量变化,触发舆情 / 爆款告警
相关推荐
会写代码的柯基犬13 小时前
DeepSeek vs Kimi vs Qwen —— AI 生成俄罗斯方块代码效果横评
人工智能·llm
Mintopia14 小时前
OpenClaw 是什么?为什么节后热度如此之高?
人工智能
爱可生开源社区14 小时前
DBA 的未来?八位行业先锋的年度圆桌讨论
人工智能·dba
叁两17 小时前
用opencode打造全自动公众号写作流水线,AI 代笔太香了!
前端·人工智能·agent
前端付豪17 小时前
LangChain记忆:通过Memory记住上次的对话细节
人工智能·python·langchain
strayCat2325517 小时前
Clawdbot 源码解读 7: 扩展机制
人工智能·开源
王鑫星17 小时前
SWE-bench 首次突破 80%:Claude Opus 4.5 发布,Anthropic 的野心不止于写代码
人工智能
lnix17 小时前
当“大龙虾”养在本地:我们离“反SaaS”的AI未来还有多远?
人工智能·aigc
泉城老铁17 小时前
Dify知识库如何实现多关键词AND检索?
人工智能