25
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Pythonを使って位置情報から天気予報を送るLINE Botを作った!

Last updated at Posted at 2019-09-24

目的

  • LINE Botに慣れる。
  • Pythonを用いて位置情報を送信すると天気予報を返信してくれるbotを作成する。

注意!

LINEmessagingAPIもスクレイピングも初めてやったのでプログラムに変なとこがある可能性が高いです。(特にスクレイピングに関しては)
改善点などあったら是非コメントしてください!

参考

下記のサイト、記事を参考にさせていただきました。ありがとうございます。

PythonとLINE APIとHerokuでBOTを作る[Python編]
--LINE Botとスクレイピングを組み合わせるのに参考にさせていただきました。

Messaging API リファレンス
--公式のリファレンスです。

LINE初心者!-LINE Botでオウム返し編-
PythonでLINE Botを作ってみた
Python, LINE APIを使ってbotを作成する
--1番最初に何からやったら良いか分からないときに非常に参考になりました。

イメージマップを使って終電に乗り遅れないボットを作りました
--位置情報を使ったBotを作るのに参考になりました。

Beautiful soupでの スクレイピング基礎まとめ[初学者向け]
PythonとBeautiful Soupでスクレイピング
--Pythonでスクレイピングをするのに参考になりました。

開発環境

  • OS X 10.14.6
  • Python 3.6.6
  • Flask 1.1.1
  • Line-bot-sdk 1.14.0
  • Heroku

前提

  • Line Developerに登録済み
  • Herokuに登録済み

ファイル構成

Line_bot
├ main.py
├ scrape.py
├ runtime.txt
├ requirements.txt
└ Procfile

ソースコードとその説明

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
)
from linebot.exceptions import LineBotApiError

import scrape as sc
import urllib3.request
import os
 
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("/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 = event.message.text
  if '位置情報' in text:
    line_bot_api.reply_message(
      event.reply_token,
      [
      TextSendMessage(text='位置情報を教えてください。'),
      TextSendMessage(text='line://nv/location')
      ]
    )
  
@handler.add(MessageEvent, message=LocationMessage)
def handle_location(event):
    text = event.message.address

    result = sc.get_weather_from_location(text)
    line_bot_api.reply_message(
        event.reply_token,
        TextSendMessage(text=result)
    )

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

「位置情報」という文字列の入ったテキストをbotが受信すると、「位置情報を教えてください」という返信とともに位置情報の選択画面へのURLを送信するようにしました。
詳しくはLINE DeveloperのドキュメントであるLINE URLスキームを使うを参照してください。

scrape.py
import requests
from bs4 import BeautifulSoup
import re

# 位置情報からその日の天気を返す
def get_weather_from_location(original_location):
  # 住所の中から郵便番号を抽出する
  location = re.findall('\d{3}-\d{4}', original_location)
  # 1回目のスクレイピングでは住所を検索し、候補から取ってくる
  url = "https://weather.yahoo.co.jp/weather/search/?p=" + location[0]
  r = requests.get(url)
  soup = BeautifulSoup(r.text, 'html.parser')
  content = soup.find(class_="serch-table")
  # 2回目のスクレイピングで用いるURLを得る
  location_url = "http:" + content.find('a').get('href')
  r = requests.get(location_url)
  soup = BeautifulSoup(r.text, 'html.parser')
  content = soup.find(id='yjw_pinpoint_today').find_all('td')
  info = []

  for each in content[1:]:
    info.append(each.get_text().strip('\n'))
  
  # 時間
  time = info[:8]
  # 天気
  weather = info[9:17]
  # 気温
  temperature = info[18:26]
  # 上の3つの情報を合わせる
  weather_info = [(time[i], weather[i], temperature[i]) for i in range(8)]

  result = [('{0[0]}: {0[1]}, {0[2]}°C'.format(weather_info[i])) for i in range(8)]
  result = ('{}\nの今日の天気は\n'.format(original_location) + '\n'.join(result) + '\nです。')

  return result

scrape.pyのget_weather_from_locationでは受け取った位置情報のうち郵便番号を抜き出してyahoo天気からその日の天気予報を取ってくるようにしています。

runtime.txt
python-3.6.6
requirements.txt
Flask==1.1.1
line-bot-sdk==1.14.0 
beautifulsoup4==4.7.
urllib3==1.24.1
soupsieve==1.6.1

もしかしたら不要なものも書いているかもしれません。
ご指摘ください。

ソースコードはここにおいてます。
https://github.com/RY908/Weather_bot

ハマったポイント

Line botとはあんまり関係ないのですが、スクレイピングするのが初めてだったのでスクレイピングにかなり時間がかかりました笑

結果

Screenshot_20190924-171917609_1.jpg
無事1日の天気を送ることができました!

今後はプッシュ通知などを使って改良していきたいです!

25
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?