1. 项目概述:一个浏览器书签工具,一键导出AI对话
作为一名长期与各类AI助手打交道的创作者和开发者,我经常遇到一个痛点:和ChatGPT、Claude、Gemini这些工具的对话记录,往往“困”在浏览器标签页里。想整理成文档分享给团队、存档备份,或者离线阅读,就得手动复制粘贴,格式还经常乱掉。特别是那些长篇的技术讨论或创作内容,导出过程繁琐得让人望而却步。
今天分享的这个工具,完美解决了这个问题。它是一个书签工具,我习惯叫它“一键导出小助手”。你只需要把它像保存普通网页书签一样,添加到浏览器的书签栏里。之后,无论你在使用Claude.ai、ChatGPT.com、Grok.com还是Gemini.google.com,只要点一下这个书签,它就能立刻把当前整个对话历史,连同侧边栏可能存在的代码片段、文件内容等“附加信息”,打包导出为一份整洁的PDF或纯文本文件。整个过程完全在你的浏览器本地运行,无需安装任何插件,你的对话数据不会上传到任何第三方服务器,安全性和便捷性都拉满了。
这个工具特别适合以下几类朋友:一是需要定期归档AI工作记录的知识工作者;二是希望将AI对话作为项目文档一部分的开发者;三是喜欢整理和分享精彩Prompt与回复的AI爱好者。无论你是技术小白还是资深极客,这个几乎零门槛的工具都能让你的AI工作流效率提升一个档次。
2. 核心原理与设计思路拆解
2.1 为什么是书签工具?
在决定技术方案时,作者选择了“书签工具”这条路径,而非浏览器插件或用户脚本,这是一个非常巧妙且务实的设计。背后的核心考量在于最大化兼容性与最小化使用门槛。
浏览器插件虽然功能强大,但需要用户主动去应用商店搜索、安装,并授予其访问特定网站的权限。这个过程本身就过滤掉了一部分怕麻烦的用户。更重要的是,插件需要针对不同浏览器(Chrome、Firefox、Edge等)进行适配和上架审核,维护成本较高。而用户脚本通常需要依赖Tampermonkey等脚本管理器,又多了一层依赖。
书签工具则完美规避了这些问题。它的本质是一段以javascript:开头的URL代码,保存在书签中。当点击时,浏览器会将其作为JavaScript在当前页面上下文中执行。这意味着:
- 零安装:只需拖拽或复制一次,永久使用。
- 全平台通用:只要浏览器支持
javascript:书签(几乎所有现代浏览器都支持),就能运行。 - 权限天然拥有:它运行在当前页面的上下文中,天然可以访问和操作该页面的DOM元素,无需额外申请权限。
- 更新相对简单:虽然用户需要手动更新书签链接,但维护者只需更新一段代码。
当然,书签工具也有其局限性,比如代码长度受浏览器URL长度限制,功能复杂度不能太高。但针对“提取页面特定内容并导出”这个核心需求,它无疑是“杀鸡用牛刀”般的高效方案。
2.2 智能识别与内容抓取逻辑
工具的核心智能体现在它能自动识别你当前访问的是哪个AI聊天网站,并采用对应的“抓取策略”。这是通过分析页面的URL主机名来实现的。
switch (location.hostname) { case 'claude.ai': // Claude的抓取策略 dialog = document.querySelector('div[data-test-render-count]').parentElement; events = dialog.querySelectorAll('div[data-testid="user-message"], div[data-test-render-count]>div>div>div.font-claude-response'); break; case 'chatgpt.com': // ChatGPT的抓取策略 dialog = document.querySelector('article').parentElement; events = dialog.querySelectorAll('div[data-message-author-role]'); // ... 其他策略 }每一套策略都包含几个关键步骤:
- 定位对话容器:首先找到包裹所有聊天消息的父级元素。例如,在ChatGPT中,它通过
document.querySelector('article').parentElement来定位。这个容器是后续所有操作的基准。 - 抓取对话回合:在容器内,使用特定的CSS选择器精准抓取用户和AI的每一条消息。这里的选择器设计得非常考究,通常是利用了这些网站UI组件中的
>events = [...events].filter(Boolean); extras = [...extras].filter(Boolean);这行代码非常精妙。
querySelectorAll返回的是一个NodeList,[...events]将其转化为真正的数组。.filter(Boolean)是一个简洁的写法,用于过滤掉数组中所有“假值”(如null,undefined),确保后续处理的都是有效的DOM元素。生成时间戳文件名:
let ts = new Date().toISOString().replace(/[-:T.]/g, '').slice(0, 14); // 示例输出:20240415123045 (年月日时分秒)这行代码生成了一个基于当前时间的文件名,避免了重复和手动命名。它获取ISO格式的时间字符串(如
2024-04-15T12:30:45.678Z),然后通过正则表达式移除所有分隔符,并取前14位,得到精确到秒的字符串,非常适合作为文件名。可搜索PDF的“魔术”样式:
let style = document.createElement('style'); style.textContent = `@media print{body>*{display:none!important}#${temp.id}{display:flex!important;flex-direction:column}}`;这是实现“仅打印对话内容”的关键。
@media print是CSS媒体查询,其中的样式只在打印时生效。body>*{display:none!important}隐藏了<body>下的所有直接子元素(即整个原始页面)。#${temp.id}{display:flex!important}则让我们创建的临时容器显示出来,并用Flexbox布局保持内容垂直排列。!important用于覆盖页面原有样式,确保效果绝对生效。文本导出时的BOM字符:
new Blob(['\uFEFF', txt], {type: 'text/plain;charset=utf-8'})在创建文本文件的Blob时,代码在文本内容前添加了
\uFEFF(字节顺序标记)。这对于UTF-8编码的文本文件来说不是必须的,但它是一个好习惯,可以确保一些老旧的文本编辑器(如Windows记事本)能正确识别文件的UTF-8编码,避免中文等非ASCII字符显示为乱码。4.2 如何自定义与适配新网站
当遇到一个新的、不被支持的AI聊天网站,或者某个支持网站改版导致工具失效时,你可以尝试自己更新代码中的选择器。这需要一些基础的HTML和CSS知识。
步骤一:打开开发者工具在目标聊天网站,按F12打开浏览器开发者工具,切换到“元素”面板。
步骤二:定位对话元素
- 在页面上找到一条用户消息,右键点击它,选择“检查”。开发者工具会自动定位到对应的HTML元素。
- 观察这个元素的特征。寻找稳定的、有意义的属性,优先级如下:
>问题现象可能原因 解决方案 点击书签无任何反应 1. 书签代码复制不完整或格式错误。
2. 当前网站不支持(控制台可能有错误)。1. 重新创建书签,确保完整复制 javascript:开头的整段代码。
2. 打开浏览器开发者工具(F12)的“控制台”面板,点击书签,查看是否有红色错误信息。弹出提示“xxx.com is not supported” 该网站不在工具的预设支持列表中。 目前仅支持Claude、ChatGPT、Gemini、Grok。如需支持其他网站,需手动修改代码添加选择器。 导出PDF时,浏览器打印对话框未弹出,或PDF内容为空/只有一部分 1. 网站的CSP策略阻止了打印模拟。
2. 页面DOM结构已更新,选择器失效。1. 下次导出时,在第二个确认框选择“取消”,使用不可搜索PDF方案。
2. 等待工具作者更新代码,或尝试自行分析页面结构更新选择器。导出的文本或PDF格式混乱,包含大量无关元素 CSS选择器抓取到了过多或错误的元素。 同样是页面结构更新导致。需要更新对应网站的选择器逻辑。 选择“不可搜索PDF”后,长时间无反应或失败 网络问题,无法从Cloudflare CDN加载 html2pdf.js库。检查网络连接。如果网络环境特殊,可以考虑将 html2pdf.js库下载到本地,并修改代码指向本地文件(需要一定的技术能力)。导出的文件名是乱码 浏览器或系统对时间戳格式的处理问题。 此问题较少见。可以修改代码中的文件名生成逻辑,例如使用 new Date().toLocaleString('zh-CN').replace(/[/:\\s]/g, '-')生成中文格式的日期。5.2 性能优化与使用技巧
- 对话长度限制:对于极其漫长的对话(例如超过数万字的聊天记录),一次性克隆所有DOM节点并处理可能会导致浏览器短暂卡顿甚至内存不足。虽然工具本身没有设置硬性限制,但建议对于超长对话,可以分次导出,或先使用文本导出功能(负担较小)。
- 清理浏览器缓存:如果你修改了书签代码,但点击后似乎还是旧版本的行为,可能是浏览器缓存了旧的书签URL。尝试清除浏览器缓存,或使用“无痕模式”测试。
- 书签栏管理:给这个书签起一个醒目的名字或添加一个特殊的表情符号图标(如 📄),方便在众多书签中快速找到。大部分浏览器允许你右键编辑书签时,上传一个自定义图标。
- 备用方案:对于非常重要的对话,除了使用此工具导出,建议同时使用各个AI平台自带的对话历史记录和分享功能(如果有)作为备份。不要完全依赖单一工具。
5.3 潜在风险与长期维护
没有任何工具是完美的,了解其边界和风险能让你用得更加安心。
1. 失效风险:这是基于前端选择器的工具最大的风险。AI产品的UI迭代速度很快,一个前端的类名、ID或结构改动,就可能导致工具“失明”。应对策略是:
- 关注项目仓库:在GitHub上Star或Watch原项目,以便及时收到更新通知。
- 社区互助:如果发现工具失效,可以到项目的GitHub Issues页面查看是否已有其他人报告,或者自己提交问题。
- 学习基础排查:掌握前面提到的“使用开发者工具定位元素”的方法,在紧急时可以尝试自行临时修复。
2. 功能局限性:
- 动态内容:如果聊天内容中包含需要滚动才能完全显示的代码块、或通过懒加载的图片,工具抓取的可能是未完全展开的状态。导出前最好手动滚动确保所有内容已加载。
- 格式丢失:文本导出模式会丢失所有的富文本格式(加粗、代码高亮、列表等)。PDF模式能较好地保留视觉格式。
- 非公开对话:工具无法导出需要滚动加载的、过于久远的历史对话。它只能抓取当前已加载在页面DOM中的内容。
3. 关于开源与信任:使用任何开源工具都基于一种信任。虽然代码可审,但如果你是从第三方文章而非官方仓库获取的代码,存在被篡改的微小风险。最安全的方式是从项目的官方GitHub仓库复制原始代码。对于极度敏感的商业或隐私对话,在采用任何自动化工具前,评估其代码是必要的步骤。
这个书签工具代表了一种轻巧、实用且尊重用户隐私的技术哲学。它不试图做一个大而全的平台,而是精准地解决一个高频痛点。通过将复杂的功能封装进一个简单的书签,它降低了技术使用的门槛,让效率提升变得触手可及。在我自己的使用中,它已经成为了我AI工作流中不可或缺的一环,将我从繁琐的复制粘贴中彻底解放出来。