🍽️

Google Map上のレストラン情報をNotion DBに保存するGAS

に公開

店舗情報をNotion DBで管理したい

レストランや居酒屋など、もう一度行きたいと思った飲食店にはGoogle Map上でスターを付けていた。
ただその数が増えてくると、一覧を見ただけでは店の詳細が思い出せなくなってきた。
店の位置やURL等の情報とともに、自分用のメモも添えてデータとして残しておきたい。

ということで、NotionにDBテーブルを作ってデータを貯めることにした。
テーブルのカラムはとりあえずこんな感じにした。

カラム名 説明
name 店名
url 店のURL
map_url Google Map上のURL
address 住所
genre ジャンル
visited 訪れた日
memo 自分用メモ

このうち name, url, map_url, address, visited 辺りはGoogle Map上のデータをそのまま使えるが、そのデータを手動でパースして手動でDBに追加するのはとてもダルい。
幸いNotionには公開APIがあり、それを通してDBへのデータ追加ができる。
またGoogleにも Places API というものがあり、これを通してGoogle Map上にあるデータを取得できる。

ということで、以下のようなシステムを作った。

  1. Google MapのURLをSlackに投稿 (Google Mapアプリからの共有など)
  2. Slack webhook経由でGAS起動
  3. Google Maps APIで店舗情報を取得
  4. 取得した情報をNotion DBに保存
  5. Notionへの保存が完了したらSlackに通知

GASのコードは以下
※ GAS上で作成+編集して後でリポジトリ作ったので、TypeScriptでもないしフォーマットも適当……
https://github.com/s4kr4/slack-notion-restaurant

適当にポイント解説

短縮URLの展開

https://github.com/s4kr4/slack-notion-restaurant/blob/96c73a145334e063696772369732f64069bf50fd/maps.js#L52-L64

Places APIでは、店名を元に店を検索してPlaceデータを取得する。
元になる店名は、Google MapのURLから抽出する。

例えば以下のURLなら、 .../place/ の後の 叙々苑 新宿歌舞伎町店 が店名となる。
https://www.google.co.jp/maps/place/叙々苑 新宿歌舞伎町店/@XX.XXXXXX,XXX.../data=!XXXXXX!XXXXXXX...

Google Mapアプリ等からURLを共有しようとすると短縮URLしか取得できないので、メイン処理の前にURLを展開している。

フィールドを絞ったPlaceデータの取得

https://github.com/s4kr4/slack-notion-restaurant/blob/96c73a145334e063696772369732f64069bf50fd/maps.js#L20-L49

Places APIでデータを検索する際、必要なフィールドのみを指定して取得できる。
Notion DBに保存するのに必要なフィールドを、 X-Goog-FieldMask ヘッダーに指定している。

Slack Event API の複数回実行による重複データ作成を防止

https://github.com/s4kr4/slack-notion-restaurant/blob/96c73a145334e063696772369732f64069bf50fd/main.js#L8-L16

SlackのEvent APIは、実行の確実性のためにイベントを複数回実行することがある。
ref: https://api.slack.com/apis/events-api#retries

当然その度にWebhookも発火し、何も対処しなければ同じ店舗データが複数作成されることになる。

対策として、イベントが複数回実行されてもイベントIDは変わらないことを利用する。
GAS上のスクリプトキャッシュに期限付きでイベントIDを保存し、それが存在する期間は同じイベントIDを持つイベントを無視している。

すでに登録済みの店舗の重複データ作成を防止

https://github.com/s4kr4/slack-notion-restaurant/blob/96c73a145334e063696772369732f64069bf50fd/notion.js#L1-L29
https://github.com/s4kr4/slack-notion-restaurant/blob/96c73a145334e063696772369732f64069bf50fd/notion.js#L33-L37

過去に同じ店舗を登録済みの場合を考慮して、DBへの保存前に店舗データを検索し、すでにデータがある場合は登録処理をスキップしている。

実行してみる

作ったGASのURLをSlack AppのEvent Subscriptionsに登録し、SlackにGoogle MapのURLを投下してみる。


ちゃんとレスポンスが返ってきた。


DBにも保存できてる。

もう一度同じURLを投下してみると……

重複処理もちゃんと動いてる。

おわりに

各APIの4xx系エラーの対処や諸々リファクタリング等、まだまだ足りないところはあるものの、ひとまずやりたいことは実現できた。
GASのログをGCのログエクスプローラに流してのデバッグ、Webhook重複実行の対処等、勉強になる部分もあった。

ある程度店舗データが貯まったら、今度はそれをAIに食わせて、いい感じに店の提案をしてくれるアプリでも作るか。

Discussion