- 开发工具
- CLI
- 人工智能
- AI 应用
- 浏览器控制
- GUI 自动化
【免费下载链接】OpenCLI
Make Any Website into CLI & Use your logged-in browser by AI agent.
本篇技术指南以 OpenCLI 仓库中skills/opencli-adapter-author/references/site-memory/bilibili.md这份站点记忆文档为核心骨架,结合仓库内clis/bilibili/下 30+ 个真实 adapter 与共享工具源码,系统讲解为 bilibili 编写 OpenCLI adapter 所需的全部站点知识:域名划分、默认鉴权策略、wbi 签名机制、常用 endpoint、字段约定与九类高频陷阱。读完本文,你可以掌握如何复用utils.js快速写出可验证、抗风控的 B 站 adapter,并理解opencli-adapter-authorskill 中"站点记忆"这一层知识资产的组织方式。
一、这份文档在 OpenCLI 中的作用
在 OpenCLI 的 adapter 编写技能opencli-adapter-author中,站点记忆(site memory)被设计为两层结构(见skills/opencli-adapter-author/references/site-memory.md):
- in-repo 种子:
skills/opencli-adapter-author/references/site-memory/<site>.md,是手工编写 + PR 审核进入仓库的公共知识,多 agent 共享的第一批起点。目前已铺设eastmoney / xueqiu / bilibili / tonghuashun四个站点。 - 本地工作目录:
~/.opencli/sites/<site>/,是 agent 每次跑 adapter 时自动累积的产物(endpoints.json/field-map.json/verify//fixtures//notes.md),不进 git、不进 PR。
bilibili.md就是 B 站这一站点在 in-repo 层的种子记忆。SKILL.md 的 Runbook 第 2 步明确要求:写 adapter 之前先读站点记忆,命中 endpoint 后不能直接跳去写代码,仍要跑 Step 5 endpoint 验证 + Step 7 字段抽查,因为 memory 可能过期或站点换版(verified_at超过 30 天视作过期,按冷启动重新侦察)。
该文档的固定结构(域名 → 默认鉴权 → 已知 endpoint → 字段 → 坑/陷阱 → 可参考的 adapter)正是所有站点记忆的统一 schema,本节文档是所有 B 站 adapter 开发的共同起点。
二、域名划分:六个域各司其职
B 站接口分散在多个子域名,写 adapter 前先明确请求落在哪个域,避免"接口 404"式的低级错误:
| 用途 | 域名 |
|---|---|
| 主 API | api.bilibili.com |
| 个人主页 / 空间 | space.bilibili.com |
| 登录 / 鉴权 | passport.bilibili.com |
| 动态 | t.bilibili.com/api.vc.bilibili.com |
| 直播 | api.live.bilibili.com |
从源码可以印证这一点:clis/bilibili/utils.js中的apiGet把baseUrl固定为https://api.bilibili.com,所有主站接口都拼在这个域下;而直播接口独立在api.live.bilibili.com(记忆文档第 9 条陷阱也专门提醒了这点)。t.bilibili.com则用于动态页面的展示 URL——clis/bilibili/dynamic.js在输出动态条目时会把id_str拼成https://t.bilibili.com/${item.id_str}作为可跳转链接。
三、默认鉴权策略:COOKIE + browser
B 站 adapter 的默认鉴权策略是:
Strategy.COOKIE + browser: true:复用浏览器已登录的 cookie,在页面上下文内发请求。- 核心 cookie:
SESSDATA(登录态)与bili_jct(CSRF token)。部分写接口要求请求头带Referer + csrf。 - 未登录也能调多数读接口,但带有 wbi 签名要求(下文详述)。
查看仓库中 B 站 adapter 的声明,几乎全部是strategy: Strategy.COOKIE,例如clis/bilibili/user-videos.js、clis/bilibili/search.js、clis/bilibili/comments.js、clis/bilibili/me.js、clis/bilibili/history.js等。其中clis/bilibili/hot.js是少数例外——它不声明 strategy,直接用 pipeline 形式在www.bilibili.com页面内 fetch 热门接口,说明公开无签名接口可以不走 COOKIE 策略。
写接口的 CSRF 处理在utils.js的apiPost中有完整实现:它在页面上下文中从document.cookie匹配bili_jct=([^;]+)取出 token,塞进 POST body 的csrf字段,并以application/x-www-form-urlencoded发送。值得注意的实现细节:B 站写接口可能返回 HTML 风控页(如 HTTP 412)而非 JSON,apiPost对此做了防护——先res.text()再尝试JSON.parse,解析失败则返回{ code: -1, message: "Non-JSON response (HTTP ...)" }的结构化错误,而不是让 JSON 解析直接崩溃。
此外utils.js还提供了getSelfUid(page):通过nav接口取data.mid作为当前登录用户 UID,拿不到就抛AuthRequiredError。clis/bilibili/me.js正是用它配合/x/space/wbi/acc/info返回当前账号的名称、等级、硬币、粉丝数等资料。
四、核心机制:wbi 签名
4.1 签名规则
wbi 签名是 B 站 adapter 开发中最重要的机制,记忆文档给出了三条铁律:
- 凡 URL 含
/wbi/的接口都要带w_rid + wts签名。 - 签名算法依赖每日轮换的
img_key / sub_key,从api.bilibili.com/x/web-interface/nav响应的wbi_img字段获取。 - 不要自己重新实现:
clis/bilibili/utils.js里的apiGet(page, path, { signed: true, params })已经封装好。
普通 cookie JSON 接口优先用page.fetchJson(url);站点级签名逻辑仍复用utils.js。
4.2 源码级实现拆解
clis/bilibili/utils.js完整实现了 wbi 签名链,逐段拆解如下:
① 取 key:getWbiKeys(page)在页面上下文 fetchnav接口,从data.wbi_img.img_url / sub_url中截取文件名主干作为imgKey / subKey(split('/').pop().split('.')[0])。
② 生成 mixin key:getMixinKey(imgKey, subKey)用内置的 64 项置换表MIXIN_KEY_ENC_TAB把imgKey + subKey重排,再截取前 32 个字符。这份置换表就硬编码在 utils.js 第 143-148 行。
③ 签名:wbiSign(page, params)计算当前秒级时间戳wts,将所有参数(含wts)按 key 排序,每个值去除!'()*四个字符,拼成 query 后对query + mixinKey做 MD5 得到w_rid。这里有一个极其隐蔽的坑已由源码注释点明:B 站 wbi 校验要求空格编码为%20而不是+(URLSearchParams 默认行为),因此代码里做了.replace(/\+/g, '%20')——否则签名不匹配会导致 CORS 拦截,报TypeError: Failed to fetch。
④ 发送:apiGet(page, path, opts)中opts.signed为真时先调用wbiSign对参数签名,再拼https://api.bilibili.com${path}?${qs}交给fetchJson在页面上下文以credentials: "include"请求。
4.3 缓存策略:不要每次请求都刷 nav
img_key / sub_key24 小时内有效,若每次请求都重新 fetchnav会被限频。记忆文档强调"utils.js 内部做了缓存"——写新 adapter 时直接复用即可,不要在业务代码里重复拉nav。
五、已知 endpoint 清单
记忆文档整理了 12 条最常用的 B 站接口,按用途分组如下:
基础 / 鉴权类
GET api.bilibili.com/x/web-interface/nav— 登录态 + 拿 wbi keyGET api.bilibili.com/x/space/acc/info?mid=<uid>— 用户资料
视频类
GET api.bilibili.com/x/space/wbi/arc/search?mid=<uid>— 用户视频(需 wbi 签)GET api.bilibili.com/x/web-interface/view?bvid=BV...— 视频详情
榜单类
GET api.bilibili.com/x/web-interface/popular?ps=20&pn=1— 热门GET api.bilibili.com/x/web-interface/ranking/v2?rid=0— 排行
互动类
GET api.bilibili.com/x/v2/reply/wbi/main?type=1&oid=<aid>&mode=3— 评论(需 wbi)GET api.bilibili.com/x/web-interface/search/all/v2?keyword=<q>— 综合搜索
用户数据类(需登录)
GET api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/space_history?host_uid=<uid>— 用户动态(新版走api.bilibili.com/x/polymer/web-dynamic/v1/feed/space)GET api.bilibili.com/x/v2/history/cursor— 观看历史(需登录)GET api.bilibili.com/x/v3/fav/folder/created/list-all— 收藏夹列表(需登录)
5.1 从源码看实际使用差异
对照仓库源码可以发现记忆文档与实际 adapter 之间有几个值得注意的对应关系:
- 搜索接口:
clis/bilibili/search.js实际用的是/x/web-interface/wbi/search/type(带search_type: video | bili_user参数、走 wbi 签名),并支持type参数在视频搜索与用户搜索间切换。这与文档列出的/x/web-interface/search/all/v2是同一体系的另一形态——文档是"已知 endpoint 索引",具体 adapter 会按需选择。 - 评论接口:
clis/bilibili/comments.js使用/x/v2/reply/main(顶层评论 + 置顶,wbi 签名)和/x/v2/reply/reply(某条评论下的楼中楼回复,参数root=<rpid>)。它还展示了 bvid → aid 的解析链路:先调/x/web-interface/view拿aid,因为 reply 系列接口的oid需要的是 aid 而非 bvid。 - 历史接口:
clis/bilibili/history.js实际调用/x/web-interface/history/cursor,与文档记录一致,且ps上限是 30(不是 50),并支持type: archive过滤。 - 收藏接口:
clis/bilibili/favorite.js先调/x/v3/fav/folder/created/list-all?up_mid=<uid>拿收藏夹列表,默认取第一个收藏夹的 id,再调/x/v3/fav/resource/list(ps上限 40)拉取具体内容。 - 动态接口换版:
clis/bilibili/dynamic.js已经使用新版/x/polymer/web-dynamic/v1/feed/all(当前登录用户的动态流),与文档"新接口走x/polymer/web-dynamic/v1/feed/space"的提示一致,老的dynamic_svr已废弃。
这些差异说明:站点记忆是索引不是权威,写 adapter 时必须回到源码或实际抓包确认 endpoint 形态。
六、字段约定
B 站接口字段基本人类可读,核心代号已在skills/opencli-adapter-author/references/field-conventions.md的 bilibili 节登记:
| 字段 | 含义 |
|---|---|
mid | 用户 UID |
aid / bvid | 视频 ID(av 号 / bv 号) |
cid | 视频分 P ID |
uname / upname | up 主昵称 |
view / danmaku / reply / favorite / coin / share / like | 各类计数 |
pubdate / ctime | 发布 / 创建时间(秒级 unix) |
注意mid与uid是同一回事(陷阱第 2 条):接口参数不统一,mid=居多,个别接口要求host_mid=。仓库中resolveUid(utils.js)统一了这一差异:纯数字输入直接当作 mid,非数字输入则走wbi/search/type(search_type: bili_user)按用户名搜索取第一个结果的mid,搜不到抛EmptyResultError。
时间字段统一是秒级 Unix 时间戳,adapter 输出前需自行格式化——例如user-videos.js用new Date(item.created * 1000).toISOString().slice(0, 10),comments.js用new Date(ctime * 1000).toISOString().slice(0, 16)。
七、坑 / 陷阱:九条高频踩坑记录
记忆文档的"坑 / 陷阱"节是整份文档最浓缩的实战价值所在,逐条展开如下:
wbi 签名缓存
img_key / sub_key:24 小时内有效,每次请求都重新 fetchnav会被限频。utils.js 内部已做缓存,直接复用apiGet({ signed: true })即可。mid和uid一回事:接口参数不统一,mid=居多,个别接口要host_mid=。写 adapter 前先确认目标接口的参数名。视频 ID 有两种:
aid(老数字 av 号)与bvid(BV1xxx 格式)。视频详情要用bvid;而评论等部分接口的oid需要aid,需要先经 view 接口做一次 bvid → aid 转换(见comments.js的实现)。ps=最大 50(popular / ranking):超过 50 需多发几页再拼接。仓库中user-videos.js用Math.min(Number(limit), 50)做上限钳制,history.js用 30、favorite.js用 40——各接口上限不一致,写前查证。动态接口换版:老的
dynamic_svr已废弃,新接口走x/polymer/web-dynamic/v1/feed/space,写新 adapter 直接用新接口。评论分页靠
next游标,不是页号。comments.js对楼中楼回复也是用root: <rpid>定位,而不是 page 参数。B 站限频
-352 风控:短时间高频调用会被拦截,adapter 层应加约 500ms 间隔。这是"验证能过但生产环境挂"的典型场景,批量抓取时务必控制节奏。搜索要先 "cold start":空 cookie 的 session 第一次搜索会返回 412,需要先访问首页拿到
buvid3cookie 再搜。这与hot.jspipeline 第一步先navigate: 'https://www.bilibili.com'的做法互相印证——在页面上下文 fetch 天然自带 cold-start 过程。直播接口在
api.live.bilibili.com,不在主 API 域。这与第二节的域名表一一对应。
7.1 补充源码层的额外防御
除文档九条外,utils.js还体现了两类值得复用的防御性设计:
- 错误路由:
requireOkPayload(payload, label)检查{ code, message, data }信封结构,code !== 0时按isAuthLikeBilibiliError判定——-101 / -111 / -403或 message 匹配csrf / 登录 / 账号 / 权限 / forbidden / permission / login的抛AuthRequiredError,其余抛CommandExecutionError,保证登录过期不会被误报为普通执行错误。 - 输入校验:
parsePageArg对--page选集序号做严格校验(缺省返回 null 不下钻;非正十进制整数抛ArgumentError);resolveBvid支持 BV 号、bilibili.com/video/BV...URL、以及b23.tv短链三种输入形态,短链解析带 4 秒超时。
八、可参考的 adapter 索引
记忆文档按功能列出了 B 站 adapter 的模板对照表。结合仓库中 30 个文件的实际分布,完整索引如下:
| 模板类型 | 参考文件 |
|---|---|
| 用户资料 / 视频列表 | clis/bilibili/user-videos.js/me.js |
| 视频详情 / 字幕 | clis/bilibili/download.js/subtitle.js |
| 评论 | clis/bilibili/comments.js |
| 搜索 | clis/bilibili/search.js |
| 热门 / 排行 | clis/bilibili/hot.js/ranking.js |
| 动态 | clis/bilibili/dynamic.js |
| 关注 | clis/bilibili/following.js |
| 收藏 | clis/bilibili/favorite.js |
| 观看历史 | clis/bilibili/history.js |
| 创作者数据 | clis/bilibili/creator-stats.js |
| 关系操作 | clis/bilibili/follow.js/unfollow.js/relation.js |
| 视频摘要 / 综合信息 | clis/bilibili/summary.js/video.js/feed.js |
通用工具:clis/bilibili/utils.js。新 adapter 第一行就应import { apiGet, fetchJson } from './utils.js',不要重写签名与请求逻辑。
8.1 两个典型 adapter 的写法拆解
user-videos.js(标准 COOKIE + wbi 读接口范式):声明site: 'bilibili', name: 'user-videos', strategy: Strategy.COOKIE,参数含 positional 的uid(支持 UID 或用户名)、limit、order(pubdate / click / stow)、page。func 内先resolveUid归一化用户,再apiGet('/x/space/wbi/arc/search', { params: { mid, pn, ps, order }, signed: true }),从payload.data.list.vlist映射出 rank / title / plays / likes / date / url 六列,与columns声明完全对齐。
hot.js(pipeline 范式,无需 wbi):不写 func,而是用 pipeline 声明navigate → evaluate(fetch popular) → map → limit。第一步先导航到www.bilibili.com完成 cold-start,然后在页面上下文直接 fetch/x/web-interface/popular?ps=...&pn=1,无需任何签名。这印证了记忆文档的判断——热门这类公开接口不必走 wbi,但要在页面上下文执行以携带会话。
九、写新 adapter 时的落地步骤
结合本记忆文档与opencli-adapter-author的 Runbook,为 B 站新增 adapter 的推荐路径是:
- 读记忆:先读本文档(in-repo 种子)与
~/.opencli/sites/bilibili/(本地累积)。命中 endpoint 后仍要跑 endpoint 验证 + 字段抽查。 - 定策略:B 站绝大多数接口走
Strategy.COOKIE + browser: true;纯公开榜单类可参考hot.js的 pipeline 写法。 - 复用 utils:
import { apiGet, fetchJson, resolveUid, getSelfUid } from './utils.js'。需要 wbi 的接口传signed: true;普通 cookie JSON 接口用fetchJson或page.fetchJson。 - 核对字段:对照
field-conventions.md的 bilibili 节,时间戳记得 ×1000 转 Date;注意mid / uid命名差异与aid / bvid的使用场景。 - 写 typed error:
code !== 0时交给requireOkPayload路由,登录态问题抛AuthRequiredError,空结果抛EmptyResultError,不要return []或塞 sentinel 行(详见skills/opencli-adapter-author/references/typed-errors.md)。 - 验证与回写:
opencli browser verify bilibili/<name>通过后用--write-fixture生成种子并手改patterns / notEmpty / rowCount;肉眼比对网页值无误后,把 endpoint / field-map / notes 回写~/.opencli/sites/bilibili/——记忆是每轮滚动的资产,越滚越厚。
十、与 skill 其他参考文件的配合关系
本记忆文档不是孤立的,它与opencli-adapter-author技能体系的其他参考文件形成闭环:
skills/opencli-adapter-author/references/site-memory.md:站点记忆两层结构总览,bilibili.md就是其中 in-repo 种子的实例。skills/opencli-adapter-author/references/field-conventions.md:字段代号解码表,bilibili 节即本文第六节内容的出处。skills/opencli-adapter-author/references/adapter-template.md:adapter 三段式写法(declaration / args / func)与 COOKIE 骨架。skills/opencli-adapter-author/references/typed-errors.md:5 类 typed error 的落点与反模式。skills/opencli-adapter-author/references/strategy-selection.md:为什么 COOKIE_API 优于 PAGE_FETCH/INTERCEPT 的契约模型与实测维护成本。
阅读顺序建议:先SKILL.md建立整体流程,再读本记忆文档快速进入 B 站上下文,写代码时回到adapter-template.md与utils.js源码对照。
综上,bilibili.md虽是一份篇幅有限的"站点记忆"卡片,但浓缩了 B 站 adapter 开发最关键的域名、鉴权、签名、接口与陷阱知识;结合仓库源码后,它足以支撑从零写出一条健壮的 B 站 adapter。对后续 agent 而言,这份记忆的增量价值在于:先查记忆、再验 endpoint、后写 adapter、最后回写记忆——这是 OpenCLI 站点适配器生态能持续滚动的根本机制。
- 开发工具
- CLI
- 人工智能
- AI 应用
- 浏览器控制
- GUI 自动化
【免费下载链接】OpenCLI
Make Any Website into CLI & Use your logged-in browser by AI agent.
相关推荐
5 分钟上手 ShareX:截图、录屏、分享一次做完
5 分钟上手 ShareX:截图、录屏、分享一次做完 写周报时被同事要一张"手机号打码的截图",顺手还要存一份长文档整页图。Windows 自带截图拼不出这个效
开发工具CLI人工智能AI 应用浏览器控制GUI 自动化OpenCLI 同花顺(ths)适配器开发指南:域名、鉴权、Endpoint 与避坑全解
OpenCLI 同花顺(ths)适配器开发指南:域名、鉴权、Endpoint 与避坑全解 导读 本文以 skills/opencli adapter autho
开发工具CLI人工智能AI 应用浏览器控制GUI 自动化时光倒流:用Bilibili-Old重拾B站经典记忆
还记得那个界面简洁、弹幕纯粹的B站吗?当新版界面不断迭代,许多老用户开始怀念那个充满情怀的经典版本。今天,让我们一起探索如何通过Bilibili Old项目,让
前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考