はじめまして。さきがけデジタルの越高です。私は、いろいろな言語でプログラムを書いています。このサイトも、AstroとmicroCMSを使って構築しました(これについては、後日改めて語れればと思っています)。
「Notionからデータをローカル環境に取ってこれる?その後、サーバーにアップロードしたいんだけど」という話がありました。調べるとPowerShellでできそうです。ただ、PowerShellは触ったことがなかったため、基礎からデータ取得まで苦戦しました。
ここでは、PowerShell初心者が、NotionAPIを使ってデータを取得するまでの過程をまとめました。「PowerShellは初めて🔰」という人の、お役に立てれば幸いです。
やりたかったこと
- NotionAPIを使って、データを取得しCSV化する
- CSVをSFTPでアップロードする
- 上の内容を、batファイルで実行できるようにする
※今回は、CSV化までの内容を書きます
とても参考になったサイト
この参考サイトをなぞっていくと、データを取得するまでは問題なくできます。 ただ、取得したデータから、必要な値をどうやって取り出していいのか、「知識なし」だと苦戦しました。
まずは手を動かしてみる
まずは、Notionに適当なデータベース(DB)を作成します。
そこに、NotionインテグレーションでAPI用の設定をします。
ざっくりとした手順は「Notionインテグレーションを作る→DBにコネクトする」です。
もし、親DBがあって、そこから絞り込みで子に表示している場合は、親DBにコネクトしてください。
詳しくは、Notionのサイトなどを参照します。
ここまで来て思いました。
🤔 PowerShellってどうやって実行するの? ※実行環境は、Windows10
🤔 とりあえずコマンドプロンプト立ち上げて、参考サイトの内容を貼って…いや、無理か
🤔 コマンドプロンプトに「powershell」と入力して起動。最低限のコードを書いて実行すると、次の値が返ってきた。
お、できそうな感じの値が返ってきたぞ…! ここから進められそうです!
この後、実行方法をChatGPTに聞くと、「拡張子が『.ps1』のファイルをbatファイルで実行すると動く」ということが分かりました。
ここまで分かったので、後は知っている知識とChatGPTをフル活用して、実行できるものを作っていきます。
Notion APIで取得したデータの取り出し方
PowerShellで細かく書いていく前に、事前知識として、Notionから取得したデータはどう扱うのか?について書こうと思います。が、説明するよりもコードを見てもらった方が早いと思います。
過去に類似案件で、Google App Script(GAS)でプログラムを書いていました。
GASでは、値はこんな感じで取り出して使うことができます。
//---取得部分は省略
//取得結果をdataに入れて、値を取り出して表示する
for (i=0; i< data.results.length;i++){
record = data.results[i];
Logger.log("店名:" + record.properties.店名.rich_text[0].text.content);
Logger.log("商品名:" + record.properties.商品名.title[0].plain_text);
Logger.log("開始日:" + record.properties.start.date.start);
Logger.log("終了日:" + record.properties.end.date.start);]
Logger.log("status:" + record.properties.Status.select);
}
詳しくは、APIリファレンスを参照してください。
PowerShellに挑戦!
GASで、ある程度、事前知識があったものの、PowerShellでどう実装するのかが分からない💦
「System.Objectって何?」「PowerShellだとどうやって取り出すんだ?」「@()って何?」というレベル😱
ここでもChatGPT様に大変お世話になりました m(_ _)m
$NotionAPIKey="APIシークレットキー(Notionインテグレーションのページからコピペ)"
$DatabaseID="データベースID(取得したいDBのID)"
$APIURL = "https://api.notion.com/v1/databases/"+$DatabaseID+"/query"
$Notionheaders = @{
"Authorization" = "Bearer $($NotionAPIKey)"
"Content-type" = "application/json"
"Notion-Version" = "2022-06-28"
}
$JsonBody = ""
$Return = Invoke-RestMethod -Uri $APIURL -Method POST -Headers $Notionheaders -Body $JsonBody
$data = @(
[PSCustomObject]@{item='商品名'; category='カテゴリー'}
)
# 必要な情報を取り出して配列に格納していく
for($i = 0; $i -lt $Return.results.properties.Count; $i++) {
$item = $Return.results.properties[$i]."商品名".title.plain_text
$category = $Return.results.properties[$i]."カテゴリー".select.name
$newElement = [PSCustomObject]@{item=$item; category=$category}
$data += $newElement
}
# CSV出力
$data | Export-Csv -Path "output.csv" -Encoding UTF8 -NoTypeInformation
↓これを実行するには、batファイルが必要↓
PowerShell を実行するためのbatファイルの中身(実行するだけ用)
@echo off
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0test.ps1"
pause
※PowerShellファイルとbatファイルは、同じディレクトリに置く
Property値の中身がわからない…どうしたか
プロパティ値が分からない時、「まずは値を出力してみよう」と思ったんですが…
😇どうやって値を画面に出力するの??
ChatGPT先生~~~!!
#中略
$Return = Invoke-RestMethod -Uri $APIURL -Method POST -Headers $Notionheaders -Body $JsonBody
for($i = 0; $i -lt $Return.results.properties.Count; $i++) {
# 例えば、掲載終了のPropertyわからない場合
$end = $Return.results.properties[$i]."掲載終了"
#$endの中身が出力されます
$end
#型のようなものが出力されます
$Return.results.properties[$i]."掲載終了".getType()
}
#----------------------------
#該当部分の出力結果
#----------------------------
# $end = $Return.results.properties[$i]."掲載終了"
id type date
-- ---- ----
WYkx date @{start=2021-10-27; end=; time_zone=}
#------------
# $Return.results.properties[$i]."掲載終了".getType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False PSCustomObject System.Object
※「$end」直書きしていますが、出力するための関数的なものはあるようです。
…「PSCustomObject」って何??
あ、でもdateには「@{start=2021-10-27; end=; time_zone=}」が入っている?ということは、GASでやった感じでなぞってみるとできるのかな?と、仮定して、やってみました。
NotionAPIは、1リクエストあたり100件まで
ひとまず値を取り出せたので、いろいろできるようになったところで、
「そういえばNotionAPIって1リクエストあたり100件までしか取れなかったなあ」と思い出しました。
★「今日の日付」と「掲載開始」「掲載終了」を比較して、フィルターを設定して取得するしかなさそう🤔
GASだと、こんな感じで書いてました。
//掲載開始日と終了日のフィルタで絞り込みます。
const query = {
filter: {
"or":[
{
"property": "掲載終了",
"date": {
equals: yesterday,
}
},
{
"property": "掲載開始",
"date": {
equals: tomorrow,
}
}
]
},
};
※参考資料
Filterオブジェクトの値を取得できず…(理由は不明)
まずは、テスト用のDBはこちらです
👇️実行したPowerShell
$APIURL = "https://api.notion.com/v1/databases/"+$DatabaseID+"/query"
$Notionheaders = @{
"Authorization" = "Bearer $($NotionAPIKey)"
"Content-type" = "application/json"
"Notion-Version" = "2022-06-28"
}
$today = Get-Date -Format "yyyy-MM-dd"
$JsonBody = @"
{
"filter": {
"and":[{
"property": "掲載終了",
"date": {
"on_or_before": "$today"
}
},
{
"property": "掲載開始",
"date": {
"on_or_after": "$today"
}
}]
}
}
"@
$Return = Invoke-RestMethod -Uri $APIURL -Method POST -Headers $Notionheaders -Body $JsonBody
for($i = 0; $i -lt $Return.results.properties.Count; $i++) {
$item = $Return.results.properties[$i]."商品名".title.plain_text
$start = $Return.results.properties[$i]."掲載開始".date.start
$end = $Return.results.properties[$i]."掲載終了".date.start
$shop = $Return.results.properties[$i]."店名".rich_text.plain_text
$newElement = [PSCustomObject]@{shop=$shop ;item=$item; start=$start; end=$end}
$newElement
}
Invoke-RestMethod : {"object":"error","status":400,"code":"validation_error","message":"Could not find property with na
me or id: ????","request_id":""}
発生場所 行:33 文字:15
(以下省略)
「Could not find property with name or id」…つまり「このプロパティ値的なものがない?」 idの後ろの「????」ってどういう意味なのか。
🤔 発生場所から推測して「掲載開始」「掲載終了」のPropertyが取れてない?
ほぼ半日悩んで、結論
「DB側のプロパティをアルファベットにしないと反応しない」ことが分かりました💡
※文字コードを指定すると読み込めるかもしれませんが、そこまでの余裕はありませんでした
#Notionからデータを取ってくる
$NotionAPIKey="シークレットキー"
$DatabaseID="データベースID"
$APIURL = "https://api.notion.com/v1/databases/"+$DatabaseID+"/query"
$Notionheaders = @{
"Authorization" = "Bearer $($NotionAPIKey)"
"Content-type" = "application/json"
"Notion-Version" = "2022-06-28"
}
$today = Get-Date -Format "yyyy-MM-dd"
$JsonBody = @"
{
"filter": {
"and":[{
"property": "start",
"date": {
"on_or_before": "$today"
}
},
{
"property": "end",
"date": {
"on_or_after": "$today"
}
}]
}
}
"@
$Return = Invoke-RestMethod -Uri $APIURL -Method POST -Headers $Notionheaders -Body $JsonBody
for($i = 0; $i -lt $Return.results.properties.Count; $i++) {
$item = $Return.results.properties[$i]."商品名".title.plain_text
$start = $Return.results.properties[$i]."start".date.start
$end = $Return.results.properties[$i]."end".date.start
$shop = $Return.results.properties[$i]."shop".rich_text.plain_text
$newElement = [PSCustomObject]@{shop=$shop ;item=$item; start=$start; end=$end}
$newElement
}
shop item start end
---- ---- ----- ---
A店 ちけっとAあ 2021-09-02 2024-08-31
C店 チケットC 2021-10-07 2024-08-31
test チケットA 2021-09-01 2024-08-31
できた!
後は整えて…
🎉🎉やっと完成🎉🎉
#Notionからデータを取ってくる
$NotionAPIKey="シークレットキー"
$DatabaseID="データベースID"
$APIURL = "https://api.notion.com/v1/databases/"+$DatabaseID+"/query"
$Notionheaders = @{
"Authorization" = "Bearer $($NotionAPIKey)"
"Content-type" = "application/json"
"Notion-Version" = "2022-06-28"
}
#きょうの日付
$today = Get-Date -Format "yyyy-MM-dd"
$JsonBody = @"
{
"filter": {
"and":[{
"property": "start",
"date": {
"on_or_before": "$today"
}
},
{
"property": "end",
"date": {
"on_or_after": "$today"
}
}]
}
}
"@
$Return = Invoke-RestMethod -Uri $APIURL -Method POST -Headers $Notionheaders -Body $JsonBody
#出力用の配列を作成
$data = @()
for($i = 0; $i -lt $Return.results.properties.Count; $i++) {
$item = $Return.results.properties[$i]."商品名".title.plain_text
$start = $Return.results.properties[$i]."start".date.start
$end = $Return.results.properties[$i]."end".date.start
$shop = $Return.results.properties[$i]."店名".rich_text.plain_text
$newElement = [PSCustomObject]@{shop=$shop ;item=$item; start=$start; end=$end}
$data += $newElement
}
#中身を表示
$data
#csv出力
$data | Export-Csv -Path "output.csv" -Encoding UTF8 -NoTypeInformation
※CSV出力の部分は、ChatGPTに質問して書き方を教えてもらいました
後は、ローカルのファイルを、SFTPなどでアップロードすればOKかと思います。
おわりに
「PowerShell 正直難しそうだな」と思って、これまで手を出すのを渋っていました。 でも、今回やってみて「あ、これなら私でもやれそうかも」と思いました。 ChatGPTという「頼りになるオトモ」も解禁させてもらい、なんとか漕ぎつくことができました。
私のように「PowerShell使える?」「Notion連携できる?」と、聞かれて困ってしまった人のお役に立てたらうれしいです!