PR

PythonでWordPressの記事をMarkdown化し、Obsidianに同期するスクリプトを作ってみた

WordPressの記事をMarkdown化してObsidianへ Pythonスクリプトで自動化する方法 IT活用・効率化
記事内に広告が含まれています。

WordPressで書いた記事をObsidianでも管理したい──

そんなことを考えたことはありませんか?

私は以前、Obsidian Web Clipperを使って、公開した記事を1つずつMarkdown化して取り込んでいました。

しかし、この作業は思った以上に手間がかかり、「毎回やるのは正直面倒…」というのが本音でした。

そこで、PythonスクリプトでWordPressの記事を自動的にObsidianへ取り込む仕組みを作ってみました。

今回は、その背景と具体的な実装手順を紹介します。

WordPress × Obsidian をつなぐ目的

ObsidianはMarkdown形式で情報を整理できる強力なノートツールです。

ブログの下書きやネタ管理だけでなく、公開した記事をナレッジとして再活用するのにも最適です。

私の場合、Obsidian側で Smart Composer プラグイン を使い、既存の記事を再構成したり、過去の文章を次の記事ネタとして再利用しています。

そのため、「WordPressで公開した記事をObsidianのVault内にMarkdownで残す」ことが重要でした。

でも、記事を公開、更新するたびに手作業でクリップするのは続けられない──

なんとかラクできないかなと調べて、WordPress REST API と Pythonで自動化する仕組みを構築しました。

仕組みの概要

今回はPythonのスクリプトを使って、WordPress REST APIから公開記事と固定ページを取得し、MarkdownでObsidianのVaultに保存する仕組みを構築しました。

記事を公開・更新するタイミングでスクリプトを実行してVaultに保存します。

▶ フロー概要

  1. WordPress REST APIから記事を取得
  2. requestsでデータを取得し、markdownifyモジュールでMarkdown化
  3. YAMLヘッダーを付加
  4. iCloud Drive上の My Vault/PublicBlog/ に保存
  5. Obsidianからアクセスできる状態に

環境と前提条件

今回の環境、前提条件は以下のとおりです。

  • macOS(Python 3.9以上)
  • Obsidian VaultがiCloud Driveと同期済み
    VaultはiCloudの直下のObsidian/My Vaultに格納
  • WordPressのREST APIが有効(標準でON)
  • 必要なPythonのライブラリ:markdownify

この環境で動作を確認して、その後他のOSなどでも検証していきたいと思います。

PythonはMacOSに標準でインストールされているものを利用します。

markdownifyはHTMLをMarkdown形式に変換するPythonのライブラリです。

以下のコマンドでインストールしておきます。

pip install requests markdownify python-dateutil

WordPressの記事をMarkdown化してObsidianに同期する

このスクリプトは、WordPressのREST APIから記事(投稿+固定ページ)を取得し、本文をMarkdown化してObsidian VaultのPublicBlogフォルダにあるドメイン名フォルダに自動保存します。

投稿は posts/ フォルダ、固定ページは pages/ フォルダにそれぞれ分けて出力されます。

▶ スクリプト

スクリプトは作成後、ObsidianのVaultのPublicBlogフォルダに、ファイル名wp_to_obsidian.pyで保存してください。

設定(あなたの環境に合わせて変更)」の部分は環境に合わせて変更します。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
WordPress → Obsidian Markdown Exporter(投稿+固定ページ分離版)
------------------------------------------------
WordPressの公開投稿と固定ページを取得し、
Markdown(.md)に変換して iCloud Drive 上の Obsidian Vault に保存します。

出力構成:
~/Library/Mobile Documents/iCloud~md~obsidian/Documents/My Vault/PublicBlog/<ドメイン名>/
 ├── posts/
 └── pages/
"""

import os
import re
import sys
import requests
from markdownify import markdownify as md
from urllib.parse import urljoin
from dateutil import parser as dp

# ---------------------------------------------------
# 🔧 設定(あなたの環境に合わせて変更)
# ---------------------------------------------------
SITE = "https://hirosfreedomblog.com"   # あなたのWordPressサイトURL
SINCE = "2024-01-01"                    # この日付以降の記事を取得
OUT_BASE = "/Users/myaccount/Library/Mobile Documents/iCloud~md~obsidian/Documents/My Vault/PublicBlog"
# ---------------------------------------------------


def html_to_md(html: str) -> str:
    """WordPressのHTML本文をMarkdownに変換"""
    html = re.sub(r"<!--.*?-->", "", html)  # 不要なブロックコメント削除
    text = md(html, heading_style="ATX", bullets="*")  # Markdown化
    return re.sub(r"\n{3,}", "\n\n", text).strip() + "\n"


def fetch_posts(endpoint: str, params: dict):
    """WordPress REST APIから記事を取得"""
    try:
        resp = requests.get(urljoin(SITE, endpoint), params=params, timeout=20)
        resp.raise_for_status()
        return resp.json()
    except Exception as e:
        print(f"❌ {endpoint} の取得に失敗: {e}")
        return []


def save_post(item: dict, out_dir: str):
    """1件の記事をMarkdownとして保存"""
    title = re.sub("<[^<]+?>", "", item["title"]["rendered"]).strip()
    date = dp.parse(item["date"]).date().isoformat()
    slug = item["slug"]
    url = item["link"]
    md_text = html_to_md(item["content"]["rendered"])

    os.makedirs(out_dir, exist_ok=True)
    fname = f"{date}-{slug}.md"
    fpath = os.path.join(out_dir, fname)

    with open(fpath, "w", encoding="utf-8") as f:
        f.write(f"---\n")
        f.write(f"title: {title}\n")
        f.write(f"url: {url}\n")
        f.write(f"published: {date}\n")
        f.write(f"site: {SITE}\n")
        f.write(f"---\n\n")
        f.write(f"# {title}\n\n{md_text}")

    print(f"✅ {fname} を保存 ({out_dir.split('/')[-1]})")


def main():
    print("🔄 WordPress → Obsidian Export 開始")

    domain = SITE.replace("https://", "").replace("http://", "").strip("/")
    OUT_DIR = os.path.join(OUT_BASE, domain)
    POSTS_DIR = os.path.join(OUT_DIR, "posts")
    PAGES_DIR = os.path.join(OUT_DIR, "pages")

    print(f"📁 出力先: {OUT_DIR}")
    os.makedirs(POSTS_DIR, exist_ok=True)
    os.makedirs(PAGES_DIR, exist_ok=True)

    params = {
        "status": "publish",
        "per_page": 50,
        "after": f"{SINCE}T00:00:00",
        "_fields": "date,slug,title,content,link",
    }

    # 投稿と固定ページをそれぞれ取得
    posts = fetch_posts("/wp-json/wp/v2/posts", params)
    pages = fetch_posts("/wp-json/wp/v2/pages", params)

    if not posts and not pages:
        print("⚠️ 新しい投稿や固定ページは見つかりません。")
        return

    for p in posts:
        save_post(p, POSTS_DIR)

    for p in pages:
        save_post(p, PAGES_DIR)

    total = len(posts) + len(pages)
    print(f"🎉 Export 完了!合計 {total} 件(投稿 {len(posts)}/固定ページ {len(pages)})を出力。")


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n⏹ 中断しました。")
    except Exception as e:
        print("❌ 予期せぬエラー:", e)
        sys.exit(1)

コードのポイントは以下のとおりです。

目的コード部分解説
WordPress APIを呼び出すfetch_posts()/posts と /pages の2種類を取得
HTMLをMarkdownに変換html_to_md()markdownify ライブラリを使用
メタ情報を保持YAMLブロックタイトル・URL・公開日などをObsidianで使える形に保存
出力先を分離posts/ pages/記事と固定ページを別フォルダ管理
上書き処理with open(…, “w”)更新時は既存ファイルを上書き(常に最新化)

※ このスクリプトは毎回すべての記事を再取得・上書き保存するシンプルな仕組みです。記事数が多い場合は処理に少し時間がかかりますが、常に最新の状態を確実に反映できます。WordPressの記事数が非常に多い場合は、変更のあった記事のみ同期する「差分更新」方式に改良することも可能です。運用規模に応じて調整してください。

▶ 実行コマンド

初回実行で posts/ と pages/ フォルダが自動作成され、WordPressの記事がすべてMarkdownで保存されます。

python3 ~/Library/Mobile\ Documents/iCloud~md~obsidian/Documents/My\ Vault/PublicBlog/wp_to_obsidian.py

▶ 実行結果の例

▶ 出力構成(Finder / Obsidianで確認)

My Vault/
 └── PublicBlog/
      └── hirosfreedomblog.com/
           ├── posts/
           │    ├── 2025-10-25-shottr-mac-screenshot.md
           │    ├── 2025-10-24-obsidian-daily-note-todo.md
           │    └── ...
           └── pages/
                ├── about.md
                ├── privacy-policy.md
                └── contact.md

WordPressの記事と固定ページが自動でObsidian Vaultに同期されています。

運用の工夫

無事に取り込めたので、Obsidianで以下の運用が可能になります。

  • 記事更新後にコマンドを再実行 → 自動上書き
  • iCloud同期で他のMac・iPadにも即反映
  • Dataviewで記事一覧を自動生成
  • Smart Composerで再構成・要約・再執筆

今後の展開アイデア

今回はWordPressの記事とObsidianを同期させる基本的な部分を実現しました。

今後は以下のような展開を考えています。

  • iPadでのモバイル運用
  • Windowsでの運用
  • スクリプトの高機能化
  • SmartComposerで記事の活用

更新したらまた共有します。

まとめ

WordPress × Python × Obsidian の組み合わせで、「ブログの公開」と「知識管理」をシームレスに繋げることができました。

Markdownで記事を残しておけば、後から修正・引用・再構成が自在です。

手動では続かないことを自動化する──

それが、この仕組みを作った最大の目的です。

今後も機能を拡張しながら、より便利に使える形を模索していきます。

改善アイデアなどがあれば、ぜひ教えてください。

※ 注意: このスクリプトは自分が管理するWordPressサイトのバックアップや編集効率化を目的としたものです。第三者のサイトを無断で取得・保存することは著作権や利用規約に抵触する場合があります。

コメント

タイトルとURLをコピーしました