気ままに実装する機械学習

機械学習に興味のある大学院生によるブログです. 機械学習以外のトピック多めです.

天気を知らせてくれるtwitter botを作ってみた

前回はgoogle calendarに予定を追加したり確認したりできるbotを紹介しました。
linearml.hatenablog.com


今回は天気を知らせてくれるtwitter botの紹介です。

テレビで天気を見てから学校行くなんてことはないですし、(正直)天気アプリを起動してまで確認することではないと思っています笑

しかしtwitterは毎朝開きます。なので、twitter botが教えてくれれば悩み解決です。

1. 天気APIの取得

今回はlivedoor天気情報が提供しているAPIを用いています。
APIから天気の情報を取得するためには地域コードが必要になってきます。
そこで最初に、地域を入力とし、地域コードを返すプログラムを作成しました。
各地域コードはこちらxml形式で提供されていたので、Beautiful Soupを用いて作成します。
Beautiful Soupについての詳細は今回は割愛させていただきます(Qiitaに詳しい記事がたくさんあります)。
今回は都道府県名を入力クエリとして想定しています。
(下記プログラムを動かすにはxmlファイルを"region_id.xml"という名前で保存する必要があります。)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup
import requests

def check_id(setCity):
	soup = BeautifulSoup(open('region_id.xml'),'html.parser')
	pref = soup.find('pref',title = setCity)
	if pref is not None:
		return True
	return False

def get_id(setPref):
	tmp = setPref[len(setPref) - 1]
	hokkaidou = ['道北','道南','道央']
	if tmp !=  '都' and setPref == '東京':
		setPref += '都'
	elif tmp != '府' and (setPref == '大阪' or setPref == '京都'):
		setPref += '府'
	elif tmp != '県' and setPref not in hokkaidou:
		setPref += '県'
	elif setPref == '北海道':
		setPref == '道央'

	soup = BeautifulSoup(open('region_id.xml'),'html.parser')
	pref = soup.find('pref',title = setPref)
	city = pref.find('city')
	txt = get_weather(city.get('id'))
	return txt


def get_weather(cityId):
	url = 'http://weather.livedoor.com/forecast/webservice/json/v1'
	payload = { 'city' : cityId }
	data = requests.get(url,params = payload).json()
	txt = ''
	txt += data['title'] + '\n'
	
	for weather in data['forecasts']:
		txt += weather['dateLabel'] + ':' + weather['telop'] + '\n'
		if  weather['temperature']['max'] is not None:
			txt += ' 最高気温は' + weather['temperature']['max']['celsius'] + '\n'
		else:
			txt += ' 最高気温情報はありません。\n'
		if weather['temperature']['min'] is not None:
			txt += ' 最低気温は' + weather['temperature']['min']['celsius']  + '\n'
		else :
			txt += ' 最低気温情報はありません。\n'
	return txt

if __name__ == '__main__':
	pref = '東京'.encode('utf-8')
	print get_id(pref)

xmlでは北海道は、「道央、道北、道南」に分かれていたので、北海道と入力した場合は札幌を出力するために「道央」に変換するようにしています。
また、"東京都"と"東京"や"大阪"と"大阪府"のように"都道府県"がついている場合とついていない場合のどちらにも対応できるようにしています。
このプログラムを動かすと以下のような出力結果が得られます。

東京都 東京 の天気
今日:晴れ
 最高気温は14
 最低気温情報はありません。
明日:晴れ
 最高気温は16
 最低気温は3

ツイート部分は前回の記事
linearml.hatenablog.com
で紹介した通りなので、そのツイート部分にこのテキスト情報を渡せば終わりです。

2.ツイート制御部分

今回は、3つの機能を新たに加えました。

  1. botに"w 都道府県名"とリプを送るとその地域の天気情報を返す機能
  2. botに"w s 都道府県名"とリプを送るとその地域をデフォルト地域として設定してくれる機能(存在しない都道府県を指定された場合その旨をリプで返す)
  3. botに"w"とリプを送るとデフォルト地域の天気情報を返す機能

前回の記事ではカレンダーに予定を登録する時のオプションを"r"、確認する時のオプションを"c"としていましたが今回はweatherの"w"をユーザに指定させます。
変更部分は以下の通りです。

~略~
elif reply[1] == 'w':
    if len(reply) == 3:
        txt = str(gr.get_id(reply[2]))
        tweet = '@' + str(status.user.screen_name) + ' ' + txt  + '\n' + str(datetime.datetime.today())
        api.update_status(status=tweet)
    elif len(reply) == 4:
        if reply[3] == '北海道':
                reply[3] = '道央'
        flag = gr.check_id(reply[3])
        if flag:
            file = open('defaultCity.txt','w')
            file.write(reply[3])
            file.close()
            tweet = '@' + str(status.user.screen_name) + ' デフォルト地域を' + reply[3] + 'に設定しました。' 
        else:
            tweet = '@' + str(status.user.screen_name) + ' ' + reply[3] + 'は存在しません。'

        api.update_status(status=tweet)

    elif len(reply) == 2:
        file = open('defaultCity.txt','r')
        defaultCity = file.readline()
        txt = str(gr.get_id(defaultCity))
        file.close()
        tweet = '@' + str(status.user.screen_name) + ' ' + txt  + '\n' + str(datetime.datetime.today())
        api.update_status(status=tweet)

    else:
        tweet = '@' + userName + ' You should reply : w city.'
        api.update_status(status=tweet)
~略~

この部分を新たに追加すれば動きます。
デフォルト地域はデータベースを使ってもいいのですが少し大げさな気もするので今回はテキストファイルで保存しています。
また、herokuやらなんやらでスケジューリングすれば毎朝自動で天気情報を送ってくれたりもします。
githubに全体のソースコードを載せておきます。

3. 動作確認

f:id:linearml:20180302082854p:plain
f:id:linearml:20180302082857p:plain
f:id:linearml:20180302082900p:plain

次はどんな機能を追加しましょうか。
今の所ありきたりのことしかできないので、もっと面白いことをやりたいですね。
とりあえず日々のことをtwitterで済ませてしまおう計画は続けつつ、面白いアイデアが思いつければいいなと思っています。