#はじめに
tenki.jpをスクレイピングして天気予報をlinebotに組み込んでみました。
https://tenki.jp/
*linedeveloperは登録されている前提でお話します!
#環境
windows
python 3.6.4
#まずはスクレイピング準備
#対象のサイトURL
url = "https://tenki.jp/forecast/6/30/6200/27100/"
#インスタンス作成
res = urllib.request.urlopen(url)
soup = BeautifulSoup(res, 'html.parser')
'html.parser'はスクレイピングに必要なフィルターみたいなもの。
#classごとのスクレイピング
weather = soup.find_all("p", class_="weather-telop")
temp = soup.find_all("dd", class_="high-temp temp")
low_temp = soup.find_all("dd", class_="low-temp temp")
tds = soup.select("tr.rain-probability td")
hini = soup.find_all("h3", class_="left-style")
上から、「天気、気温、最低気温、降水確率、日にち」の順番でスクレイピングしています。
find_allやselectメソッドの使い分けはもっと慣れる必要があるが、selectだけ使っとけば問題なさそうだと思った。
#出力に備えて
tenki = hini[0].getText() + "\n\n" + weather[0].getText()
kion = "\n最高 " + temp[0].getText()
low_kion = " 最低 " + low_temp[0].getText()
rain1 = "\n\n降水確率\n00-06時 " + tds[0].getText()
rain2 = "\n06-12時 " + tds[1].getText()
rain3 = "\n12-18時 " + tds[2].getText()
rain4 = "\n18-24時 " + tds[3].getText()
先ほどスクレイピングした物は全部リストとなって取得される。
今回は基本的に[0]の中身が今日のデータで、[1]の中身が明日のデータだったため割とあっさり出来た。
#スクレイピングファイル(scw.py)の全体図
import urllib.request
from bs4 import BeautifulSoup
def getw(): #今日の天気スクレイピング
#対象のサイトURL
url = "https://tenki.jp/forecast/6/30/6200/27100/"
#インスタンス作成
res = urllib.request.urlopen(url)
soup = BeautifulSoup(res, 'html.parser')
#対象の要素
weather = soup.find_all("p", class_="weather-telop")
temp = soup.find_all("dd", class_="high-temp temp")
low_temp = soup.find_all("dd", class_="low-temp temp")
tds = soup.select("tr.rain-probability td")
hini = soup.find_all("h3", class_="left-style")
tenki = hini[0].getText() + "\n\n" + weather[0].getText()
kion = "\n最高 " + temp[0].getText()
low_kion = " 最低 " + low_temp[0].getText()
rain1 = "\n\n降水確率\n00-06時 " + tds[0].getText()
rain2 = "\n06-12時 " + tds[1].getText()
rain3 = "\n12-18時 " + tds[2].getText()
rain4 = "\n18-24時 " + tds[3].getText()
a = tenki+kion+low_kion+rain1+rain2+rain3+rain4
return a
def tom_getw(): #明日の天気スクレイピング
#対象のサイトURL
url = "https://tenki.jp/forecast/6/30/6200/27210/"
#インスタンス作成
res = urllib.request.urlopen(url)
soup = BeautifulSoup(res, 'html.parser')
#対象の要素
weather = soup.find_all("p", class_="weather-telop")
temp = soup.find_all("dd", class_="high-temp temp")
low_temp = soup.find_all("dd", class_="low-temp temp")
tds = soup.select("tr.rain-probability td")
hini = soup.find_all("h3", class_="left-style")
tenki = hini[1].getText() + "\n\n" + weather[1].getText()
kion = "\n最高 " + temp[1].getText()
low_kion = " 最低 " + low_temp[1].getText()
rain1 = "\n\n降水確率\n00-06時 " + tds[4].getText()
rain2 = "\n06-12時 " + tds[5].getText()
rain3 = "\n12-18時 " + tds[6].getText()
rain4 = "\n18-24時 " + tds[7].getText()
b = tenki+kion+low_kion+rain1+rain2+rain3+rain4
return b
あとはこの関数をlinebotのmain.pyに読み込ませる。
main.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
import os
import requests
import pprint
import urllib.request
from bs4 import BeautifulSoup
import scw #先ほどファイルをインポート
app=Flask(__name__)
#環境変数の取得
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 "cheer up!!2"
@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):
#入力された文字を取得
text_in = event.message.text
if "今日" in text_in: #scw.pyのgetw関数を呼び出している
line_bot_api.reply_message(event.reply_token,TextSendMessage(text=scw.getw()))
elif "明日" in text_in: #scw.pyのtom_getw関数を呼び出している
line_bot_api.reply_message(event.reply_token,TextSendMessage(text=scw.tom_getw()))
else: #「今日」「明日」以外の文字はオウム返しする
line_bot_api.reply_message(event.reply_token,TextSendMessage(text=event.message.text))
if __name__=="__main__":
port=int(os.getenv("PORT",5000))
app.run(host="0.0.0.0",port=port)
ユーザーが「今日」という文字が含まれている文字を入力すると、今日の天気が出るようにした。
あとはデプロイして完成!
#最後に
もっとスマートに書けるはずなので、次へ課題にしておく。
あと、全然面白みがないBOTなので、雨だったら「傘もった?」などの通知が来るなどのアレンジを加えるなど、やれる事はいっぱいあるので此方も次の課題にしておこう。
全く関係ない話だが、腰が痛い。