0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Notionを正本にして研究業績リストをMarkdown/HTMLに出力する

0
Last updated at Posted at 2026-06-08

はじめに

研究業績は、意外といろいろな場所で使います。

  • 個人Webサイト
  • 研究室Webサイト
  • Markdown形式のCV
  • プレーンテキストの業績リスト
  • researchmap
  • 申請書や所内書類

業績を毎回用意するのが本当に面倒です。書類の中身に時間を割きたいのに、しょーもない体裁の調整に時間をかけたくありません。

そこでこの記事では、Notionのデータベースを研究業績の正本として管理し、PythonスクリプトでMarkdownやHTMLに出力する運用を紹介します。

Notionを入口にする理由として、

  • よくできたGUIを活用したデータベースの構築ができる
  • クラウド上にデータを保存できるのでPCの更新などに左右されない
  • やろうと思えば今の他の環境からの移行もNotion APIでプログラムによる移行ができる(本記事では触れない)

あたりが理由です。

この記事は2本立ての前編です。

  • 前編: Notion DBから業績リストをMarkdown/HTML/TXTに出力する
  • 後編: Notion DBからresearchmap V2 CSVを生成・更新する

この記事では、researchmap連携にはまだ踏み込みません。まずは、Notionを正本にして業績リストを外部ファイルとして出力できるところまでを扱います。

この記事で作るもの

この記事で作る運用は、次のようなものです。

Notion Publications DB
  ↓
Pythonで取得
  ↓
cache/publications.json
  ↓
Markdown / HTML / TXT に出力

Notionを更新すれば、Webサイト用HTMLやMarkdown形式の業績リストを再生成できます。

例えば、次のようなコマンドでNotionから取得し、

uv run notion-export fetch \
  --config config.yaml \
  --cache cache/publications.json

次のようなコマンドでHTMLを出力します。

uv run notion-export render \
  --config config.yaml \
  --cache cache/publications.json \
  --template publications.html.j2 \
  --output outputs/publications.html

方針

この運用では、次の方針にします。

  • Notion DBを正本にする
  • 出力されたMarkdown/HTML/TXTは生成物として扱う
  • フォーマット変更はテンプレート側で行う
  • Notion APIの生データを直接テンプレートで触らない
  • 一度、扱いやすい中間JSONに変換してから出力する

全体像は次の通りです。

Notion API
  ↓
normalize
  ↓
cache/publications.json
  ↓
Jinja2 template
  ↓
Markdown / HTML / TXT

この構成にしておくと、Notionから取得する処理と、出力フォーマットを調整する処理を分けられます。

必要なもの

この記事では、以下を使います。

  • Notionアカウント
  • Python
  • uv
  • Notion API integration
  • Notion API token
  • Notion database ID

Python環境管理には uv を使います。

Notion側の準備

Publications DBを作る

まず、Notionに業績管理用のデータベースを作ります。ここでは Publications という名前にします。

データベース構築の公式情報は、例えばこちらを参考してください。

この記事の方針では、Notion DBを単なるメモ置き場ではなく、Markdown、HTML、TXT、将来的にはresearchmap CSVなどに展開できる構造化された業績データベースとして使います。

そのため、最初から次のような入力欄を用意しておくと後で楽です。

基本情報

プロパティ 用途 入力例
Name title 業績タイトル Numerical study on ...
Type select 業績種別 Original Paper, 国内学会
Authors list relation 著者リスト Authors DBへのrelation
Journal rich text / select 雑誌名、会議名、リポジトリ名など Combustion and Flame, 日本燃焼学会
Publication date date 出版日または発表日 2026-06-08
DOI url DOI URL https://doi.org/...

Name, Type, Authors list, Journal, Publication date, DOI は、少なくとも用意しておくことをおすすめします。特に DOI は、論文・preprintの外部リンクとして使いやすく、HTML出力やresearchmap連携でも重要になります。

Type には、例えば次のような選択肢を用意します。

Original Paper
Review paper
Preprint
International conference
国内学会

Journal という名前は少し論文寄りですが、この記事では会議名やリポジトリ名も含む汎用的な「掲載先・発表先」として使います。気になる場合は Venue という名前にしてもよいです。

論文用の情報

論文をきちんと出力したい場合は、巻・号・ページも分けて持っておくと便利です。

プロパティ 用途 入力例
Volume number 315
Issues number 1
Page rich text ページまたは論文番号 112345, 123-130

Volume, Issues, Page は、論文リストとして表示するときにほぼ必須です。最近の論文ではページ範囲ではなくarticle numberだけの場合もあるので、Page は number型よりも rich text にしておく方が扱いやすいです。

学会発表用の情報

学会発表まで管理したい場合は、次のプロパティを追加します。

プロパティ 用途 入力例
Place rich text 開催地 Houston, Texas, 東京
Duration date range 会議の開催期間 2026-06-082026-06-10
Presentation select 発表形式 Oral, Poster
Invited checkbox 招待講演かどうか checked / unchecked
Tags multi-select 任意の分類 combustion, quantum

Publication date は実際の発表日、Duration は会議全体の開催期間として使います。

Invited は、招待講演かどうかを後から出力に反映したい場合に重要です。researchmapでは「招待の有無」が独立した項目として扱われるため、後編のresearchmap CSV連携まで考えるなら追加しておくと便利です。

Preprint用の情報

arXivなどのpreprintも同じDBで管理したい場合は、次のプロパティを追加しておくとよいです。

プロパティ 用途 入力例
arXiv ID rich text arXiv ID 2501.01234
arXiv URL url arXivページ https://arxiv.org/abs/2501.01234
Journal Status select 査読済み版との関係 preprint, under_review, published
Related Journal Paper relation 対応する査読済み論文 同じPublications DBへのrelation

preprintと査読済み版は、タイトルや著者順、DOIが変わることがあります。そのため、preprintとOriginal Paperは別レコードとして持ち、Related Journal Paper で紐づける運用が安全です。

将来のresearchmap連携まで考える場合

後編で扱うresearchmap CSV連携まで考えるなら、次のプロパティも追加しておくと後が楽です。

プロパティ 用途
Researchmap ID rich text researchmap側の業績ID
Researchmap Type select researchmap種別を手動で上書きしたい場合
Sync to Researchmap checkbox researchmapに出力するかどうか
Researchmap Sync Status select 照合・同期状態のメモ
Language Code select jpn / eng
Country Code select / rich text JPN, USA, CAN など
Visibility select disclosed, researchers_only, closed
Major checkbox 主要業績かどうか

ただし、この記事ではresearchmap連携には踏み込みません。まずは、MarkdownやHTMLに出すための基本項目が揃っていれば十分です。

最初に作るおすすめ構成

最初からすべての欄を用意するのが大変な場合は、まず以下の構成で始めるのがおすすめです。

プロパティ
Name title
Type select
Authors list relation
Journal rich text / select
Publication date date
Volume number
Issues number
Page rich text
DOI url
Place rich text
Duration date range
Presentation select
Invited checkbox
Tags multi-select

Authors DBを作る

著者は、文字列で直接持つより、別データベースにしてrelationでつなぐと管理しやすいです。

Authors DBを作り、最小構成では以下を用意します。

プロパティ 用途
Name title 著者名
日本名 rich text 日本語アイテムでの表示名

まずは Name だけでも十分です。必要に応じて、後から表示名やresearchmap用の表記を追加できます。

Publications DBとAuthors DBをrelationでつなぐ

relationは、別データベースの項目を参照するためのプロパティです。APIから見ると、Authors list には著者名そのものではなく関連先ページIDが入るため、スクリプト側でAuthors DBを読み直して著者名に変換しています。

Publications DBに Authors list というrelationプロパティを追加し、Authors DBを参照するようにします。

これにより、各業績に対して複数の著者を紐づけられます。Notion上で著者順を管理しておけば、出力時にもその順序を使えます。

このあたりの仕組みについては、公式ではこの辺に情報があります。

Notion API integrationを作る

Notion APIからデータベースを読むには、integrationを作成し、対象データベースへアクセス権を付ける必要があります。

大まかな手順は次の通りです。

  1. NotionのDeveloper向けページでinternal integrationを作る
  2. tokenを取得する
  3. Publications DBにintegrationを追加する
  4. Authors DBにもintegrationを追加する
  5. database_idauthors_db_id を取得する

NotionのDBを作っただけではAPIから読めません。DB側でintegrationに明示的に共有する必要があります。

環境変数を設定する

このプロジェクトでは、Notion API tokenやDB IDを環境変数で渡します。

direnv を使うと便利です。

direnv edit .

取得したNotion API TokenとDatabase IDを以下の環境変数に格納しておきます。

export NOTION_KEY="secret_xxxxxxxxxxxxxxxxx"
export database_id="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export authors_db_id="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

.envrc には秘密情報が入るので、Git管理しないようにします。

.envrc

プロジェクトをセットアップする

以下のGitHubをクローンして持ってきてください。

git clone https://github.com/takakiba/notion-publication-exporter.git
cd notion-publication-exporter

おおよそ次のようなプロジェクト構造になっています。

notion-publication-exporter/
├── config.yaml
├── pyproject.toml
├── templates/
│   ├── publications.md.j2
│   ├── publications.html.j2
│   └── publications.txt.j2
├── src/
│   └── notion_exporter/
│       ├── __init__.py
│       ├── authors.py
│       ├── cache.py
│       ├── cli.py
│       ├── config.py
│       ├── dates.py
│       ├── models.py
│       ├── normalize.py
│       ├── notion_api.py
│       ├── render.py
│       ├── writer.py
│       └── researchmap/
└── README.md

依存関係は uv で入れます。

uv sync --default-index https://pypi.org/simple

CLIが見えるか確認します。

uv run notion-export --help

環境変数が読めているかも確認します。

uv run python - <<'PY'
import os

for key in ["NOTION_KEY", "database_id", "authors_db_id"]:
    print(f"{key}: {'OK' if os.getenv(key) else 'MISSING'}")
PY

例えば次のように出ればOKです。

NOTION_KEY: OK
database_id: OK
authors_db_id: OK

config.yamlを書く

Notion側のプロパティ名は、人によって違います。そこで、Pythonコードにプロパティ名を直接書かず、config.yaml で対応関係を指定します。

例です。

notion:
  token_env: NOTION_KEY
  database_id_env: database_id
  authors_database_id_env: authors_db_id
  data_source_id_env: null
  authors_data_source_id_env: null

query:
  types:
    - Original Paper
    - Review paper
    - Preprint
    - International conference
    - 国内学会
  date_begin: null
  date_end: today
  date_order: descending

properties:
  name: Name
  title: Name
  authors_relation: Authors list
  type: Type
  journal: Journal
  venue: Journal
  volume: Volume
  issue: Issues
  publication_date: Publication date
  page: Page
  doi: DOI
  place: Place
  duration: Duration
  presentation: Presentation
  tags: Tags

output:
  template: publications.md.j2
  file: outputs/publications.md

Notion側で Journal ではなく Venue というプロパティにしている場合は、ここを変えればよいです。

properties:
  journal: Venue
  venue: Venue

Notionからデータを取得する

Notionから最新データを取得し、正規化済みJSONとして保存します。

uv run notion-export fetch \
  --config config.yaml \
  --cache cache/publications.json

成功すると、例えば次のように表示されます。

Saved 70 item(s) to cache/publications.json

通常運用では、cache/publications.json を毎回上書きして問題ありません。別名で保存するのは、デバッグや比較をしたいときだけでよいです。

取得結果を確認するには、例えば次のようにします。

uv run python - <<'PY'
import json
from pathlib import Path

data = json.loads(Path("cache/publications.json").read_text(encoding="utf-8"))

print("items:", len(data))

for item in data[:5]:
    print("-" * 80)
    print("title:", item.get("title"))
    print("type:", item.get("type"))
    print("authors:", item.get("authors"))
    print("venue:", item.get("venue"))
PY

Markdownに出力する

Markdown形式で出力します。

uv run notion-export render \
  --config config.yaml \
  --cache cache/publications.json \
  --template publications.md.j2 \
  --output outputs/publications.md

出力を確認します。

sed -n '1,80p' outputs/publications.md

フォーマットを変更したい場合は、基本的に templates/publications.md.j2 を編集します。Notionから再取得する必要はありません。テンプレートを編集したら、render だけ実行すればよいです。

HTMLに出力する

HTML形式で出力します。

uv run notion-export render \
  --config config.yaml \
  --cache cache/publications.json \
  --template publications.html.j2 \
  --output outputs/publications.html

HTML出力は、個人Webサイトや研究室Webサイトに埋め込む用途に向いています。

TXTに出力する

プレーンテキストで出力したい場合は、TXT用テンプレートを使います。

uv run notion-export render \
  --config config.yaml \
  --cache cache/publications.json \
  --template publications.txt.j2 \
  --output outputs/publications.txt

メールや申請書に貼り付けるときには、プレーンテキスト出力が便利です。

テンプレートを編集する

出力フォーマットを変えたい場合は、templates/ 以下の .j2 ファイルを編集します。

templates/
├── publications.md.j2
├── publications.html.j2
└── publications.txt.j2

例えば、Markdownで著者、タイトル、雑誌名、年を出すなら、テンプレートでは次のような書き方になります。

{% for section in sections %}
## {{ section.name }}

{% for item in section.records %}
- {{ item.authors | join(", ") }}, "{{ item.title }}", {{ item.venue }}, {{ item.year }}.
{% endfor %}

{% endfor %}

テンプレート側では、Notion APIの生データではなく、正規化済みの値を使います。

よく使う値は次のようなものです。

item.title
item.authors
item.type
item.venue
item.publication_date
item.year
item.volume
item.issue
item.pages
item.doi
item.place
item.duration_text_ja
item.duration_text_en

ハマりどころ

Notion DBを共有していない

integrationを作っても、DB側でそのintegrationにアクセス権を付けていないとAPIから読めません。

この場合、API側では「存在しない」ように見えることがあります。Publications DBと Authors DBの両方にintegrationを追加してください。

database_idが間違っている

NotionのURLからIDを取るときに、余計なクエリ文字列やハイフンの扱いで間違えることがあります。うまく読めない場合は、まずDB retrieveだけを試すと切り分けしやすいです。

relation先の著者名が取れない

Authors list をrelationにした場合、Publications DB側には関連先ページIDが入ります。著者名を出すには、関連先のAuthors DBページを読む必要があります。

この処理はスクリプト側で AuthorResolver のような形に分けておくと見通しがよいです。

フォーマット変更のために毎回fetchしてしまう

Notionのデータが変わっていないなら、毎回fetchする必要はありません。テンプレートの修正だけなら、既存の cache/publications.json を使って render だけ実行すれば十分です。

次回: researchmap CSV連携

この記事では、Notionを正本にしてMarkdown/HTML/TXTを出力するところまでを扱いました。

次回は、同じNotion DBからresearchmap V2 CSVを生成する運用を扱います。特に次の点を説明します。

  • researchmap CSVの基本形式
  • Researchmap ID の管理
  • 初回登録時の insert/merge
  • 次回以降の update/doc
  • researchmap export CSVとの照合
  • Researchmap IDのNotionへの書き戻し

まとめ

Notionを研究業績の正本にしておくと、Webサイト、Markdown CV、プレーンテキストなどを同じデータから生成できます。

この運用のポイントは次の通りです。

  • Notion DBを正本にする
  • Notion APIで取得したデータを中間JSONにする
  • 出力形式はJinja2テンプレートで管理する
  • フォーマット変更時は render だけやり直す

研究業績は何度も使い回す情報なので、一度この流れを作っておくと、更新作業がかなり楽になります。
Python側のスクリプトは何度か作り直してきましたが、Notion Databaseを正本にしてAPI経由で取得・出力する、という骨組み自体は数年使ってみても安定しており、個人的にはかなり扱いやすい運用だと感じています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?