📖
NotionでエクスポートしたMDファイルをObsidianに取り込む
Obsidianに記事を移したかったため、スクリプトで対応することにしました。この作業を頻繁に行っていて、画像が10枚も20枚もあると、全て手動では無理なので、楽にやりたいなと思って作りました。(スクリプト化してるけど、ある程度は手動で整形します)
↓Obsidianはこの時の環境
NotionからObsidianに記事を移行する
エクスポート
特に説明するところはありませんが、Notionの記事から「マークダウンとCSV」を選んでファイルをエクスポートしておきます。
Obsidianの構造
以下のフォルダ構造に対応しています。00_Assets
は画像を格納するためのフォルダで、各記事のファイル名に基づいたフォルダごとに画像が保存されています。
MyVault/
├── 00_Assets/
│ ├── 2025-05-29T12-10-45/
│ │ ├── IMG-20250625010534873.jpg
│ │ ├── IMG-20250625010535037.jpg
│ │ └── ...(他の画像)
│ └── 2025-03-25T14-51-20/
│ ├── IMG-20250625010149976.jpg
│ └── ...(複数の画像)
│
├── 2025-05-29T12-10-45.md
├── 2025-03-25T14-51-20.md
├── ...
スクリプトの機能
-
.md
ファイルのファイル名:2025-03-25T14-51-20.md
のような形式にリネーム - 画像フォルダ名: 対応する
.md
と同じ名前にして00_Assets/
の下へ移動 -
.md
ファイル内の画像リンク:
に書き換え - YAMLメタデータを記事の一番上に追加
できたスクリプト
コピペで使えます。画像の形式とかで合わないものに気づいたら更新していきます。
(ChatGPTで修正してます)
import os
import re
import shutil
from datetime import datetime
from urllib.parse import unquote
# === フォルダの設定 ===
INPUT_DIR = "Notion_Export"
OUTPUT_DIR = "Obsidian_Vault"
ASSET_DIR = os.path.join(OUTPUT_DIR, "00_Assets")
os.makedirs(ASSET_DIR, exist_ok=True)
# === ヘルパー:安全なファイル名に変換 ===
def clean_filename(name):
name = unquote(name) # %20 → 半角スペース
name = name.replace(" ", "_").replace(" ", "_")
return name
# === 処理開始 ===
for file in os.listdir(INPUT_DIR):
if file.endswith(".md"):
old_md_path = os.path.join(INPUT_DIR, file)
ts = datetime.fromtimestamp(os.path.getmtime(old_md_path))
new_filename_base = ts.strftime("%Y-%m-%dT%H-%M-%S")
new_md_name = f"{new_filename_base}.md"
new_md_path = os.path.join(OUTPUT_DIR, new_md_name)
basename_without_ext = os.path.splitext(file)[0]
old_asset_folder = os.path.join(INPUT_DIR, basename_without_ext)
new_asset_folder = os.path.join(ASSET_DIR, new_filename_base)
image_rename_map = {}
# === 画像フォルダの処理(ファイル名リネームしながらコピー) ===
if os.path.exists(old_asset_folder):
os.makedirs(new_asset_folder, exist_ok=True)
for img_name in os.listdir(old_asset_folder):
old_img_path = os.path.join(old_asset_folder, img_name)
safe_img_name = clean_filename(img_name)
new_img_path = os.path.join(new_asset_folder, safe_img_name)
shutil.copy2(old_img_path, new_img_path)
image_rename_map[img_name] = safe_img_name
print(f" └─ 画像 {len(image_rename_map)}個 → {new_asset_folder}")
else:
print(f" └─ 画像フォルダなし(スキップ)")
# === .md内容の読み込みとリンク変換 ===
with open(old_md_path, "r", encoding="utf-8") as f:
content = f.read()
def replace_link(match):
folder = match.group(1)
original_name = match.group(2)
cleaned_name = image_rename_map.get(original_name, clean_filename(original_name))
return f""
# Markdownリンクをすべて画像リンクに変換
content = re.sub(
r'!?[\[][^]]*[\]]\((.*?)\/(.*?)\)',
replace_link,
content
)
# YAMLヘッダーを挿入
yaml_header = f"""---
tags:
-
aliases:
-
UID:
---
"""
with open(new_md_path, "w", encoding="utf-8") as f:
f.write(yaml_header + content)
print(f"[✓] {file} → {new_md_name}")
print("\n=== 完了 ===")
スクリプトの実行方法
Notion_Export
というフォルダを作成し、その中に解凍したMarkdownファイルと画像ファイルを格納します。スクリプトも同じフォルダに配置します。
上記のフォルダの場所で、以下のコマンドでスクリプトを実行します。
python3 convert_notion_to_obsidian.py
Obsidian_Vaultというフォルダの中に、MDファイルと画像フォルダが生成されるので、それぞれをObsidianのVaultに移して完了です。
Notionのタグ情報とか、改行、空白行など手動で修正したほうが早いものは、そのままにしてあります。
(目視確認するし、Obsidian用に整形したいので、ある程度は手動がいいかなと思ってます)
URLリンクもメンションするなら手動で貼り直しです。今は動画にも対応していません。できたらまた、更新したいと思います。。。
Discussion