Pythonで、位置情報から花粉情報を送るLINEBotを作った。

#（１）背景
・いつもこの時期から花粉に悩まされる。
・今年はコロナもあって花粉症者は辛い。
・マスク不足。
・pythonとscraping、herokuを使って何か作ってみたい。
・アウトプットイメージ　↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
![unnamed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29856/187cd985-8383-7265-52e2-b25c920f943d.png)


#（２）環境構築
デスクトップに、ディレクトリline_kafunを作成。
line-sdkを扱うmain.pyと、Yahoo天気情報から花粉情報を収集するweather.pyを作成。

ディレクトリ構成は以下の通り。

```
line_kafun
├main.py
├weather.py
├Procfile
├runtime.txt
└requirements.txt
```

必要なパッケージをインストール。

```
pip install flask
pip install line-bot-sdk
pip install beautifulsopu4
pip install gunicorn
pip install lxml
pip install requests
```


#（３）main.py

```.py:main.py
from flask import Flask, request, abort
from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import (
    MessageEvent, TextMessage, TextSendMessage,LocationMessage
)
import os
import weather as wt #weather.pyをインポート


app = Flask(__name__)

#Herokuの環境変数設定
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]

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

@app.route("/")
def hello_world():
    return "hello world!"


@app.route("/callback", methods=['POST'])
def callback():
    signature = request.headers['X-Line-Signature']
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)
    return 'OK'



@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    if '花粉' in event.message.text:
        line_bot_api.reply_message(
            event.reply_token,
　　　　　　　[
            TextSendMessage(text='現在の位置情報は？'),
            TextSendMessage(text='https://line.me/R/nv/location/'),
            ]
        )
  

@handler.add(MessageEvent, message=LocationMessage)
def handle_location(event):
    text = event.message.address
    result = wt.get_weather(text)
    line_bot_api.reply_message(
    event.reply_token,
    TextSendMessage(text=result + '\uDBC0\uDC20')
    )


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

###補足説明
・text = event.message.addressの箇所のaddressは、linedevelopersの[apiリファレンス](https://developers.line.biz/ja/reference/messaging-api/#audio-message)を参考にした。<img width="1177" alt="スクリーンショット 2020-03-25 22.51.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29856/192afa78-672d-2ce4-4486-0e5b0abbae25.png">
・ TextSendMessageの箇所はLINEapiリファレンスのURLスキームを参考にした。
<img width="1151" alt="スクリーンショット 2020-03-25 23.03.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29856/de74ac9d-bcfb-990a-846f-c2741735c2dd.png">
・**なお、URLスキームは１対１のトークのみで利用可能であり、グループでの利用は不可。**
・'\uDBC0\uDC20'は絵文字で、[LINE BOTで「LINEの絵文字」を使う](https://www.pre-practice.net/2017/10/line-botline_21.html)を参考にした。

#（４）weather.py
Yhaooから花粉情報をスクレイピング。

```.py:weather.py
import requests
from bs4 import BeautifulSoup
import re
import lxml


def get_weather(text):
    location = re.findall('\d{3}-\d{4}',text)
    location2 = location[0].replace('-','')
    url1 = "https://weather.yahoo.co.jp/weather/search/?p={}".format(location2)
    url2 = ""

    #１つ目のurlからhtmlの情報を取得し、そこから2つ目のurlを取得
    res = requests.get(url1)
    res.encoding = res.apparent_encoding
    html_doc = res.text
    soup = BeautifulSoup(html_doc,"lxml")
    content_1 = soup.find_all(id = 'rsltmuni')
    for i in content_1:
        content_2 = i.find('a')
        url2 = 'https:' + content_2.get('href')


    #2つ目のurlから今日と明日の日付を取得(today、nextday)
    res = requests.get(url2)
    res.encoding = res.apparent_encoding
    html_doc = res.text
    soup = BeautifulSoup(html_doc,"lxml")
    content_3 = soup.find_all('p',class_='date')
    today = content_3[0].get_text()
    nextday = content_3[1].get_text()

    #今日と明日の花粉状況を取得
    content_4 = soup.find_all('p',class_='flying')
    today_kafun = content_4[0].get_text()
    nextday_kafun = content_4[1].get_text()

    #エリアを取得
    content_5 = soup.find_all('h2',class_='yjM')
    area = content_5[0].get_text()


    result = today + 'の' + area + 'は' + '「{}」'.format(today_kafun) + 'だよ。' + '\n' +'\n'+ nextday + 'の' + area + 'は' + '「{}」'.format(nextday_kafun) + 'だよ。' + '\n' +'\n' + '気をつけてね。'

    return result
```

#（５）Herokuへデプロイと、LINE DevelopersのWebhook設定
最後に必要なファイル（requirements.txt、Procfile、runtime.txt）を作成し、Herokuへデプロイする。デプロイ方法は多くのサイトで紹介しているので割愛。詳細は[Heroku、Flask、SQLAlchemyで掲示板を作る](https://qiita.com/nooonchi/items/73c6367780644d6e5bbd)を参考。
また、LINE DevelopersのWebhook設定もこれも多くのサイトで紹介しているので割愛。詳細は[LINE BOT（オウム返し）を作る](https://qiita.com/nooonchi/items/8004dfc9deea6c25754b)を参考。

###出来上がった、LINEBotに、”花粉”と入力すると位置情報を聞いてくるので、タップすると、花粉情報を取得できる（完成）。