#(1)背景
・いつもこの時期から花粉に悩まされる。
・今年はコロナもあって花粉症者は辛い。
・マスク不足。
・pythonとscraping、herokuを使って何か作ってみたい。
・アウトプットイメージ ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
#(2)環境構築
デスクトップに、ディレクトリ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
#(3)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リファレンスを参考にした。
・ TextSendMessageの箇所はLINEapiリファレンスのURLスキームを参考にした。
・なお、URLスキームは1対1のトークのみで利用可能であり、グループでの利用は不可。
・'\uDBC0\uDC20'は絵文字で、LINE BOTで「LINEの絵文字」を使うを参考にした。
#(4)weather.py
Yhaooから花粉情報をスクレイピング。
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 = ""
#1つ目の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
#(5)Herokuへデプロイと、LINE DevelopersのWebhook設定
最後に必要なファイル(requirements.txt、Procfile、runtime.txt)を作成し、Herokuへデプロイする。デプロイ方法は多くのサイトで紹介しているので割愛。詳細はHeroku、Flask、SQLAlchemyで掲示板を作るを参考。
また、LINE DevelopersのWebhook設定もこれも多くのサイトで紹介しているので割愛。詳細はLINE BOT(オウム返し)を作るを参考。
###出来上がった、LINEBotに、”花粉”と入力すると位置情報を聞いてくるので、タップすると、花粉情報を取得できる(完成)。