Obsidian Image Uploader
一个用于批量处理 Obsidian Vault 中本地图片引用的脚本工具。
它会遍历指定 Obsidian Vault 中的 Markdown 文件,查找本地图片引用,通过 PicGo Server 上传图片,并将本地图片链接替换为远程 URL。
脚本会处理整个 Markdown 文件内容,包括正文和 frontmatter。
功能
- 遍历 Obsidian Vault 中的所有 Markdown 文件。
- 处理整个 Markdown 文件,包括 frontmatter。
- 支持 Obsidian 嵌入图片语法:
![[image.png]]![[image.png|440]]![[image.png|440x300]]![[image.png|说明文字]]![[image.png|说明文字|440]]
- 支持 Obsidian 普通文件链接语法:
[[image.png]][[image.png|别名]]
- 支持标准 Markdown 本地图片语法:

- 自动通过 PicGo Server 上传本地图片。
- 自动将本地图片引用替换为远程 URL。
- 支持上传前自动转换为 WebP 格式,减小图片体积。
- 同一个实际图片文件只上传一次,后续引用复用同一个 URL。
- 不同路径下的同名图片会被视为不同图片。
- 支持 5 分钟配额限制自动重试(带随机抖动)。
- 支持通过启动参数指定 Obsidian Vault 路径。
- 支持交互式输入 Obsidian Vault 路径。
前置条件
PicGo
需要安装并配置 PicGo。
同时需要开启 PicGo Server。
默认接口地址为:
http://127.0.0.1:36677/upload
脚本中的默认配置:
PICGO_API = "http://127.0.0.1:36677/upload"
如果你的 PicGo Server 地址不同,需要修改 upload_obsidian_images.py 中的 PICGO_API。
使用方式
安装 uv 后,直接运行:
uv run upload_obsidian_images.py
或运行时手动输入 obsidian 仓库路径
uv run upload_obsidian_images.py <vault path>
[!important] 重要 脚本会直接修改 Markdown 文件内容。
首次运行前,建议先使用 Git 或其他方式备份 Vault。
常见问题
PicGo Server 没有开启怎么办?
如果 PicGo Server 未开启,脚本会提示:
上传失败:无法连接 PicGo Server,请确认 PicGo Server 已开启。
请先打开 PicGo,并确认 PicGo Server 功能已开启。
如何关闭 [[file.png]] 的转换?
使用:
python upload_obsidian_images.py ~/Temp/Test --no-convert-file-links
如何处理多个同名图片更安全?
将脚本中的:
SKIP_AMBIGUOUS_WIKI_IMAGE = False
改为:
SKIP_AMBIGUOUS_WIKI_IMAGE = True
这样脚本遇到多个同名图片时会跳过,不会默认使用第一个匹配项。
如何关闭 WebP 转换?
python upload_obsidian_images.py ~/Temp/Test --no-convert-webp
上传图片时提示配额限制怎么办?
脚本内置了自动重试机制,遇到配额限制时会自动等待约 5 分钟后重试,无需手动干预。
如果希望在更短时间内上传大量图片,可以每次只处理少量 Markdown 文件,分批次运行。
配额限制与自动重试策略是怎样的?
PicGo 使用的图床通常有 5 分钟上传配额限制。脚本针对此问题内置了自动重试机制:
- 遇到
429/500/quota/rate limit等响应时,自动等待约 5 分钟 + 随机抖动(0-30 秒),然后重试。 - 最多重试 10 次,保证在大批量上传时能自动续传。
- 随机抖动用于避免多个请求恰好撞在配额窗口边界。
抖动和重试次数可在脚本顶部的
MAX_UPLOAD_RETRIES、RATE_LIMIT_RETRY_DELAY_SECONDS、RATE_LIMIT_JITTER_SECONDS变量中调整。
为什么带尺寸的图片会转换成 HTML?
标准 Markdown 图片语法是:

其中 alt 是替代文本,不是图片宽度。
例如:

含义是:
<img src="url" alt="440">
而不是:
<img src="url" width="440">
因此,为了保留 Obsidian 中 ![[file.png|440]] 的渲染大小,脚本会将其转换为 HTML:
<img src="url" width="440">
Frontmatter 是否会处理?
脚本会处理整个 Markdown 文件,包括 frontmatter。
例如:
---
cover: "![[cover.png]]"
attachment: "[[file.png]]"
---
也会被转换。
示例转换结果:
---
cover: ""
attachment: "[file.png](https://example.com/file.png)"
---
注意:frontmatter 是结构化元数据。如果某些发布系统、Dataview 查询或插件依赖原始 Obsidian 链接格式,转换前建议先确认兼容性。
同一张图片被多次引用是否导致重复上传?
脚本会缓存已经上传过的图片。
缓存 key 使用图片文件的 resolved absolute path,也就是解析后的绝对路径。
因此:
/Users/lu/Vault/assets/demo.png
如果被多个 Markdown 文件引用,只会上传一次。
后续引用会复用第一次上传得到的远程 URL。
如何处理同名图片与重复引用?
对于 Obsidian Wiki 图片引用,例如:
![[demo.png]]
脚本会在整个 Vault 中查找 demo.png。
如果同一个图片文件被多个 Markdown 文件引用,脚本只会上传一次,并复用第一次上传得到的远程 URL 替换所有引用位置。
如果 Vault 中存在多个同名图片文件,例如:
assets/demo.png
notes/project-a/demo.png
notes/project-b/demo.png
脚本不会把它们简单视为同一张图片。
因为多个同名文件可能是不同图片,所以脚本的上传缓存基于"实际文件路径",而不是单纯基于文件名。
也就是说:
- 同一路径的图片文件:只上传一次。
- 不同路径的同名图片文件:视为不同图片。
- 无法唯一确定的 Wiki 图片引用:会输出警告。
当前默认策略是:如果发现多个同名图片,脚本会输出警告,并默认使用第一个匹配结果。
如果你希望更安全,可以在脚本中将:
SKIP_AMBIGUOUS_WIKI_IMAGE = False
改为:
SKIP_AMBIGUOUS_WIKI_IMAGE = True
这样遇到多个同名图片时,脚本会跳过该引用,不上传、不替换,避免误替换。
已经是远程图片的引用会不会处理?
例如:

不会被重复上传或替换。
目前普通 Markdown 图片链接中,http:// 和 https:// 开头的 URL 都会被跳过。