百度脑图将于2026年3月31日正式停服,核心是长期无商业变现、资源投入停滞、功能与生态掉队、战略优先级低,最终被“断舍离”。
但是奇怪的是现在还没停服,但估计是快了,应该是给我们留存保留数据的时间。
在百度脑图上有数据的朋友可以借助这个油猴脚本把自己账号上的脑图数据下载下来,转向使用开源的百度脑图(https://github.com/NaoTu/DesktopNaotu)继续使用。
依旧是使用油猴脚本,在AI的帮助下做了这个脚本。
安装链接:
https://greasyfork.org/zh-CN/scripts/574394-%E7%99%BE%E5%BA%A6%E8%84%91%E5%9B%BE%E6%89%B9%E9%87%8F%E5%AF%BC%E5%87%BA-km-zip
AI查毒:
https://www.doubao.com/thread/wad340797b7f572c9这是效果图:

[JavaScript]
纯文本查看 复制代码// ==UserScript==//
@name 百度脑图批量导出(.km + ZIP)//
@namespace https://naotu.baidu.com///
@version 2.3.3// @description 在百度脑图主页添加【批量导出】按钮,支持导出所有文件及文件夹内的文件,输出为 .km 格式,最终打包成 ZIP 压缩包下载。//
@AuThor 帅气的小莲//
@match https://naotu.baidu.com/home*// @match
http://naotu.baidu.com/home*//
@grant none// @require
https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js// ==/UserScript==(function () { 'use strict'; console.log('[脑图导出] 脚本启动,JSZip 是否可用:', typeof JSZip !== 'undefined'); // ─── 样式 ─────────────────────────────────────────────────────────────────── const styleEl = document.createElement('style'); styleEl.textContent = ` #nm-export-btn { position: fixed; bottom: 32px; right: 32px; z-index: 99999; padding: 12px 22px; background: linear-gradient(135deg, #3b7de8, #1a56c4); color: #fff; font-size: 14px; font-weight: bold; border: none; border-radius: 28px; cursor: pointer; box-shadow: 0 4px 18px rgba(59,125,232,0.45); transition: all 0.2s ease; user-select: none; } #nm-export-btn:hover { background: linear-gradient(135deg, #4e8ef7, #2460d6); box-shadow: 0 6px 24px rgba(59,125,232,0.6); transform: translateY(-2px); } #nm-export-btn:disabled { background: #999; cursor: not-allowed; box-shadow: none; transform: none; } #nm-export-panel { position: fixed; bottom: 90px; right: 32px; z-index: 99999; width: 360px; background: #fff; border-radius: 14px; box-shadow: 0 8px 40px rgba(0,0,0,0.18); overflow: hidden; display: none; font-size: 13px; } #nm-export-panel .nm-panel-header { background: linear-gradient(135deg, #3b7de8, #1a56c4); color: #fff; padding: 12px 18px; font-weight: bold; font-size: 14px; display: flex; justify-content: space-between; align-items: center; } #nm-export-panel .nm-panel-header span.nm-close { cursor: pointer; font-size: 18px; line-height: 1; opacity: 0.8; } #nm-export-panel .nm-panel-header span.nm-close:hover { opacity: 1; } #nm-export-panel .nm-panel-body { padding: 14px 18px; } #nm-export-panel .nm-log { background: #f5f7fb; border-radius: 8px; padding: 10px 12px; max-height: 220px; overflow-y: auto; font-family: monospace; font-size: 12px; color: #333; line-height: 1.6; word-break: break-all; } #nm-export-panel .nm-log .nm-ok { color: #22a355; } #nm-export-panel .nm-log .nm-warn { color: #e07c00; } #nm-export-panel .nm-log .nm-err { color: #d32f2f; } #nm-export-panel .nm-progress-bar-wrap { margin-top: 10px; background: #e8edf5; border-radius: 999px; overflow: hidden; height: 8px; } #nm-export-panel .nm-progress-bar { height: 100%; width: 0%; background: linear-gradient(90deg, #3b7de8, #7ab4ff); border-radius: 999px; transition: width 0.25s ease; } #nm-export-panel .nm-phase-label { margin-top: 6px; font-size: 11px; color: #3b7de8; font-weight: bold; } #nm-export-panel .nm-progress-text { float: right; margin-top: -15px; color: #666; font-size: 11px; } `; document.head.appendChild(styleEl); // ─── UI ───────────────────────────────────────────────────────────────────── const btn = document.createElement('button'); btn.id = 'nm-export-btn'; btn.textContent = '📦 批量导出'; document.body.appendChild(btn); const panel = document.createElement('div'); panel.id = 'nm-export-panel'; panel.innerHTML = ` 📦 批量导出进度 ✕
等待开始…
0 / 0
`; document.body.appendChild(panel); panel.querySelector('.nm-close').addEventListener('click', () => { panel.style.display = 'none'; }); // ─── 工具 ────────────────────────────────────────────────────────────────── const logBox = document.getElementById('nm-log-box'); const progressBar = document.getElementById('nm-progress-bar'); const progressText = document.getElementById('nm-progress-text'); const phaseLabel = document.getElementById('nm-phase-label'); function log(msg, type = '') { const line = document.createElement('div'); if (type) line.className = `nm-${type}`; line.textContent = msg; logBox.appendChild(line); logBox.scrollTop = logBox.scrollHeight; console.log('[脑图导出] ' + msg); } function clearLog() { logBox.innerHTML = ''; } function setProgress(cur, total, phase) { const pct = total > 0 ? Math.round((cur / total) * 100) : 0; progressBar.style.width = pct + '%'; if (phase === 'zip') { phaseLabel.textContent = '📦 打包中 ' + pct + '%'; progressText.textContent = ''; } else { phaseLabel.textContent = '📥 采集文件'; progressText.textContent = cur + ' / ' + total; } } // ─── CSRF ────────────────────────────────────────────────────────────────── function getCsrf() { const el = document.getElementById('km-csrf'); if (el && el.value) return el.value; const m = document.cookie.match(/(?:^|;\s*)csrfToken=([^;]+)/); if (m) return decodeURIComponent(m[1]); const meta = document.querySelector('meta[name="csrf-token"]'); if (meta) return meta.getAttribute('content'); return ''; } // ─── API(使用页面 jQuery) ───────────────────────────────────────────────── function api(path, data = {}) { const csrf = getCsrf(); const body = Object.assign({}, data); if (csrf) body.csrf_token = csrf; return new Promise((resolve, reject) => { const jq = (typeof jQuery !== 'undefined') ? jQuery : (typeof $ !== 'undefined' ? $ : null); if (!jq) { reject(new Error('jQuery 不可用')); return; } jq.ajax({ url: path, type: 'POST', cache: false, data: body, dataType: 'json', success(json) { if (json.errno !== 0 && json.errno != null) { reject(new Error('API ' + path + ' errno=' + json.errno)); } else { resolve(json.data !== undefined ? json.data : json); } }, error(xhr, status, err) { reject(new Error('API ' + path + ' 失败: ' + status)); } }); }); } function sleep(ms) { return new Promise(r => setTimeout(r, ms)); } function sanitize(name) { return (name || 'untitled').replace(/[\\/:*?"|]/g, '_').trim() || 'untitled'; } // ─── 递归遍历 ────────────────────────────────────────────────────────────── async function walkDir(dirGuid, zipFolder, counter) { let items; try { const res = await api('bos/ls', { dirGuid }); if (Array.isArray(res)) items = res; else if (Array.isArray(res.list)) items = res.list; else if (Array.isArray(res.children)) items = res.children; else items = []; } catch (e) { log('⚠ 读取目录失败: ' + e.message, 'warn'); return; } const files = items.filter(i => i.file_type === 'file'); const dirs = items.filter(i => i.file_type === 'directory'); counter[1] += files.length; setProgress(counter[0], counter[1], 'fetch'); for (const dir of dirs) { const subFolder = zipFolder.folder(sanitize(dir.file_name)); log('📁 进入目录:' + dir.file_name); await walkDir(dir.file_guid, subFolder, counter); await sleep(200); } for (const file of files) { try { const fileData = await api('bos/open', { fileGuid: file.file_guid }); let content = fileData.content; if (typeof content === 'object') content = JSON.stringify(content); let fileName = fileData.file_name || file.file_name || 'untitled'; const ext = fileData.ext_name || '.km'; if (!fileName.endsWith(ext)) fileName += ext; zipFolder.file(sanitize(fileName), content); counter[0]++; setProgress(counter[0], counter[1], 'fetch'); log('✓ ' + fileName, 'ok'); } catch (e) { log('✗ ' + (file.file_name || file.file_guid) + ' 失败: ' + e.message, 'err'); counter[0]++; setProgress(counter[0], counter[1], 'fetch'); } await sleep(300 + Math.random() * 200); } } // ─── 主流程 ──────────────────────────────────────────────────────────────── async function startExport() { btn.disabled = true; btn.textContent = '⏳ 导出中…'; panel.style.display = 'block'; clearLog(); setProgress(0, 0, 'fetch'); log('🚀 开始批量导出…'); try { // 1) 获取根目录 log('正在获取根目录…'); const rootData = await api('bos/get_root_dir'); const rootGuid = rootData.file_guid || rootData.dirGuid; const creatorName = rootData.creater_name || 'naotu'; if (!rootGuid) throw new Error('无法获取根目录 GUID'); log('根目录 GUID: ' + rootGuid + ',用户: ' + creatorName, 'ok'); // 2) 创建 ZIP const zip = new JSZip(); console.log('[脑图导出] JSZip 实例创建成功, typeof zip.generateAsync =', typeof zip.generateAsync); const counter = [0, 0]; // 3) 递归遍历 await walkDir(rootGuid, zip, counter); if (counter[1] === 0) { log('⚠ 未找到任何脑图文件', 'warn'); return; } // 4) 打包 — 使用 STORE(不压缩)避免 DEFLATE 卡死,先确保流程通畅 log('📦 正在打包 ZIP(' + counter[0] + ' 个文件)…'); setProgress(0, 100, 'zip'); console.log('[脑图导出] 即将调用 zip.generateAsync...'); console.log('[脑图导出] zip 内文件数:', Object.keys(zip.files).length); let zipBlob = null; // 先尝试无回调 + STORE 模式 try { console.log('[脑图导出] 尝试方式1: generateAsync + STORE + onUpdate 回调'); zipBlob = await zip.generateAsync( { type: 'blob', compression: 'STORE' }, function onUpdate(meta) { // 回调内部不能抛异常,否则会中断 generateAsync try { var pct = Math.round(meta.percent); setProgress(pct, 100, 'zip'); if (pct % 10 === 0) { console.log('[脑图导出] 打包进度: ' + pct + '%'); } } catch (e) { console.warn('[脑图导出] onUpdate 内部错误:', e); } } ); console.log('[脑图导出] 方式1成功! blob size =', zipBlob.size); } catch (e1) { console.error('[脑图导出] 方式1失败:', e1); // 方式2:完全无回调,用 arraybuffer 再转 blob try { console.log('[脑图导出] 尝试方式2: generateAsync + arraybuffer(无回调)'); var ab = await zip.generateAsync({ type: 'arraybuffer', compression: 'STORE' }); zipBlob = new Blob([ab], { type: 'application/zip' }); console.log('[脑图导出] 方式2成功! blob size =', zipBlob.size); } catch (e2) { console.error('[脑图导出] 方式2失败:', e2); // 方式3:用 nodebuffer / uint8array try { console.log('[脑图导出] 尝试方式3: generateAsync + uint8array'); var u8 = await zip.generateAsync({ type: 'uint8array', compression: 'STORE' }); zipBlob = new Blob([u8], { type: 'application/zip' }); console.log('[脑图导出] 方式3成功! blob size =', zipBlob.size); } catch (e3) { console.error('[脑图导出] 方式3失败:', e3); throw new Error('所有打包方式均失败: ' + e1.message + ' | ' + e2.message + ' | ' + e3.message); } } } setProgress(100, 100, 'zip'); console.log('[脑图导出] 打包完成,blob size =', zipBlob.size, 'type =', zipBlob.type); // 5) 下载 const now = new Date(); const datePart = now.getFullYear() + '_' + String(now.getMonth() + 1).padStart(2, '0') + '_' + String(now.getDate()).padStart(2, '0'); const fileName = creatorName + '_脑图备份_' + datePart + '.zip'; console.log('[脑图导出] 开始下载,文件名:', fileName); const url = URL.createObjectURL(zipBlob); console.log('[脑图导出] createObjectURL 成功:', url); const a = document.createElement('a'); a.href = url; a.download = fileName; a.style.display = 'none'; document.body.appendChild(a); a.click(); console.log('[脑图导出] a.click() 已执行'); setTimeout(() => { URL.revokeObjectURL(url); if (a.parentNode) a.parentNode.removeChild(a); console.log('[脑图导出] 下载链接已清理'); }, 10000); log('🎉 导出完成!共 ' + counter[0] + ' 个文件,已打包下载:' + fileName, 'ok'); } catch (e) { log('❌ 导出失败:' + e.message, 'err'); console.error('[脑图导出] 错误详情:', e); } finally { btn.disabled = false; btn.textContent = '📦 批量导出'; } } btn.addEventListener('click', startExport); console.log('[脑图导出] 脚本已加载,点击右下角【📦 批量导出】按钮开始。');})();