📖

NotionでエクスポートしたMDファイルをObsidianに取り込む

に公開

Obsidianに記事を移したかったため、スクリプトで対応することにしました。この作業を頻繁に行っていて、画像が10枚も20枚もあると、全て手動では無理なので、楽にやりたいなと思って作りました。(スクリプト化してるけど、ある程度は手動で整形します)

↓Obsidianはこの時の環境
https://zenn.dev/fukagawa/articles/9e0436fe7e6f25

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ファイル内の画像リンク: ![](00_Assets/対応フォルダ名/元の画像ファイル名) に書き換え
  • 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"![](00_Assets/{new_filename_base}/{cleaned_name})"

        # 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