【PowerShell初心者向け🔰】はじめてのPowerShellで、Notionからデータを取り出してみた

はじめまして。さきがけデジタルの越高です。私は、いろいろな言語でプログラムを書いています。このサイトも、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連携できる?」と、聞かれて困ってしまった人のお役に立てたらうれしいです!

越髙佑芽さんのプロフィール画像
越髙佑芽

キャベツいっぱい食べたいなぁ…

大学院では新聞の自動切り抜きシステムを研究。入社後はプログラム開発を担当。サメ映画とポケモンが好き。

こんな記事もあります

お問い合わせ

ウェブ制作や「ふるさと電報」に関するお問い合わせ、ご相談などお気軽にご連絡ください。お見積りは無料で作成いたします。