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上にあるデータを取得できる。
ということで、以下のようなシステムを作った。
- Google MapのURLをSlackに投稿 (Google Mapアプリからの共有など)
- Slack webhook経由でGAS起動
- Google Maps APIで店舗情報を取得
- 取得した情報をNotion DBに保存
- Notionへの保存が完了したらSlackに通知
GASのコードは以下
※ GAS上で作成+編集して後でリポジトリ作ったので、TypeScriptでもないしフォーマットも適当……
適当にポイント解説
短縮URLの展開
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データの取得
Places APIでデータを検索する際、必要なフィールドのみを指定して取得できる。
Notion DBに保存するのに必要なフィールドを、 X-Goog-FieldMask
ヘッダーに指定している。
Slack Event API の複数回実行による重複データ作成を防止
SlackのEvent APIは、実行の確実性のためにイベントを複数回実行することがある。
ref: https://api.slack.com/apis/events-api#retries
当然その度にWebhookも発火し、何も対処しなければ同じ店舗データが複数作成されることになる。
対策として、イベントが複数回実行されてもイベントIDは変わらないことを利用する。
GAS上のスクリプトキャッシュに期限付きでイベントIDを保存し、それが存在する期間は同じイベントIDを持つイベントを無視している。
すでに登録済みの店舗の重複データ作成を防止
過去に同じ店舗を登録済みの場合を考慮して、DBへの保存前に店舗データを検索し、すでにデータがある場合は登録処理をスキップしている。
実行してみる
作ったGASのURLをSlack AppのEvent Subscriptionsに登録し、SlackにGoogle MapのURLを投下してみる。
ちゃんとレスポンスが返ってきた。
DBにも保存できてる。
もう一度同じURLを投下してみると……
重複処理もちゃんと動いてる。
おわりに
各APIの4xx系エラーの対処や諸々リファクタリング等、まだまだ足りないところはあるものの、ひとまずやりたいことは実現できた。
GASのログをGCのログエクスプローラに流してのデバッグ、Webhook重複実行の対処等、勉強になる部分もあった。
ある程度店舗データが貯まったら、今度はそれをAIに食わせて、いい感じに店の提案をしてくれるアプリでも作るか。
Discussion