
简介Octoman微博备份工具是一款基于JavaScript开发的新浪微博备份Chrome浏览器扩展面向需要本地留存微博内容的个人用户可解决微博易被删除、难以批量归档的问题。资源包内含20个文件以js脚本、css样式、html页面及png图片为主分别对应扩展逻辑、界面样式、弹窗页面与图标资源整体仅134KB轻量易部署。已有337人学习下载。通过该扩展用户登录微博后即可选取目标博主以每500条微博为一个HTML文件完成备份所生成文件可用Chrome直接打开并支持通过“另存为”方式转为完全离线版本便于长期保存与查阅。对于需要留存个人微博、甚至处理异常账号内容的场景这套工具提供了简洁可行的本地备份方案。1. 微博备份不是收藏夹为什么你需要一个本地快照工具很多人以为点了收藏就等于留住了内容直到某个深夜发现收藏夹里一片灰——原博删除、账号注销、关键词被清理收藏列表变成一排失效链接。微博内容有很强的时效性和易失性这决定了靠平台侧的收藏、点赞、转发都不算真正拥有。基于 JavaScript 实现的 Octoman 微博备份工具做的就是把你自己的微博、评论、图片、视频链接从网页端接口拉下来落成本地 JSON、图片文件和可检索的索引。适合需要长期留存自己发言记录、做内容资产沉淀或者想对某段历史做完整快照的从业者。它不是爬全网数据的重型采集器而是一个针对当前账号维度、按时间线增量导出的轻量工具。这篇笔记围绕它完整拆一遍——数据从哪来、怎么落地、参数怎么设、哪些坑是绕不过去的。2. 从抓包到存储Octoman 的备份链路与数据落盘设计2.1 微博数据接口的常见形态与抓取边界浏览器打开自己的微博主页按 F12 切到 Network 面板刷新页面后能看到一批 XHR 请求。Octoman 这类工具通常不会去模拟点击和滚动页面而是直接请求微博网页端的 ajax 接口最常见的是https://weibo.com/ajax/statuses/mymblog这类路径它返回当前用户发布微博的 JSON 数据字段里包含idstr、text、created_at、pic_ids、url_struct等信息。抓取边界在于接口只返回“当前登录用户在网页端能看到的数据”。你去抓另一个人的主页大概率会遇到权限校验或者返回空列表抓自己已设置仅粉丝可见的内容也会受限。Octoman 的设计思路是“先满足本人账号备份”而不是做一个万能采集器。它通过携带 Cookie 请求接口把返回的 JSON 原样落盘再抽取出纯文本、图片链接、视频链接做二次整理。实际操作中接口的since_id或max_id参数用来翻页。第一页返回的 JSON 里通常会带since_id把它拿下来拼进下一次请求持续循环直到返回的微博列表为空就是全量抓完了。2.2 备份数据的本地组织结构JSON、图片与文本分离Octoman 的落盘目录结构值得直接参考。根目录下通常分为raw、assets、index三个子目录含义分别是原始 JSON、二进制图片文件、可读性更好的索引文件。每一次运行备份raw目录里按当天日期生成一个文件夹保存该次请求拿到的原始响应assets目录按微博 id 建立子目录存放该微博下的图片文件index目录则存放经过清洗后的 Markdown 或 HTML 文件方便人直接阅读。我一般会在配置里指定backupDir为绝对路径避免相对路径在不同系统下翻车。一个典型的目录结构长得像下面这样backupDir ├── raw/2025-04-10/xxx.json ├── assets/WB001/001.jpg ├── assets/WB001/002.jpg └── index/2025-04-10.md这种 JSON、图片、索引分离的结构有实际好处原始 JSON 是黑匣子级别的保底数据就算后续索引生成逻辑写错了还能重新解析 raw 文件找回内容图片单独存放则方便做对象存储迁移或本地相册归档。index目录下的 Markdown 文件可以直接被 Obsidian、Typora 这类工具打开搜索和阅读体验远好于直接翻 JSON。2.3 增量备份与去重不把时间浪费在已备份的内容上第一次全量备份很顺利问题出在第二次跑的时候——如果每次都把全部微博重新下载图片资源和接口请求量都会成倍浪费。Octoman 的去重逻辑通常是依赖微博 id 来做的每条微博有全局唯一的idstr本地已经存在的 id 就跳过只抓上次备份之后新增的内容。这个去重策略有个隐含前提本地必须已经保存了 id 列表。所以我建议把备份产物的索引文件当作“数据库”来看待不要随便删。增量备份时会先扫描index目录下已有的 id 集合再和接口返回的第一页数据比对找到最大 id 或最早时间点作为断点参考。断点续传也是这一层要考虑的事。如果备份到一半网络断了重启后 Octoman 会重新从第一页开始请求但已经落盘的图片不会重复下载因为本地文件系统里已经有对应 id 的文件了。这个设计比较朴素但胜在可靠——以文件是否存在作为是否下载过的判断依据不做额外的状态记录文件反而减少了状态不一致的问题。3. 把备份跑起来环境初始化、参数配置与首次全量导出3.1 依赖准备JavaScript 运行时环境与项目初始化Octoman 是基于 JavaScript 写的所以第一步是准备 Node.js 运行环境。建议使用 Node 16 以上的版本因为代码里可能用到了fetch、AbortController这些较新的 API老版本的 Node 不内置这些能力跑起来会报fetch is not defined。检查环境用下面两条命令node -v npm -v输出里如果版本号低于预期建议先去官网装 LTS 版本。项目初始化的过程是把 Octoman 的源码包解压到目标目录然后执行依赖安装cd octoman-weibo-backup npm install这里的npm install会读取package.json里的依赖列表把需要的库装到node_modules里。常见依赖包括axios网络请求、cheerioHTML 解析、commander命令行参数处理等。装完之后可以看下package.json里的scripts字段确认启动命令是npm run start还是node src/index.js不同版本的入口可能不一样。参数配置方面Octoman 通常会提供一个.env或config.js文件里面最关键的三项是 Cookie、备份目录路径、请求间隔时间。Cookie 从浏览器登录微博后复制注意要复制完整的 Cookie 字符串只复制半截的SINA开头字段会导致鉴权失败。3.2 首次全量备份登录态、间隔参数与导出格式准备工作做完后首次备份建议先跑一小段验证链路通不通不要一上来就全量。可以先在命令行里加一个--limit 10这样的参数限制只抓取最近 10 条微博node src/index.js --cookie 你的完整Cookie --limit 10跑通后再执行完整备份命令。注意控制请求频率微博接口对高频请求的封禁策略非常敏感。常见做法是在配置里设置interval为 800 到 1500 毫秒也就是每抓一页休息约一秒。短于 500 毫秒的请求节奏非常容易触发风控表现为接口突然返回1005或-100之类的错误码。如果备份的微博数量大、图片多建议把interval调大到 2000 毫秒时间换安全性完全值得。导出格式方面Octoman 默认输出 JSON 和 Markdown 两种。JSON 保留接口原始字段Markdown 则适合阅读和二次编辑。如果你后续打算把备份内容导入其他笔记软件建议保留 Markdown 格式它比 JSON 可读性好而且纯文本文件在做全文检索时相对友好。3.3 备份产物校验从目录结构反查完整性备份跑完后不要急着关终端先做一轮产物完整性检查。我会习惯性地在index目录下随机挑几天的 Markdown 文件核对里面的微博条数和页面显示的数量是否一致。更彻底的方式是统计raw目录下 JSON 文件的数量和日期覆盖范围find backupDir/raw -name *.json | wc -l find backupDir/raw -type d | sort | tail -5第一条命令统计所有原始响应文件的数量第二条查看最近生成的日期文件夹。如果日期文件夹能连续覆盖到当天说明翻页逻辑没有中途卡死如果某个日期缺失就要考虑是不是网络问题导致那一段的请求直接失败了。还有一个小技巧——检查assets目录下图片子目录的数量是否接近微博总数。图片是二进制文件下载过程中如果断了不会自动修复文件数量对不上基本就是漏图了。4. 微博备份避坑指南登录态失效、频率限制与缺失数据4.1 Cookie 过期导致批量失败现象是存档期突然出现大量 404 和空文件运行备份跑了一段时间某天突然发现输出里连续出现“请求失败”和-100错误之前一直好好的。打开浏览器登录微博发现网页版需要重新扫码登录——这就是会话过期了。微博网页端的 Cookie 有效期不定短则几天长则几周跟账号活跃度和风控状态有关。解决办法是做好 Cookie 失效的预警检测。Octoman 在请求接口后如果连续返回 3 次鉴权类错误码我会在脚本外面包一层日志监控检测到-100就停止任务并发送提醒。另外建议养成每周手动更新一次 Cookie 的习惯脚本每次启动前先读取最新 Cookie保持配置文件里的值始终是最近一次登录后复制的。4.2 接口频率限制现象是备份卡在某一页反复重试备份跑到一半日志显示同一页被请求了七八次每次返回的都是错误码。这就是接口频率触发限制的典型表现。微博网页端接口的限流阈值没有公开文档说明从血泪经验来看低于 500 毫秒的单次间隔基本必被限连续请求超过 2000 次也有概率被临时封禁。解决方向是两个一是调大interval到 1500 毫秒以上二是在请求失败时做指数退避重试第一次失败等 5 秒、第二次等 10 秒、第三次等 20 秒累计失败超过 5 次就暂停该轮备份。把这段逻辑写进配置文件让它自动执行不要手动盯着终端反复重跑。4.3 图片延迟加载导致空文件现象是 assets 目录里出现 0 字节图片微博的图片链接是懒加载的接口返回的pic_ids只给了图片 ID真实地址需要拼接https://wx1.sinaimg.cn/large/{id}.jpg这样的 URL 才能访问。有些时候接口返回的图片地址是https://wx1.sinaimg.cn/mw690/{id}.jpg但mw690是压缩图原图对应的后缀是large。如果脚本直接拿接口里的地址下载下载到一半服务端返回 302 跳转跳转链路断了就会落盘一个空文件。解决方法是下载图片时先检查响应头的Content-Length小于 1024 字节就认定为下载异常重新请求一次。另外在拼 URL 时使用large后缀而不是mw690能在多数情况下直接取到原图。如果原图下载失败但压缩图存在脚本应当降级保存压缩图而不是报错中断。4.4 转发微博的正文内容重复现象是搜索时同一段文字出现多次微博转发时原博的文字内容会出现在被转发微博的text字段里如果你既转发了原博又评论了一句话备份下来的内容可能包含两段重复的原文。这是微博接口返回数据的特性不是工具写错了。处理方式是解析text字段时单独提取“转发者自己的话”和“原博内容”两部分分开存到不同字段。Markdown 导出时用分隔线把两部分隔开这样检索时能精确命中你写的评论而不是每次搜到一堆重复的原文。还有一种情况是原博已被删除但转发记录还在此时retweeted_status字段为空直接展示“原博已删除”占位文本即可不要强行拼 URL。4.5 备份中途停机会产生“假完成”现象是时间线中间缺了一片内容有一次备份跑到一半笔记本没电关机了重启后继续跑看到日志显示“备份完成”但翻index目录发现中间某个月份的记录整段缺失。原因是该轮备份有断点续传逻辑但它判断“已备份”的条件是”存在it返回值对应的索引目录“而中途停止的会话里索引文件只写了一半没有写入最后一行结束标记。解决方法是每次备份完成后生成一个summary.json文件里面写入本轮开始时间、结束时间、抓取的微博总数、图片总数。下次备份开始前先检查summary.json是否存在且结束时间不为空如果发现上一轮没有结束标记就强制做一次全量校验而不是直接跳到增量流程。5. 从备份到检索用导出的 JSON 做本地内容过滤与二次加工5.1 把 JSON 转成结构化表格用脚本提取发布时间、正文与图片数原始 JSON 文件的字段非常冗长直接扔进 Excel 或者数据库之前要先做一轮字段抽取。常见做法是写一个 Node.js 脚本遍历raw目录里所有 JSON 文件提取每条微博的idstr、created_at、text_raw、pic_num、reposts_count、comments_count等核心字段输出成 CSV 或者 SQLite 表。示例脚本片段如下核心逻辑是递归读取所有 JSON 文件并平铺成对象数组const fs require(fs); const path require(path); function walkDir(dir) { const results []; for (const file of fs.readdirSync(dir)) { const full path.join(dir, file); if (fs.statSync(full).isDirectory()) { results.push(...walkDir(full)); } else if (file.endsWith(.json)) { results.push(full); } } return results; } function extractList(rawDir) { const list []; for (const file of walkDir(rawDir)) { const data JSON.parse(fs.readFileSync(file, utf8)); if (!data.data || !Array.isArray(data.data.list)) continue; for (const item of data.data.list) { list.push({ id: item.idstr, time: item.created_at, text: item.text_raw || item.text, pics: (item.pic_ids || []).length }); } } return list; } const rows extractList(backupDir/raw); console.log(共提取 ${rows.length} 条微博); fs.writeFileSync(backup.csv, rows.map(r ${r.id},${r.time},${r.text.replace(/,/g, )},${r.pics} ).join(\n));这段代码有两个关键设计walkDir递归遍历目录保证了多天备份的 JSON 文件都能被扫到text_raw优先于text因为text字段里往往混着 HTML 标签而text_raw是纯文本。如果你后续要做词频分析或情感分析建议直接用text_raw作为输入。5.2 本地全文搜索不依赖平台的轻量索引方案备份完成后最常用的操作是搜索——搜某年发过的某条内容、搜某个关键词和谁的互动。数据量不大的时候直接用 Node.js 的fs模块逐行扫描就是最朴素的方案。但如果内容有几千条每次搜索都全量遍历就会有点慢可以建一个简单的倒排索引。索引结构按关键词建 Map每个关键词对应一组微博 idconst idx new Map(); for (const item of rows) { const words item.text.split(/[\s。、]/); for (const w of words) { if (w.length 2) continue; if (!idx.has(w)) idx.set(w, new Set()); idx.get(w).add(item.id); } } function search(keyword) { const ids idx.get(keyword); if (!ids) return []; return rows.filter(r ids.has(r.id)); }这个实现里用 Set 去重避免同一单词在同一微博出现多次导致重复命中w.length 2过滤掉单字噪声减少索引体积。如果想更省事也可以把备份数据导入 SQLite用LIKE %关键词%查询效果差不多索引空间也小得多。对于个人备份场景我自己更偏向 SQLite 方案——不用维护内存索引查询语法也更通用。5.3 生成可读的 HTML 归档把备份变成能直接翻阅的存档站JSON 和 Markdown 适合程序处理但给不熟悉技术的人翻阅时HTML 归档体验更好。我可以写一个生成脚本把每条微博渲染成类似网页时间线的结构按月份分组微博卡片里放正文、图片缩略图、发布时间和转发评论数。这样的归档可以直接用浏览器打开也能扔到任意静态站点服务器上。生成 HTML 时的关键点是处理图片路径——备份下来的图片在assets目录HTML 文件如果放在别的位置引用图片时要算相对路径。常见做法是在 HTML 的img标签里写../assets/WBxxx/001.jpg保证整个归档目录移动后依然能显示图片。生成完以后用浏览器打开首页随机点几个月份检查图片是否正常加载。6. 让备份变成每周的习惯定时任务、资源占用与一条命令跑完备份工具能跑通只是第一步真正有价值的是把它变成长期习惯。我现在的做法是用系统自带的定时任务每周日凌晨三点跑一次增量备份命令是node src/index.js --cookie $(cat .cookie) --interval 1500。运行前先读取.cookie文件里的最新 Cookie避免把敏感字符串直接嵌到脚本里。日志输出重定向到backup.log这样每次运行后只需要检查日志末尾有没有“备份完成”字样。资源占用方面增量备份比全量备份轻得多。实测每周跑一次、每次新增几十条微博和十几张图片内存占用约 200MB时间在几分钟内完成全量备份首次跑会占用较多带宽和 CPU建议在夜间执行。另外一个值得做的动作是给backupDir目录做一次 git 初始化每次备份完成后自动提交一次这样内容有任何变化都有痕迹可追。还有个小技巧——拿备份数据做月度统计。每周备份后把 JSON 里的created_at字段按月聚合统计发博频率、图片数量、关键词趋势。这个方法让我对内容产出的规律有了特别直观的认识。从那以后我每次跑完备份都会顺手看一眼summary.json确认三条信息新增条数、图片下载成功率、是否有鉴权报错。这三项正常这一轮备份就是健康的。说到底备份工具的意义不是跑一次而是能长期稳定地跑下去希望这套思路能帮到你。本文还有配套的精品资源点击获取