Excelで最寄り駅を取得するAPIを作る

## 動機
Excel上の大量の緯度経度座標の最寄り駅を一括で調べたかった。
google map platformのPlaces APIを使えば最寄り駅は分かるが、Excelを読み込んで書き込みは使いにくい。
ましてやVBAでAPIを叩くのは面倒。

なので、ExcelのWEBSERVICE関数を使ってAPIを叩きたい。
ただし、Places APIを直接叩くとjsonかxmlで返ってきてしまうので不適切。
よって、Places APIを代わりに叩いてExcel向けにいい感じに返してくれるAPIを作る。

## 構成
ExcelのWEBSERVICE関数を使ってCloud function上に作ったAPIを叩く。
APIはさらにPlace APIを叩いて最寄り駅をもらってExcelに返す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2605106/605a1f90-000c-e059-89c5-f43a57084959.png)

## Place APIを使えるようにする
GCPでプロジェクトを作成し、google map platformでAPIキーを作成する
参考資料はいっぱいあるのでやり方は省略

google map platformの公式ドキュメントはこちら
https://mapsplatform.google.com/intl/ja/

Place APIをEnableにする（多分デフォルトでEnableになってる）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2605106/474c4f08-6420-942f-99cd-0729b30a5644.png)

## コーディング
緯度経度を投げて最寄り駅を返すHTTP関数を作る
keysには取得したAPIキーを入れる

```python
import requests
import json

def nearest(request):
    keys = "***********"
    types = json.load(open('types.json', 'r', encoding="utf-8"))

    type = types.get(request.args.get('type'))
    if type is None:
        return "タイプを正しく選択してください"
    
    lat = request.args.get('lat')
    lon = request.args.get('lon')

    if lat is None or lon is None:
        return "緯度・経度が設定されていません"
    try:
        lat = float(lat)
        lon = float(lon)
    except:
        return "緯度・経度が正しく設定されていません"
    
    base_url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json"
    location = f"{lat},{lon}"

    params = {
        "location": location,
        "type": type,
        "language": "ja",
        "rankby": "distance",
        "key": keys["google_map_api"]
    }

    response = requests.get(base_url, params=params)
    results = response.json()

    if results["status"] == "OK":
        objs = results["results"]
        nearest = objs[0]

        result = nearest["name"] + "," + nearest["vicinity"]
        return result

    else:
        return "検索エラー"
```

今回使用するPlace APIの"nearbysearch"関数は最寄り駅だけでなくいろいろな最寄り施設を検索できる
日本国内で使用できそうな施設一覧を以下のjsonにまとめた
これを3つ目の引数として渡して、与えた緯度経度の最寄りの指定施設を返せるようにする

```json
{
	"空港":"airport",
	"遊園地":"amusement_park",
	"水族館":"aquarium",
	"美術館":"art_gallery",
	"ATM":"atm",
	"パン屋":"bakery",
	"銀行":"bank",
	"バー":"bar",
	"美容院":"beauty_salon",
	"書店":"book_store",
	"バスステーション":"bus_station",
	"カフェ":"cafe",
	"衣料品店":"clothing_store",
	"コンビニエンスストア":"convenience_store",
	"歯科医院":"dentist",
	"デパート":"department_store",
	"ドラッグストア":"drugstore",
	"電気店":"electronics_store",
	"家具店":"furniture_store",
	"ガソリンスタンド":"gas_station",
	"ジム":"gym",
	"ヘアケアサービス":"hair_care",
	"ホームセンター":"hardware_store",
	"病院":"hospital",
	"ランドリー":"laundry",
	"図書館":"library",
	"鍵屋":"locksmith",
	"宿泊施設":"lodging",
	"映画館":"movie_theater",
	"博物館":"museum",
	"公園":"park",
	"駐車場":"parking",
	"ペットショップ":"pet_store",
	"薬局":"pharmacy",
	"警察署":"police",
	"郵便局":"post_office",
	"不動産代理店":"real_estate_agency",
	"レストラン":"restaurant",
	"靴店":"shoe_store",
	"ショッピングモール":"shopping_mall",
	"スパ":"spa",
	"地下鉄駅":"subway_station",
	"スーパーマーケット":"supermarket",
	"タクシー乗り場":"taxi_stand",
	"鉄道駅":"train_station",
	"交通駅":"transit_station",
	"獣医":"veterinary_care"
}
```


## Cloud functionエミュレータの起動
今回は自分だけで使えればよかったので、デプロイせずにエミュレータで作ったAPIを立ち上げて使用した
複数人で使いたければCloud functionにデプロイすればいい


functions-frameworkをインストールする
```
pip install functions-framework
```

作成したAPIのフォルダで以下コマンドを実施
```
functions-framework --target=nearest
```
以下の様にローカル上で実行されていることが示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2605106/6710e93d-b2b2-0f71-6415-6039986abd84.png)

Excelで以下の計算式を実行
latには緯度を、lonには経度を、typeには最寄り検索をしたい施設の日本語名（上記のjsonファイル参照）を入れる
```vb
=WEBSERVICE("http://127.0.0.1:8080?lat="&ENCODEURL(B2)&"&lon="&ENCODEURL(C2)&"&type="&ENCODEURL(D2))
```

都道府県庁の緯度経度で実行した例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2605106/b8a6e85b-1756-5e85-8b8b-5328ccc13a42.png)