乐于分享
好东西不私藏

我用插件把豆包聊天记录自动存到了Obsidian

我用插件把豆包聊天记录自动存到了Obsidian
我平时跟豆包聊天的频率其实很高:写代码遇到问题问它,看书有想法跟它聊,健身计划也让它排。半年下来攒了一堆对话。

但有个问题一直让我不爽——聊天记录全锁在豆包里面。想看之前聊过什么,只能手动往上翻。豆包虽然也支持导出文本到本地,但聊天内容太长,重要的可能就那么一小段。

如何能够把我跟豆包之间的对话觉得有意思的部分自动存到 Obsidian,方便日后复盘和总结?

第一回合:直接读硬盘

豆包 PC 客户端是 Electron 做的,数据存在本地。我尝试去读取里面的内容,折腾了几个小时没啥进展,暂时放弃。

第二回合:远程调试连进去

Electron 本质就是 Chrome。Chrome 有远程调试协议(CDP),可以用 WebSocket 连进去执行 JavaScript。

关了豆包进程,加 --remote-debugging-port=9222 重启。写了个 Node.js 脚本用 WebSocket 连上,调用 Runtime.evaluate 执行任意 JS。

连上了,成功读到了对话列表:

  • 健康小助手
  • VBA批量插入图片
  • OpenClaw学习指南
  • 40岁男性囚徒健身入门计划

看到这些熟悉的标题躺在数据库里,当时觉得稳了。

但再往下挖,发现只能读到元信息(标题、ID、创建时间),每条消息的具体内容根本不在这个库里。

第三回合:浏览器扩展

不碰本地数据了,换个思路。

我 Obsidian 上装了 Local REST API 插件,它可以在本地开 HTTP 服务让外部程序读写笔记。

那方案就变成了:写一个浏览器扩展,注入到豆包网页版,实时捕获对话内容,通过 REST API 写入 Obsidian。

写脚本的过程

第一步:摸清豆包的页面结构

豆包网页版的前端代码是打包压缩过的,class 名都是动态生成的一串乱码。没法靠猜。

打开 F12 控制台,几行 JavaScript 搞定:

// 看页面加载完整没document.querySelectorAll('div').length// → 666// 用关键词缩小范围document.querySelectorAll('[class*="message"]').length// 拿到真实的 class 名document.querySelectorAll('[class*="message"]')[0]?.className// → "conversation-page-message-host w-full flex-shrink-0 ..."// 确认内容在里面document.querySelector('[class*="conversation-page-message-host"]')?.innerText// 看子元素结构document.querySelector('[class*="conversation-page-message-host"] > div')?.className// → "message-list-zLoNs1"

[class*="xxx"] 是 CSS 的属性选择器,只要 class 里包含这个关键词就算匹配。不用管那串随机后缀。

完整 DOM 结构很快摸清楚了:

conversation-page-message-host  └── message-list-zLoNs1        ├── div(用户消息)        ├── div(AI 回复)        └── ...

第二步:封装消息捕获

豆包网页的结构可能在更新后变化,所以我没有写死选择器,而是做了多层兜底:

const selectors = [  '[class*="message-content"]',  '[class*="MessageContent"]',  '[class*="msg-content"]',  '.chat-message-content',  '[class*="chat-bubble"]',];

逐个尝试,第一个命中的就用它。如果全都没命中,fallback 到 p, div.markdown 这类更通用的选择器。

捕获到的消息交替标记角色:单数条为 user,双数条为 assistant。同时基于前 80 个字符做去重,防止重复捕获。

第三步:对接 Obsidian API

Local REST API v4 的接口很简单,Put 文件内容到指定路径就行:

// PUT 写入文件,如果文件不存在会自动创建PUT /vault/豆包对话/2026-06-03-标题.md// 如果文件不存在 PUT 返回 404,改成 POST 创建POST /vault/豆包对话/2026-06-03-标题.md

每条消息转成结构化 Markdown:

# 标题> 同步时间:2026-06-03 14:30:00 | 共 12 条消息---**我**(14:20:00)帮我看看这段代码哪里有问题...---**豆包**(14:20:05)看起来是异步操作没有 await...---

第四步:配置引导

首次安装脚本,豆包页面右上角会自动弹出一个配置对话框,引导用户完成两步:

  1. 在 Obsidian 中安装 Local REST API 插件
  2. 从插件设置里复制 API Token 粘贴进来Token通过插件的持久化到浏览器的本地存储,下次打开不用重新输入。

控制面板

豆包页面右上角悬浮了三个按钮:

按钮
功能
颜色
💾
立即保存当前对话到 Obsidian
蓝色
📂
从 Obsidian 加载历史对话
绿色
重新设置 API Token
灰色

每次操作都有反馈。

成品长这个样子: