📖
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)
name = name.replace(" ", "_").replace(" ", "_")
return name
# ★ UUID削除
def normalize_name(name):
# 末尾のUUIDっぽい部分を削除
return re.sub(r"\s+[0-9a-f]{32}$", "", name)
# ★ フォルダ探索
def find_asset_folder(base_dir, md_filename):
base_name = os.path.splitext(md_filename)[0]
normalized_md = normalize_name(base_name)
for item in os.listdir(base_dir):
full_path = os.path.join(base_dir, item)
if os.path.isdir(full_path):
if item == normalized_md:
return full_path
return None
for file in os.listdir(INPUT_DIR):
file_path = os.path.join(INPUT_DIR, file)
if file.endswith(".md") and os.path.isfile(file_path):
ts = datetime.fromtimestamp(os.path.getmtime(file_path))
new_filename_base = ts.strftime("%Y-%m-%dT%H-%M-%S")
new_md_path = os.path.join(OUTPUT_DIR, f"{new_filename_base}.md")
new_asset_folder = os.path.join(ASSET_DIR, new_filename_base)
old_asset_folder = find_asset_folder(INPUT_DIR, file)
# === 画像コピー ===
if 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)
if not os.path.isfile(old_img_path):
continue
safe_name = clean_filename(img_name)
new_img_path = os.path.join(new_asset_folder, safe_name)
shutil.copy2(old_img_path, new_img_path)
print(f" └─ コピー成功: {old_asset_folder}")
else:
print(f" └─ フォルダ未検出: {file}")
# === md処理 ===
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
def replace_link(match):
path = match.group(1)
filename = path.split("/")[-1]
cleaned = clean_filename(filename)
return f""
content = re.sub(
r'!\[[^\]]*\]\(([^)]+)\)',
replace_link,
content
)
yaml_header = """---
tags:
-
aliases:
-
UID:
---
"""
with open(new_md_path, "w", encoding="utf-8") as f:
f.write(yaml_header + content)
print(f"[✓] {file}")
print("\n=== 完了 ===")
スクリプトの実行方法
Notion_Exportというフォルダを作成し、その中に解凍したMarkdownファイルと画像ファイルを格納します。スクリプトも同じフォルダに配置します。

上記のフォルダの場所で、以下のコマンドでスクリプトを実行します。
python3 convert_notion_to_obsidian.py
Obsidian_Vaultというフォルダの中に、MDファイルと画像フォルダが生成されるので、それぞれをObsidianのVaultに移して完了です。

Notionのタグ情報とか、改行、空白行など手動で修正したほうが早いものは、そのままにしてあります。
(目視確認するし、Obsidian用に整形したいので、ある程度は手動がいいかなと思ってます)
URLリンクもメンションするなら手動で貼り直しです。今は動画にも対応していません。できたらまた、更新したいと思います。。。
Discussion