PythonでNotion API(Public Beta)を叩いてみます。
概要
2021年5月にNotionのAPIが公開されました。これ以前はnotin-pyなど非公式のAPIを使う他ありませんでした。Public
Betaの段階ですが、公式APIを使ってNotionを操作するための日本語の情報が少ないため、簡単に記述していきます。詳細の確認は英語ですが公式ドキュメントがとても役立ちます。
現時点でNotionは日本語対応していないため、Notionの言語は英語の状態で手順を記載します。
準備
Installation
pipなどでnotion-client
を導入します。
pip install notion-client
Integrations
https://www.notion.so/my-integrationsからIntegrationを作成します。notion-client
で作成したIntegrationを使い、Notion
APIを叩きます。
手順
- ページにアクセスする
- [New integration]をクリックする
-
フォームに値を入力する
- Integration名を入力する(e.g. myIntg)
- アイコンを設定する(任意)
- APIで操作するWorkspacesを選択する
-
[Submit]をクリックする
一連の操作を終えると、Tokenが発行されます。[Secret]のInternal Integration Token
のテキストボックスをクリックすると、Tokenを表示できます。もう一度、クリックしてTokenをCopyしてください。
コピーしたTokenは環境変数NOTION_TOKEN
にセットするか、メモ帳などに貼り付けるかしてください。
Integration Invitations(重要)
Integrationを作成しましたが、作成したままの状態だとAPIを十分に使用できません。Workspacesにアクセスして、以下の手順で操作の準備をします。
- APIで操作したいページを選択する
- 画面上部のバーからShareをクリックする
- [Invite]をクリックする
- 作成したIntegrationをクリックする
- [Invite]をクリックする
操作のあと、Shareの一覧に作成したIntegrationが表示されたら、そのページをAPI経由で操作できるようになります。
PythonでAPIの認証をする
PythonでAPIを操作する準備をします。以下のコードで認証します。
import os
from notion_client import Client
token: str = os.environ.get("NOTION_TOKEN", "yourToken")
notion = Client(auth=token)
公式ドキュメントに従って、環境変数を使ってtokenの入力をします。環境変数がよくわからなかったり、os.environ
の箇所でエラーが出てしまう場合には、"yourToken"
をメモ帳などに貼り付けたTokenに書き換えて再実行してください(この時、GitHubなどにTokenをシェアしてしまわないようご注意ください)。
ErrorのResponseがなければ、一旦APIの認証が完了となります。
ユーザー情報を取得する(UserEndpoint)
準備の最終段階として、UsersEndpointをつかってユーザー情報の取得をします。
>>> from pprint import pprint
>>>
>>> list_users_response = notion.users.list()
>>> pprint(list_users_response)
{'has_more': False,
'next_cursor': None,
'object': 'list',
'results': [{'avatar_url': 'https://lh3.googleusercontent.com/a-/HOGEHOGE',
'id': '323343xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'name': 'yourName',
'object': 'user',
'person': {'email': 'yourAddress@gmail.com'},
'type': 'person'},
{'avatar_url': None,
'bot': {},
'id': '323343xx-yyyy-yyyy-yyyy-xxxxxxxxxxxx,
'name': 'myIntg',
'object': 'user',
'type': 'bot'},
]}
ID
NotionのAPIを使うときに、IDで操作の対象を指定します。URLからある程度IDを確認できます。Page IDより下位にあるIDはAPIを叩いたり、ChromeのDeveloperツールなどから確認したりなどが必要となります。
https://www.notion.so/1349f9e927674a03a87d772483dd5b1b?v=05282e02290749fd95decb0df0dc3f5c&p=de3635356a224c569f103a2038dc3521
|--------- Database ID ---------| |--------- Page ID ------------|
APIをつかう
SearchEndpoint
SearchEndpointでは、ページやデータベースの検索ができます。Query引数に検索した文字を入力すると、一致したページやデータベースを返してくれます。
>>> from pprint import pprint
>>>
>>> ret = notion.search(query="My", )
>>> pprint(ret)
{'has_more': False,
'next_cursor': None,
'object': 'list',
'results': [{'archived': False,
'created_time': '2021-06-26T05:29:00.000Z',
'id': '65431967-c345-4c73-94eb-089c7781874f',
'last_edited_time': '2021-06-27T02:37:36.229Z',
'object': 'page',
'parent': {'type': 'workspace', 'workspace': True},
'properties': {'title': {'id': 'title',
'title': [{'annotations': {'bold': False,
'code': False,
'color': 'default',
'italic': False,
'strikethrough': False,
'underline': False},
'href': None,
'plain_text': 'MyTask',
'text': {'content': 'MyTask',
'link': None},
'type': 'text'}],
'type': 'title'}}}]}
DatabasesEndpoint
DatabasesEndpointでデータベース周りの操作ができます。
list
データベースの一覧とデータベースの定義を取得できます。データベースの定義は、API(Query)を使って値を更新する際に役立ちます。
>>> ret = notion.databases.list()
>>> pprint(ret)
{'has_more': False,
'next_cursor': None,
'object': 'list',
'results': [{'created_time': '2021-06-26T04:01:53.032Z',
'id': '1349f9e9-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'last_edited_time': '2021-06-27T02:37:36.229Z',
'object': 'database',
'parent': {'type': 'workspace', 'workspace': True},
'properties': {'Created': {'created_time': {},
'id': 's]Ff',
'type': 'created_time'},
'Favorite': {'checkbox': {},
'id': 'VQ{u',
'type': 'checkbox'},
'Name': {'id': 'title',
'title': {},
'type': 'title'},
'Notion': {'id': 'ta`F',
'rich_text': {},
'type': 'rich_text'},
'Tags': {'id': '{OB\\',
'multi_select': {'options': [{'color': 'pink',
'id': 'fd33a0a5-yyyy-yyyy-yyyy-yyyyyyyyyyyy',
'name': 'Notion'},
{'color': 'red',
'id': '035c85d1-zzzz-zzzz-zzzz-zzzzzzzzzzzz',
'name': 'Python'},
{'color': 'green',
'id': 'b8f93b98-aaaa-aaaa-aaaa-aaaaaaaaaaaa',
'name': 'DLL'},
{'color': 'green',
'id': '38341073-bbbb-bbbb-bbbb-bbbbbbbbbbbb',
'name': 'GoLang'},
{'color': 'brown',
'id': 'b77ec500-cccc-cccc-cccc-cccccccccc',
'name': 'API'},
{'color': 'blue',
'id': 'f0613703-dddd-dddd-dddd-dddddddddddd',
'name': 'Swift'}]},
'type': 'multi_select'},
'URL': {'id': 'b;Si', 'type': 'url', 'url': {}}},
'title': [{'annotations': {'bold': False,
'code': False,
'color': 'default',
'italic': False,
'strikethrough': False,
'underline': False},
'href': None,
'plain_text': 'WebClips',
'text': {'content': 'WebClips', 'link': None},
'type': 'text'}]},
{'created_time': '2021-06-26T13:02:55.254Z',
'id': '9da953b5-dddd-dddd-dddd-dddddddddddd',
'last_edited_time': '2021-06-27T03:36:00.000Z',
'object': 'database',
'parent': {'type': 'workspace', 'workspace': True},
'properties': {'Created': {'created_time': {},
'id': ']r?p',
'type': 'created_time'},
'Ebook': {'checkbox': {},
'id': 'An=Z',
'type': 'checkbox'},
'Favorite': {'checkbox': {},
'id': 'iHkR',
'type': 'checkbox'},
'Name': {'id': 'title',
'title': {},
'type': 'title'},
'Rate': {'id': '\\Lit',
'select': {'options': [{'color': 'red',
'id': '64d85ca2-eeee-eeee-eeee-eeeeeeeeeeee',
'name': '5'},
{'color': 'pink',
'id': '2ec6eb09-ffff-ffff-ffff-ffffffffffff',
'name': '4'},
{'color': 'gray',
'id': 'e86ef2d6-gggg-gggg-gggg-gggggggggggg',
'name': '3'},
{'color': 'purple',
'id': '10c2e5f8-hhhh-hhhh-hhhh-hhhhhhhhhhhh',
'name': '2'},
{'color': 'green',
'id': '75aeb67c-iiii-iiii-iiii-iiiiiiiiiiii',
'name': '1'}]},
'type': 'select'},
'Tags': {'id': 'bdzl',
'select': {'options': [{'color': 'blue',
'id': '3d2d9f81-jjjj-jjjj-jjjj-jjjjjjjjjjjj',
'name': 'Bought'},
{'color': 'orange',
'id': '98f3d800-gggg-gggg-gggg-gggggggggg',
'name': 'Read'},
{'color': 'red',
'id': 'cdbbc5aa-kkkk-kkkk-kkkk-kkkkkkkkkkkk',
'name': 'Reviewd'},
{'color': 'pink',
'id': 'b534b43e-llll-llll-llllllllllll',
'name': 'Reading'},
{'color': 'yellow',
'id': '12863085-mmmm-mmmm-mmmm-mmmmmmmmmmmm',
'name': 'Pending'}]},
'type': 'select'},
'URL': {'id': 'DFAE', 'type': 'url', 'url': {}}},
'title': [{'annotations': {'bold': False,
'code': False,
'color': 'default',
'italic': False,
'strikethrough': False,
'underline': False},
'href': None,
'plain_text': 'Bookshelf',
'text': {'content': 'Bookshelf', 'link': None},
'type': 'text'}]}]}
query
queryを使うとデータベースの行を抽出できます。filterは別途ドキュメントがあり、列のTypeごとにFilter方法などが記載されています。以下は、指定のdatabase_idのTags列(multi_select型)に値Swift
が含まれているレコードを抽出するクエリです。
>>> ret = notion.databases.query(
... **{
... "database_id": "1349f9e927674a03a87d772483dd5b1b",
... "filter": {
... "property": "Tags",
... "multi_select": {
... "contains": "Swift"
... }
... }
... }
... )
>>> pprint(ret)
{'has_more': False,
'next_cursor': None,
'object': 'list',
'results': [{'archived': False,
'created_time': '2021-06-26T05:33:23.002Z',
'id': 'd74a8d3e-73c0-4d04-817a-897192fbfb2e',
'last_edited_time': '2021-06-26T05:33:00.000Z',
'object': 'page',
'parent': {'database_id': '1349f9e9-2767-4a03-a87d-772483dd5b1b',
'type': 'database_id'},
'properties': {'Created': {'created_time': '2021-06-26T05:33:23.002Z',
'id': 's]Ff',
'type': 'created_time'},
'Favorite': {'checkbox': False,
'id': 'VQ{u',
'type': 'checkbox'},
'Name': {'id': 'title',
'title': [{'annotations': {'bold': False,
'code': False,
'color': 'default',
'italic': False,
'strikethrough': False,
'underline': False},
'href': None,
'plain_text': 'noppefoxwolf/notion: '
'noppefoxwolf/notion '
'is a notion.so '
'API library '
'written in '
'swift.',
'text': {'content': 'noppefoxwolf/notion: '
'noppefoxwolf/notion '
'is a '
'notion.so '
'API '
'library '
'written '
'in '
'swift.',
'link': None},
'type': 'text'}],
'type': 'title'},
'Notion': {'id': 'ta`F',
'rich_text': [],
'type': 'rich_text'},
'Tags': {'id': '{OB\\',
'multi_select': [{'color': 'pink',
'id': 'fd33a0a5-5c7a-469d-aafc-168106a15208',
'name': 'Notion'},
{'color': 'brown',
'id': 'b77ec500-aed1-45b0-be10-06a38973273f',
'name': 'API'},
{'color': 'blue',
'id': 'f0613703-e876-4dbd-8ff3-2f08f158d07e',
'name': 'Swift'}],
'type': 'multi_select'},
'URL': {'id': 'b;Si',
'type': 'url',
'url': 'https://github.com/noppefoxwolf/notion'}}}]}
Query内の辞書の前についている**
は辞書のアンパックです。以下と同じになります。
ret = notion.databases.query(
database_id="1349f9e927674a03a87d772483dd5b1b",
filter={
"property": "Tags",
"multi_select": {
"contains": "Swift"
}
}
)
retrieve
database_idに対応するデータベースの情報を取得します。IDが必要となりますが、単一のデータベースの情報を取得でき、シンプルな構造となる点で便利です。
>>> ret = notion.databases.retrieve(database_id="1349f9e927674a03a87d772483dd5b1b")
>>> pprint(ret)
{'created_time': '2021-06-26T04:01:53.032Z',
'id': '1349f9e9-2767-4a03-a87d-772483dd5b1b',
'last_edited_time': '2021-06-27T02:37:36.229Z',
'object': 'database',
'parent': {'type': 'workspace', 'workspace': True},
'properties': {'Created': {'created_time': {},
'id': 's]Ff',
'type': 'created_time'},
'Favorite': {'checkbox': {}, 'id': 'VQ{u', 'type': 'checkbox'},
'Name': {'id': 'title', 'title': {}, 'type': 'title'},
'Notion': {'id': 'ta`F', 'rich_text': {}, 'type': 'rich_text'},
'Tags': {'id': '{OB\\',
'multi_select': {'options': [{'color': 'pink',
'id': 'fd33a0a5-5c7a-469d-aafc-168106a15208',
'name': 'Notion'},
{'color': 'red',
'id': '035c85d1-e9a0-4b40-9f7b-0f78516b084f',
'name': 'Python'},
{'color': 'green',
'id': 'b8f93b98-2f81-4e4f-913a-9e355aef267c',
'name': 'DLL'},
{'color': 'green',
'id': '38341073-3d35-46f3-84bc-baeab8d3093f',
'name': 'GoLang'},
{'color': 'brown',
'id': 'b77ec500-aed1-45b0-be10-06a38973273f',
'name': 'API'},
{'color': 'blue',
'id': 'f0613703-e876-4dbd-8ff3-2f08f158d07e',
'name': 'Swift'}]},
'type': 'multi_select'},
'URL': {'id': 'b;Si', 'type': 'url', 'url': {}}},
'title': [{'annotations': {'bold': False,
'code': False,
'color': 'default',
'italic': False,
'strikethrough': False,
'underline': False},
'href': None,
'plain_text': 'WebClips',
'text': {'content': 'WebClips', 'link': None},
'type': 'text'}]}
PagesEndpoint
ページの操作ができます。
create
pageに値を追加できます。以下はページ内のテーブルに値を追加するコードです。propertiesの設定方法はドキュメントをご確認ください。
>>> ret = notion.pages.create(
... **{
... "parent": {"database_id": "1349f9e927674a03a87d772483dd5b1b"},
... "properties": {
... "Name": {
... "title": [
... {
... "text": {
... "content": "TEST"
... }
... }
... ]
... },
... "URL": {
... "url": "https://google.com"
... },
... "Favorite": {
... "checkbox": True
... },
... "Tags": {
... "multi_select": [
... {"name": tag} for tag in "Python,API".split(",")
... ]
... }
... }
... }
... )
>>> pprint(ret)
{'archived': False,
'created_time': '2021-06-27T05:18:59.743Z',
'id': 'de363535-6a22-4c56-9f10-3a2038dc3521',
'last_edited_time': '2021-06-27T05:18:59.743Z',
'object': 'page',
'parent': {'database_id': '1349f9e9-2767-4a03-a87d-772483dd5b1b',
'type': 'database_id'},
'properties': {'Created': {'created_time': '2021-06-27T05:18:59.743Z',
'id': 's]Ff',
'type': 'created_time'},
'Favorite': {'checkbox': True,
'id': 'VQ{u',
'type': 'checkbox'},
'Name': {'id': 'title',
'title': [{'annotations': {'bold': False,
'code': False,
'color': 'default',
'italic': False,
'strikethrough': False,
'underline': False},
'href': None,
'plain_text': 'TEST',
'text': {'content': 'TEST', 'link': None},
'type': 'text'}],
'type': 'title'},
'Tags': {'id': '{OB\\',
'multi_select': [{'color': 'red',
'id': '035c85d1-e9a0-4b40-9f7b-0f78516b084f',
'name': 'Python'},
{'color': 'brown',
'id': 'b77ec500-aed1-45b0-be10-06a38973273f',
'name': 'API'}],
'type': 'multi_select'},
'URL': {'id': 'b;Si',
'type': 'url',
'url': 'https://google.com'}}}
retrieve
page_idに対応する対象の情報を取得します。
>>> ret = notion.pages.retrieve(page_id="de3635356a224c569f103a2038dc3521")
>>> pprint(ret)
{'archived': False,
'created_time': '2021-06-27T05:18:59.743Z',
'id': 'de363535-6a22-4c56-9f10-3a2038dc3521',
'last_edited_time': '2021-06-27T05:20:00.000Z',
'object': 'page',
'parent': {'database_id': '1349f9e9-2767-4a03-a87d-772483dd5b1b',
'type': 'database_id'},
'properties': {'Created': {'created_time': '2021-06-27T05:18:59.743Z',
'id': 's]Ff',
'type': 'created_time'},
'Favorite': {'checkbox': True,
'id': 'VQ{u',
'type': 'checkbox'},
'Name': {'id': 'title',
'title': [{'annotations': {'bold': False,
'code': False,
'color': 'default',
'italic': False,
'strikethrough': False,
'underline': False},
'href': None,
'plain_text': 'TEST',
'text': {'content': 'TEST', 'link': None},
'type': 'text'}],
'type': 'title'},
'Tags': {'id': '{OB\\',
'multi_select': [{'color': 'red',
'id': '035c85d1-e9a0-4b40-9f7b-0f78516b084f',
'name': 'Python'},
{'color': 'brown',
'id': 'b77ec500-aed1-45b0-be10-06a38973273f',
'name': 'API'}],
'type': 'multi_select'},
'URL': {'id': 'b;Si',
'type': 'url',
'url': 'https://google.com'}}}
update
page_idに対応するpropatiesの値を更新します。
>>> ret = notion.pages.update(
... **{
... "page_id": "de3635356a224c569f103a2038dc3521",
... "properties": {
... "Name": {
... "title": [
... {
... "text": {
... "content": "UPDATE_TEST"
... }
... }
... ]
... }
... }
... }
... )
>>> pprint(ret)
{'archived': False,
'created_time': '2021-06-27T05:18:59.743Z',
'id': 'de363535-6a22-4c56-9f10-3a2038dc3521',
'last_edited_time': '2021-06-27T05:36:47.559Z',
'object': 'page',
'parent': {'database_id': '1349f9e9-2767-4a03-a87d-772483dd5b1b',
'type': 'database_id'},
'properties': {'Created': {'created_time': '2021-06-27T05:18:59.743Z',
'id': 's]Ff',
'type': 'created_time'},
'Favorite': {'checkbox': True,
'id': 'VQ{u',
'type': 'checkbox'},
'Name': {'id': 'title',
'title': [{'annotations': {'bold': False,
'code': False,
'color': 'default',
'italic': False,
'strikethrough': False,
'underline': False},
'href': None,
'plain_text': 'UPDATE_TEST',
'text': {'content': 'UPDATE_TEST',
'link': None},
'type': 'text'}],
'type': 'title'},
'Tags': {'id': '{OB\\',
'multi_select': [{'color': 'red',
'id': '035c85d1-e9a0-4b40-9f7b-0f78516b084f',
'name': 'Python'},
{'color': 'brown',
'id': 'b77ec500-aed1-45b0-be10-06a38973273f',
'name': 'API'}],
'type': 'multi_select'},
'URL': {'id': 'b;Si',
'type': 'url',
'url': 'https://google.com'}}}
BlocksEndpoint
ブロックの編集をします。
list
ブロックのリストを入手します。page_idもしくはblock_idを使います。page_idを使うとページ内のブロックを取得できます。
>>> page_id: str = "098ebc861d35448a9dd725184512e95d"
>>> ret = notion.blocks.children.list(block_id=page_id)
>>> pprint(ret)
{'has_more': False,
'next_cursor': None,
'object': 'list',
'results': [{'created_time': '2021-06-27T06:07:00.000Z',
'has_children': False,
'heading_2': {'text': [{'annotations': {'bold': False,
'code': False,
'color': 'default',
'italic': False,
'strikethrough': False,
'underline': False},
'href': None,
'plain_text': 'Summary',
'text': {'content': 'Summary',
'link': None},
'type': 'text'}]},
'id': 'a64e91a1-facb-46d9-9190-5eb96e13c217',
'last_edited_time': '2021-06-27T06:08:00.000Z',
'object': 'block',
'type': 'heading_2'},
{'created_time': '2021-06-27T06:08:00.000Z',
'has_children': False,
'id': '7428808e-a481-4b0d-9a3d-28ef6a241e4c',
'last_edited_time': '2021-06-27T06:08:00.000Z',
'object': 'block',
'paragraph': {'text': [{'annotations': {'bold': False,
'code': False,
'color': 'default',
'italic': False,
'strikethrough': False,
'underline': False},
'href': None,
'plain_text': 'hogehogehugahugapiyopiyo',
'text': {'content': 'hogehogehugahugapiyopiyo',
'link': None},
'type': 'text'}]},
'type': 'paragraph'},
{'created_time': '2021-06-27T06:08:00.000Z',
'has_children': False,
'id': '9df4b261-8f93-4261-871e-14b9c25d4a2a',
'last_edited_time': '2021-06-27T06:08:00.000Z',
'object': 'block',
'paragraph': {'text': []},
'type': 'paragraph'},
{'created_time': '2021-06-27T06:08:00.000Z',
'has_children': False,
'id': '395347e7-ccdc-450d-ab99-a730dd68dcd7',
'last_edited_time': '2021-06-27T06:08:00.000Z',
'object': 'block',
'paragraph': {'text': []},
'type': 'paragraph'}]}
append
指定したpage_id(block_id)にブロックを追加します。ブロックの定義方法はドキュメントに記載されています。
>>> blocks: list = [
... {
... "object": "block",
... "type": "heading_2",
... "heading_2": {
... "text": [
... {"type": "text", "text": {"content": "H2_TITLE"}}
... ]
... }
... },
... {
... "object": "block",
... "type": "paragraph",
... "paragraph": {
... "text": [
... {
... "type": "text",
... "text": {
... "content": "Hi, This is a test text.",
... "link": {
... "url": "https://google.com"
... }
... }
... }
... ]
... }
... }
... ]
>>> block_id: str = "098ebc861d35448a9dd725184512e95d"
>>> ret = notion.blocks.children.append(block_id=block_id, children=blocks)
>>> pprint(ret)
{'child_page': {'title': 'HOGEHOGE'},
'created_time': '2021-06-27T06:07:00.000Z',
'has_children': True,
'id': '098ebc86-1d35-448a-9dd7-25184512e95d',
'last_edited_time': '2021-06-27T06:12:02.595Z',
'object': 'block',
'type': 'child_page'}
Notion SDK for Pythonを使ってみて
Documentと見比べつつライブラリを使いました。Public Beta時点で使える機能を抑えており、問題なく使えそうに見えます。公式ドキュメントで詳細の確認が必要ですが、多量のデータのimportや入力の自働化など便利に使えそうです。
その他
Upload
FAQに記載されていましたがファイルのアップロードに対応していないようです。現時点で思いつく方法としては、Selenium+AHKで1つずつ上げていくぐらいでしょうか。DropboxAPIのようにBulkでのアップロードの対応に期待します。
他の言語
色々対応していそうです。その中でも、GASでGoogleのアプリと連携させたり、タイムトリガーでNotionAPIを叩くような使い方もできそうで、ちょっと興味があります。多分、記事にしないだろうと思いますが、便利な使い方とかシェアできたらそれはそれで良さそうです。