Pythonで位置情報を活用したLINEボットを作ってみた

数年前にLINEボットを作っていましたが、位置情報を使ったアプリをクイックに作ってみたくなったので、LINEボットを使わせて頂こうと思います。
最近はユーザの端末位置情報を活用したアプリが多く世の中にあるので、皆さんも是非一度扱ってみてはいかがでしょうか？

今回は、LINEの位置情報を送信できる機能を使って、送信された位置情報近辺のゴルフ練習場を返すボットを作ろうと思います。

## 開発中のLINEボット「メジロ」
位置情報や地名から近くの屋外打ちっぱなしゴルフ練習場を検索できるLINEボットです。
<a href="https://lin.ee/BbNwMMp"><img src="https://scdn.line-apps.com/n/line_add_friends/btn/ja.png" alt="友だち追加" height="36" border="0"></a>

### 画面サンプル
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185039/bf6a3ece-d183-803d-30b3-7bc7c67f1898.png" alt="" width="50%" height="">

## 目次
- LINE developerの登録
- 位置情報の取得
- 緯度経度を使った2地点の距離を算出
- Herokuへのデプロイ

## 対象
- LINEのMessaging APIを使ってみたい人
- Messaging APIのテンプレートメッセージを実装したい人
- 位置情報をLINE Botを通じて取得・活用したい人

## LINE developerの登録
過去の記事「[PythonでLINEの「Messaging API」でテンプレートメッセージを実装してみた](https://qiita.com/kotmats/items/c4e651f1cb6c4490f4b8)」に設定方法は載っているので参考にしてください。

## 位置情報の取得

では、早速実装します。

### ライブラリの準備

```bash
$ pip install flask
$ pip install line-bot-sdk
```

### 位置情報取得する

先ほど紹介した過去記事で、webhook等の設定やcallback関数の作成を完了すれば、以下の関数で位置情報を取得可能になります。

送られてきた住所や緯度経度を簡単に取得可能です。

```python
@handler.add(MessageEvent, message=LocationMessage)
def handle_location(event):
    user_address = event.message.address
    user_latitude = event.message.latitude
    user_longitude = event.message.longitude

    print(f'住所: {user_address}')
    print(f'緯度: {user_latitude}, 経度: {user_longitude}')
```


## 緯度経度を使った2地点の距離を算出

今回は緯度経度を使った距離の計算ができる **geopy** というライブラリを使わせていただきます。

```bash
$ pip install geopy
```

`geodesic()` 関数に2地点の緯度経度を渡せば距離が計算されます。

```python
from geopy.distance import geodesic

result = geodesic(({地点Aの緯度}, {地点Aの経度}), ({地点Bの緯度}, {地点Bの経度}))

print(result)
```

### LINEから送信結果から2地点間の距離を計算

```python
@handler.add(MessageEvent, message=LocationMessage)
def handle_location(event):
    user_latitude = event.message.latitude
    user_longitude = event.message.longitude

    filed_name = find_near_filed(user_latitude, user_longitude)

    line_bot_api.reply_message(
        event.reply_token,
        messages=TextSendMessage(
                    text=f'一番近いゴルフ練習場は、「{filed_name}」です！')
    )

def find_near_filed(user_latitude, user_longitude) -> List[Dict]:
    df = pd.DataFrame()
    df['filed_name'] = ['スイング碑文谷', 'フジゴルフセンター', '向原ゴルフセンター']
    df['latitude'] = [35.62198487, 35.66612773, 35.74087619]
    df['longitude'] = [139.6817892, 139.8073926, 139.6814391]

    user_location = (user_latitude, user_longitude)
    df['dis'] = [geodesic(user_location, (row['latitude'], row['longitude'])).km for _, row in df.iterrows()]

    return df.sort_values('dis').to_dict(orient='record')[0]['filed_name']
```

## Herokuへのデプロイ
Herokuを使うと簡単にAPIをデプロイできるので活用してみてください。
過去の記事「[PythonでLINEの「Messaging API」でテンプレートメッセージを実装してみた](https://qiita.com/kotmats/items/c4e651f1cb6c4490f4b8)」が参考になると思います。

## まとめ
最後まで読んでいただきありがとうございます。
最近はユーザの端末位置情報を使ったサービスが増えてきましたので、皆さんも一度位置情報を扱ってみてはいかがでしょうか？

今回作ったサンプルは、ゴルフ練習場を対象にしていましたが、飲食店やトレーニングジム、サウナ等に対象を変えてみると自分好みのLINEボットになり面白いかもしれません。

今回、開発進めているLINEボットはこちらです。
使ってみて、感想をいただけると嬉しいです。
<a href="https://lin.ee/BbNwMMp"><img src="https://scdn.line-apps.com/n/line_add_friends/btn/ja.png" alt="友だち追加" height="36" border="0"></a>