LINE botで天気が知りたい feat.Heroku+Python

# 目的
工学系のくせに外には出るのでいつも服装を考えるのですが、天気予報をチェックしない人間なのでよく失敗をします。
そこで、LINE botちゃんに天気（気温）を教えていただこうと思います。
まずはオウム返しで構築とテストしてから本番のコーディングを行うことをおすすめします。

# 参考
この記事は作業記録&備忘録みたいなやつです。詳しい・分かりやすいものを読みたい方は以下のリンクへどうぞ。
[Python + HerokuでLINE BOTを作ってみた](https://qiita.com/shimajiri/items/cf7ccf69d184fdb2fb26#flask%E3%81%A8line-bot-sdk%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)
[PythonでLINEBotはじめました（冷やし中華的な）【前編】](https://uepon.hatenadiary.com/entry/2018/06/19/222537)
[PythonでLINEBotはじめました（冷やし中華的な）【後編】](https://uepon.hatenadiary.com/entry/2018/07/27/002843)


# LINE Developersに登録
まずLINE Developersに登録します。登録は簡単です。
https://developers.line.me/ja/

## プロバイダー&チャネルの作成
LINE Developersに登録したらプロバイダーを作成します。英語の場合右下で言語を切り替えて下さい。
プロバイダーの中にチャネル（アプリ）を作成します。
画面が続いてて分かりにくいいかと思いますが

1. プロバイダー作成を押す
2. プロバイダー情報を入力(プロジェクト的な)
3. チャネル情報を入力(botの名前とか)

です。すぐ終わります。

## 必要な情報を取得しておく
APIを利用するために
- **チャネルアクセストークン**
- **チャネルシークレット**
- **Webhook URL**
の3つが必要になります。上2つはbotの管理画面から取得出来ます。別のタブにあるので探してみてください。
Webhook URLはHerokuを設定してから取得します。

# Herokuの設定
一旦Herokuの設定に移ります。まずアカウントの登録をしましょう。
その後、Heroku CLIというコマンドラインインターフェースをインストールします。
Heroku CLI : https://devcenter.heroku.com/articles/heroku-cli#download-and-install

## Herokuログイン
プロンプトで
`$heroku login`
を実行するとキー入力を促されるので何か入力して下さい。するとブラウザ経由でログイン出来ます。

## Herokuアプリケーションの作成
`$heroku create アプリ名`で新規アプリを作成できます。アンダーバー`_`は使えないので注意です。

## 環境変数の設定
環境変数を設定します。ここのやり方は人それぞれらしいですが僕は参考サイトと同様に設定します。
先ほど控えた2つの文字列を設定してあげましょう。
`$heroku config:set YOUR_CHANNEL_ACCESS_TOKEN="チャネルアクセストークン" --app アプリ名`
`$heroku config:set YOUR_CHANNEL_SECRET="チャネルシークレット" --app アプリ名`

# Webhookの設定
LINE Developersのコンソールに戻り、WebhookのURLを設定します。
`Webhook URL：https://アプリ名.herokuapp.com/callback`
更新を押し、webhookを利用するに設定で完了です。

>https://github.com/line/line-bot-sdk-java/tree/master/sample-spring-boot-echo#step-2
こちらの[**Deploy to Heroku**]を押してそこからアプリを作るとEchoBotをデプロイできます。

# コーディング
・LINE Developersでのbotの設定
・Herokuの設定
・両者の連携
が完了しました。ここからコーディングに入ります。

## ライブラリのインストール
今回は`flask`と`line-bot-sdk`を中心に使用します。
`pip install flask line-bot-sdk`
僕の環境では
**flask : 1.1.1**
**line-bot-sdk : 1.16.0**
です。

加えてスクレイピング用のライブラリは以下を使用します。
**soupsieve==2.0**
**urllib3==1.25.8**
**beautifulsoup4**

## 作業ディレクトリとその構成
どこでもいいですがプロジェクト用にディレクトリを作成することをおすすめします。
**構成:**
line_bot(作業dir)
├ main.py
├ scrape.py
├ Procfile
├ runtime.txt
└ requirements.txt

## ファイルの中身
### ①main.py
本体です。オウム返しでテストしたい場合は[こちら](https://qiita.com/shimajiri/items/cf7ccf69d184fdb2fb26#flask%E3%81%A8line-bot-sdk%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)を参考になると思います。
※APIキーの変数名に注意

```main.py
#必用なものをインポート
from flask import Flask, request, abort
import os
import scrape as sc

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
#LINEでのイベントを取得
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,
)

app = Flask(__name__)

#環境変数取得
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["LINE_BOT_CHANNEL_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["LINE_BOT_CHANNEL_SECRET"]

line_bot_api = LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler = WebhookHandler(YOUR_CHANNEL_SECRET)

#アプリケーション本体をopenすると実行される
@app.route("/")
def hello_world():
    return "hello world!"

#/callback　のリンクにアクセスしたときの処理。webhook用。
@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)

    return 'OK'

#メッセージ受信時のイベント
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    '''
    #line_bot_apiのreply_messageメソッドでevent.message.text(ユーザのメッセージ)を返信
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=event.message.text))
    '''
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=sc.getWeather())
    )

if __name__ == "__main__":
#    app.run()
    port = int(os.getenv("PORT"))
    app.run(host="0.0.0.0", port=port)
```

### ②scrape.py
天気情報をスクレイピングします。自分で書く予定だったのですがとりあえず
こちら→https://qiita.com/RIRO/items/1b67b0418b08a52de0d6
のコードを少し改変しました。ありがとうございます。

```scrape.py
#ライブラリのインポート
import requests
from bs4 import BeautifulSoup

def getWeather():
    #tenki.jpの目的の地域のページのURL（今回は東京都調布市）
    url = 'https://tenki.jp/forecast/3/16/4410/13208/'
    #HTTPリクエスト
    r = requests.get(url)

    #プロキシ環境下の場合は以下を記述
    """
    proxies = {
        "http":"http://proxy.xxx.xxx.xxx:8080",
        "https":"http://proxy.xxx.xxx.xxx:8080"
    }
    r = requests.get(url, proxies=proxies)
    """

    #HTMLの解析
    bsObj = BeautifulSoup(r.content, "html.parser")

    #今日の天気を取得
    today = bsObj.find(class_="today-weather")
    weather = today.p.string

    #気温情報のまとまり
    temp=today.div.find(class_="date-value-wrap")

    #気温の取得
    temp=temp.find_all("dd")
    temp_max = temp[0].span.string #最高気温
    temp_max_diff=temp[1].string #最高気温の前日比
    temp_min = temp[2].span.string #最低気温
    temp_min_diff=temp[3].string #最低気温の前日比

    #とりあえず動くのを見たいので天気と気温を繋げて返しています。
    return weather+temp_max+temp_min
```

### ③Procfile
プログラムの実行方法を記載します。

```
web: python main.py
```
### ④runtime.txt
Pythonのバージョンを記載するテキストファイルです。
3.7.7ではエラーが出たので3.6.10にしています。Herokuが3.7未対応なのかな？

```runtime.txt
python-3.6.10
```
### ⑤ requirements.txt
インストールするライブラリを記載するテキストファイルです。

```requirements.txt
Flask==1.1.1
line-bot-sdk==1.16.0
soupsieve==2.0
urllib3==1.25.8
beautifulsoup4
```

<br><br>
天気情報をスクレイピングするので`scrape.py`があります。EchoBot（オウム返し）などは他4つで大丈夫です。


# Herokuにデプロイする
※gitをインストールしてない人はインストールしましょう

```php

// gitの初期ファイルを作成
git init
// ローカルリポジトリに結びつくリモートリポジトリを設定
heroku git:remote -a (自分で決めたアプリ名)
// 変更したファイルを全てインデックスに登録
git add .
// 変更したファイルをリポジトリに書き込む（"inital commit"はコメントなのでなんでも良い）
git commit -m "inital commit"
// herokuにローカルで作成したファイルをpush
git push heroku master
```
## ※僕はここでエラーが出ました
ここで`requirements.txt`の`beautifulsoup4`のスペルをミスっててエラーが出ました。
僕はバージョン指定が悪いと思いバージョンを変えてtryしたのですが、ライブラリ名がミスってました()

## Heroku側で確認しておく
Herokuのダッシュボードでactivityの確認をしましょう。画像のようになっていれば成功です。
![b7276e159aa0cadcfe46ba23ed0d4cc4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502867/7502d5b6-f585-fd83-5f7d-9d16a3471efe.png)

## webhook検証のエラー
この部分はサンプルをコピーして利用したのですが
`ボットサーバーから200以外のHTTPステータスコードが返されました`というエラーが発生します。
が、BOTは正常に動くようなので無視しました。

# 動作確認
BOT管理画面にあるQRで友達追加して、何かメッセージを送ってみましょう。
天気の返信(orオウム返し)が成功したら成功です。

# Next
現在は天気と気温を文字列で送っているだけなので

- フォーマットを整える
- 設定の追加(Regionや定期送信)
- Flex Messageの挑戦

などをできればと思います。他プロジェクトや勉強もあるのでゆっくり更新します。
参考記事の方々ありがとうございました。