Python×Notion|下書きDBへAPIで流し込む

記事のネタや下書きを、こんな風に管理していませんか?

  • 「手元のテキストファイルに書いた下書きを、毎回Notionにコピペしている」
  • 「コピペのたびに、タイトルやタグを手で入力している」
  • 「下書きがあちこちに散らばって、どこに何があるかわからない」

NotionにはAPIが用意されているので、Pythonからデータベースにページを作ることができます。

今回は、フォルダに置いた下書きファイルを読み込んで、Notionの下書きデータベースにまとめて登録するスクリプトを作ります。

💡
この記事でわかること
  • PythonからNotion APIを使うための準備
  • 下書きファイルをNotionのデータベースに登録するコード
  • APIの制限でつまずかないためのポイント
  • 運用前のチェックリスト

全体の流れ

  1. 下書きをテキストファイルで drafts フォルダに置く(1行目がタイトル)
  2. Pythonがファイルを読み込む
  3. Notion APIで、下書きデータベースにページを作る
  4. 登録が終わったファイルは done フォルダに移す

ポイントは、Notion側では必ず「下書き(非公開)」として登録することです。仕上げと公開の判断は、Notion上で自分が行います。


準備:インテグレーションとデータベース

1. インテグレーションを作る

Notionの開発者向けページからインテグレーションを作成し、トークンを発行します。トークンはパスワードと同じくらい大事に扱いましょう。

2. データベースに接続する

下書き用のデータベースを開き、右上のメニューから作成したインテグレーションを接続します。これを忘れると、APIからデータベースが見えません。

3. プロパティを用意する

今回のコードでは、次のプロパティを使います。名前は自分のデータベースに合わせて変更してください。

プロパティ名 種類 入れるもの
Page タイトル ファイルの1行目
Slug テキスト ファイル名(拡張子なし)
Tags マルチセレクト 「下書き」など任意のタグ
Published チェックボックス 常にオフ(非公開)

4. Pythonの環境を用意する
  • 1
  • 2
  • 3
python3 -m venv .venv
source .venv/bin/activate   # Windowsは .venv\Scripts\activate
pip install requests

トークンとデータベースIDは、コードに書かずに環境変数で渡します。

  • 1
  • 2
export NOTION_TOKEN="(発行したトークン)"
export NOTION_DATABASE_ID="(データベースのID)"

下書きを登録するコード

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
import os
import time
from pathlib import Path

import requests

NOTION_TOKEN = os.environ["NOTION_TOKEN"]
DATABASE_ID = os.environ["NOTION_DATABASE_ID"]
HEADERS = {
    "Authorization": f"Bearer {NOTION_TOKEN}",
    "Notion-Version": "2022-06-28",
    "Content-Type": "application/json",
}

BASE_DIR = Path(__file__).resolve().parent
DRAFT_DIR = BASE_DIR / "drafts"
DONE_DIR = BASE_DIR / "done"


def paragraph(text: str) -> dict:
    # 1つのテキストは2000文字までなので、念のため切り詰める
    return {
        "object": "block",
        "type": "paragraph",
        "paragraph": {"rich_text": [{"type": "text", "text": {"content": text[:2000]}}]},
    }


def create_draft(title: str, slug: str, paragraphs: list[str]) -> str:
    payload = {
        "parent": {"database_id": DATABASE_ID},
        "properties": {
            "Page": {"title": [{"text": {"content": title}}]},
            "Slug": {"rich_text": [{"text": {"content": slug}}]},
            "Tags": {"multi_select": [{"name": "下書き"}]},
            "Published": {"checkbox": False},
        },
        # 1回のリクエストで追加できるブロックは100個まで
        "children": [paragraph(p) for p in paragraphs][:100],
    }
    res = requests.post("https://api.notion.com/v1/pages", headers=HEADERS, json=payload, timeout=30)
    res.raise_for_status()
    return res.json()["url"]


def main() -> None:
    DONE_DIR.mkdir(exist_ok=True)
    for path in sorted(DRAFT_DIR.glob("*.txt")):
        lines = path.read_text(encoding="utf-8").splitlines()
        if not lines:
            continue
        title = lines[0].strip()
        # 空行で区切られたかたまりを、1つの段落にする
        body = "\n".join(lines[1:]).strip()
        paragraphs = [p.strip() for p in body.split("\n\n") if p.strip()]

        url = create_draft(title, path.stem, paragraphs)
        print(f"登録しました:{title} -> {url}")
        path.rename(DONE_DIR / path.name)

        # APIの利用制限にかからないよう、少し間を空ける
        time.sleep(0.5)


if __name__ == "__main__":
    main()

ポイントは次の3つです。

  • 下書きとして登録:Published は常に False にしている
  • 登録済みは移動:同じファイルを二重に登録しないよう、成功したら done に移している
  • 制限を意識:テキストの文字数とブロック数の上限、リクエストの間隔に気をつけている

if __name__ == "__main__": の意味が気になった方は、こちらで解説しています。

Pythonの「おまじない」って何?「if name == "main"」の正体と意味をやさしく解説!


つまずきやすいポイント

症状 よくある原因 対処
404エラーが返る データベースにインテグレーションが接続されていない データベースのメニューから接続する
400エラーが返る プロパティ名や種類がデータベースと合っていない エラーメッセージを確認し、名前を合わせる
429エラーが返る 短時間にリクエストを送りすぎている 待ち時間を長くして、時間を置いて再実行する
長い段落が途中で切れる 1つのテキストの文字数上限 段落を分けて書く

運用前のチェックリスト

トークンをコードや公開リポジトリに書いていない
インテグレーションは、下書き用のデータベースにだけ接続している
テスト用のファイル1つで、登録と移動ができることを確認した
登録されたページが非公開(Publishedがオフ)になっている

まとめ

今回は、Pythonで手元の下書きをNotionのデータベースに登録する方法を紹介しました。

  • インテグレーションを作って、データベースに接続する
  • トークンは環境変数で渡す
  • 登録は必ず「下書き」として、公開の判断は人が行う

次の一歩は、テスト用のデータベースを新しく作って、下書きファイル1つで試してみることです。うまくいったら、いつも使っているデータベースに切り替えましょう。

情報収集から下書き作成までをノーコードでつなげたい方は、n8nを使う方法もあります。

n8n入門:RSS→AI要約→下書き作成までをノーコードで自動化する流れ

※2026年10月追記:関連する記事を公開しました。


メンバーのSNSアカウントはこちら

◆かいと:IT担当
X(旧Twitter)
Instagram