如何编写脚本批量导入Obsidian Markdown至Wiki.js并实现双向同步
实现Obsidian笔记批量导入Wiki.js及双向同步的通用步骤
一、前期准备
- 启用Wiki.js API:在后台「设置-API」中开启API访问,生成并妥善保存API密钥
- 整理Obsidian文件:将需导入的MD笔记和图片统一放到一个目录,确保图片使用相对路径(Obsidian默认是相对路径,若不是需批量替换)
- 安装基础工具:
- 安装Python 3.8及以上版本
- 通过pip安装依赖:
pip install requests python-frontmatter watchdog
二、批量导入(含本地图片)
1. 批量上传图片到Wiki.js媒体库
编写可直接修改使用的脚本片段:
import requests import os import json # 替换为你的实际配置 WIKIJS_API_BASE = "你的Wiki.js域名/api/v1" API_KEY = "你的API密钥" IMAGE_SOURCE_DIR = "Obsidian笔记的图片目录绝对路径" headers = {"Authorization": f"Bearer {API_KEY}"} # 存储本地路径到Wiki.js图片URL的映射 local_to_wiki_url = {} for file_name in os.listdir(IMAGE_SOURCE_DIR): if file_name.lower().endswith((".png", ".jpg", ".jpeg", ".gif", ".webp")): file_path = os.path.join(IMAGE_SOURCE_DIR, file_name) with open(file_path, "rb") as img_file: upload_data = {"file": img_file} resp = requests.post(f"{WIKIJS_API_BASE}/media/upload", headers=headers, files=upload_data) if resp.status_code == 200: wiki_url = resp.json()["data"]["url"] # 按Obsidian里的相对路径存储映射,比如 "./images/xxx.png" local_rel_path = os.path.join("./images", file_name) local_to_wiki_url[local_rel_path] = wiki_url print(f"上传成功:{file_name} -> {wiki_url}") # 把映射保存到文件,后续替换MD路径用 with open("image_map.json", "w") as f: json.dump(local_to_wiki_url, f)
运行脚本后,所有图片会上传到Wiki.js,同时生成image_map.json记录路径映射。
2. 替换MD图片路径并批量导入笔记
编写导入脚本:
import requests import os import frontmatter import json # 替换为你的实际配置 WIKIJS_API_BASE = "你的Wiki.js域名/api/v1" API_KEY = "你的API密钥" MD_SOURCE_DIR = "Obsidian笔记目录绝对路径" headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"} # 读取之前生成的图片路径映射 with open("image_map.json", "r") as f: local_to_wiki_url = json.load(f) # 存储MD文件名到Wiki.js页面ID的映射,用于后续同步 page_map = {} for file_name in os.listdir(MD_SOURCE_DIR): if file_name.endswith(".md"): file_path = os.path.join(MD_SOURCE_DIR, file_name) # 读取MD元数据和内容 note = frontmatter.load(file_path) # 替换图片路径 updated_content = note.content for local_path, wiki_url in local_to_wiki_url.items(): updated_content = updated_content.replace(local_path, wiki_url) # 构建上传参数 payload = { "title": note.get("title", file_name[:-3]), # 优先用Obsidian标题元数据,否则用文件名 "content": updated_content, "isPublished": True, "locale": "zh-CN" } # 创建Wiki.js页面 resp = requests.post(f"{WIKIJS_API_BASE}/pages", headers=headers, json=payload) if resp.status_code == 200: page_id = resp.json()["data"]["id"] page_map[file_name] = page_id print(f"导入成功:{file_name} -> 页面ID {page_id}") # 保存页面映射,用于后续同步 with open("page_map.json", "w") as f: json.dump(page_map, f)
运行脚本完成所有笔记的批量导入。
三、双向同步实现思路(低代码版)
1. Obsidian → Wiki.js 自动同步
- 利用
watchdog库监听Obsidian目录的文件变化(新增、修改、删除) - 触发逻辑:
- 新增/修改图片:自动上传到Wiki.js,更新
image_map.json - 新增/修改MD文件:替换图片路径后,若为新文件则创建Wiki.js页面,若为已导入文件则通过页面ID调用API更新内容
- 删除文件:通过页面ID调用API删除对应Wiki.js页面
- 新增/修改图片:自动上传到Wiki.js,更新
2. Wiki.js → Obsidian 自动同步
- 启用Wiki.js Webhook:在后台「设置-Webhooks」添加钩子,当页面修改/删除时,发送POST请求到本地服务
- 编写简单本地HTTP服务(用Flask):
- 接收Webhook的页面修改数据,下载页面MD内容
- 替换Wiki.js图片URL为本地路径(借助
image_map.json反向映射) - 将修改后的内容保存到Obsidian对应目录
- 若收到删除通知,删除Obsidian中对应MD文件
3. 冲突处理规则
- 设定修改优先级:比如优先保留Obsidian的修改,或优先保留Wiki.js的修改
- 记录每个文件的最后修改时间,同步时仅更新目标端中版本更旧的内容
四、无代码简化方案
- 批量导入:手动将图片上传到Wiki.js媒体库,批量替换MD中的本地路径后,使用Wiki.js后台「内容-导入」功能上传MD文件
- 双向同步:将Obsidian目录和Wiki.js页面内容同步到同一个Git仓库,通过Git的版本控制来处理同步和冲突
内容的提问来源于stack exchange,提问作者Ring
相关产品推荐
相关产品推荐

