天気予報 botを定期実行しよう

Ruby

こんにちは、kazutoです。以前、作成した天気予報 botをcronコマンドを用いて、本格的に稼動させていきましょう。

事前準備

今回は、cronコマンドを用いて、Twitter botを定期実行させていきます。なので、天気予報 botを作成をしていない方は、下記の記事を参照をし、botを作成してから、こちらの記事を参照する事をお勧めします。

なお、忙しい方は、こちらの記事からソースコードをコピペをして、初めていきましょう。

Twitter bot [総集編]

「Twitter bot [総集編]」から始める方
Twitter APIのAPIKEYなどをTwitter Developerにて、ご自身で取得をしてください、下記にURLを貼り付けておきます。

https://developer.twitter.com/en

定期実行するファイルを作成しよう

まずは、定期実行するファイルを作成していきましょう。また、cronが動作しているか確認をするために、cron.logファイルも、作成をしていきましょう。

touch periodic_execution.rb
touch cron.log
ls 
...
 periodic_execution.rb
 cron.log

ファイルを作成ができたのを確認をできたら、次のステップに進みましょう。

ツイート機能を実装しよう

次にperiodic_execution.rbファイルに天気予報を取得をして、ツイートする機能を実装していきましょう。

class Wetaher
 #...省略
  def tokyo
     @citys[0]
  end
end
require"/Users/kazuto/projects/environment/wther/config.rb"
require "json"
require "open-uri"
require "csv"
require "/Users/kazuto/projects/environment/weather/weather_class.rb"
require "/Users/kazuto/projects/environment/weather/tweet.rb"
require "/Users/kazuto/projects/environment/weather/search.rb"
require "/Users/kazuto/projects/environment/weather/analysis.rb"

def today_weather_in_tokyo()
  citys=CSV.read("/Users/kazuto/projects/environment/weather/citys.csv",headers: true)
  weather = Wetaher.new(citys)
  tokyo = weather.tokyo()
  datas=weather.get_weather_forecast(tokyo)
  current_time_weather=weather.current_time_weather(datas)
  tweet = Tweet.new(current_time_weather)
  tweet.updata()
  puts "成功しました"
end
today_weather_in_tokyo()

では、ソースコードの解説をしていきます。

require"/Users/kazuto/projects/environment/wther/config.rb"
require "json"
require "open-uri"
require "csv"
require "/Users/kazuto/projects/environment/weather/weather_class.rb"
require "/Users/kazuto/projects/environment/weather/tweet.rb"
require "/Users/kazuto/projects/environment/weather/search.rb"
require "/Users/kazuto/projects/environment/weather/analysis.rb"

今回は、cronのPATHの関係上、requireメソッドでファイルを読み込むをする方法を相対パスでは無く、絶対パスで設定しています。相対パスで設定しまうと、ファイルが読み込まれず、実行されませんので、注意をしてください。

def today_weather_in_tokyo()
  citys=CSV.read("/Users/kazuto/projects/environment/weather/citys.csv",headers: true)
  weather = Wetaher.new(citys)
  tokyo = weather.tokyo()
  datas=weather.get_weather_forecast(tokyo)
  current_time_weather=weather.current_time_weather(datas)
  tweet = Tweet.new(current_time_weather)
  tweet.updata()
  puts "成功しました"
end

今回は、東京の天気を取得をしてツイートしていきます。したがって、上記のメソッドを定義をしました。では、解説をしていきます。

citys=CSV.read("/Users/kazuto/projects/environment/weather/citys.csv",headers: true)

まずは、CSVファイルを読み込む、都市を取得をします。

weather = Wetaher.new(citys)

次に、Wetaherクラスのインスタンスを生成をします。

tokyo = weather.tokyo()

東京の詳細情報を取得をします。

datas = weather.get_weather_forecast(tokyo)

get_weather_forecastメソッドを用いて、OpenWeatherMapにGETリクエストを送り、レスポンスとして、天気情報を取得をしています。

 current_time_weather=weather.current_time_weather(datas)

current_time_weatherメソッドを用いて、現在時刻に最も近い、観測時間の天気情報のみを抽出をしています。(現在時刻以降)

tweet = Tweet.new(current_time_weather)

次に取得した天気情報が格納されている変数current_time_weatherを引数に渡して、Tweetクラスのインスタンスを生成をします。

tweet.updata()

 最後にupdateメソッドを呼び出して、ツイートをします。

以上で、ツイート機能の実装は終了になります。以前、作成したメソッドを再利用する形で実装をしたので、とてもシンプルに機能を追加をできました。では、実際にツイートができるのか確認をしておきましょう。

ruby periodic_execution.rb 

上記の画像の通り、ツイートができたら、次のステップに進みましょう。

cronコマンドで定期実行を行う時間を設定しよう

periodic_execution.rbファイルが作成できたので、cronコマンドの設定を行っていきましょう。

  • cronコマンドとは
  • cronを使える様にしよう
  • vimを用いて、crontabファイルに時間を設定しよう

cronコマンドとは

cronコマンドとは、定時実行のスケジュール管理を行うために用いられるコマンドです。また、crontabファイルという、コマンドの定時実行のスケジュール管理を行うために用いられるファイル内に、

  • PATH
  • 実行させたい時間
  • 実行させたいコマンド
  • 実行させたいファイル

を設定していきます。

まあ、要するにcronコマンドを用いて、crontabファイル内に記述されているジョブを実行していくという事です。なお、注意点として、PCがスリープモードなどPC が起動していない状態で、cronコマンドは、実行できませんので注意をしてください。(一時期にスリープモードを解く設定を行えば大丈夫です。)

cronを使える様にしよう

では、cronコマンドを使える様にしていきましょう。まずは、whichコマンドを用いて、cronコマンドが保存されている、ディレクトリを探しましょう。

which cron     
/usr/sbin/cron

おそらく、/usr/sbin/cronと出力がされると思います。

次にmacの環境設定を開き、「セキュリティとプライバシー」を開き、鍵マークをクリックをし、パスワードを入力をして鍵を開きましょう。その後、「フルディスクアクセス」という項目を選択をして、+ボタンをクリックをしてください。

+ボタンをクリックをしたら、上記の画面が出てきます。

Command  Shift  G

上記、3つのキーを同時に押してください。その後、「フォルダの場所を入力:」というポップアップが出てくると思いますので、検索フォームにcronコマンドのパスを入力をしましょう。

cronコマンドが見つかったら、開くをクリックをしましょう。

開くをクリックをしたら、「セキュリティとプライバシー」という項目が表示されている画面上に戻ってきます。cronコマンドにチェックマークが記載されているのが、確認ができると思いますので、鍵マークをクリックをして、鍵を閉じましょう。

以上で、「cronを使える様にしよう」の解説を終了します。

今回、何の設定をしたのか、疑問に持たれると思いますので、簡単に説明をしておきます。簡単に解説をすると、cronコマンドを全てのファイルで使える様にする設定を行いました。

vimを用いてcrontabファイルに時間を設定しよう。

cronコマンドの設定が完了をしたら、次にvimを用いて、crontabファイルにジョブをセットをしていきましょう。

crontab -e

crontabコマンドに-eをオプションを付け足す事により、crontabファイル内で作業を行える様になります。

#文字コード(自分の環境に合わせる)
LC_CTYPE=ja_JP.utf8
LANG=ja_JP.utf8
#OpenWeatherMap API
WEATHER_API_KEY='(APIKEY)を入力'
WEATHER_URL='http://api.openweathermap.org/data/2.5/forecast'
#twitter API
CONSUMER_KEY ='(APIKEY)を入力します'
CONSUMER_SECRET='(APIKEYSECRET)を入力します'
ACCESS_TOKEN ='(ACCESSTOKEN)を入力します'
ACCESS_TOKEN_SECRET ='(ACCESSTOKENSECRET)を入力します'
PATH=/Users/kazuto/opt/anaconda3/bin:/usr/local/opt/mysql@5.6/bin:/Users/kazuto/.rbenv/shims:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
#(分) (時) (日) (月) (曜)  実行したいコマンド
1 9 * * *  ruby -Ku /Users/kazuto/projects/environment/weather/periodic_execution.rb >> /Users/kazuto/projects/environment/weather/cron.log 2>&1

では、解説をしていきます。

#文字コード(自分の環境に合わせる)
LC_CTYPE=ja_JP.utf8
LANG=ja_JP.utf8

まずは、文字コードを設定をします。僕の場合、crontabファイルの環境とローカル環境で使われている文字コードが違ったため、上記の様に文字コードの設定を行っています。(ご自身の環境に合わせてください。)

#OpenWeatherMap API
WEATHER_API_KEY='(APIKEY)を入力'
WEATHER_URL='http://api.openweathermap.org/data/2.5/forecast'
#twitter API
CONSUMER_KEY ='(APIKEY)を入力します'
CONSUMER_SECRET='(APIKEYSECRET)を入力します'
ACCESS_TOKEN ='(ACCESSTOKEN)を入力します'
ACCESS_TOKEN_SECRET ='(ACCESSTOKENSECRET)を入力します'

次に各種、環境変数の設定を行っていきます。crontabファイルは、少し特殊で、.zshrcファイルが読み込まれません。つまり、以前、設定した環境変数は、読み込まれないままperiodic_execution.rb ファイルを実行してしまい、認証に失敗してしまいます。(Twitter API)したがって、.zshrcファイルと同じ環境をcrontabファイルでも再現をします(必要な部分のみ)。

#OpenWeatherMap API
WEATHER_API_KEY='(APIKEY)を入力'
WEATHER_URL='http://api.openweathermap.org/data/2.5/forecast'

まずは、OpenWeatherMap APIの設定を行いましょう。.zshrcファイルからコピペをして設定をしてください。

#twitter API
CONSUMER_KEY ='(APIKEY)を入力します'
CONSUMER_SECRET='(APIKEYSECRET)を入力します'
ACCESS_TOKEN ='(ACCESSTOKEN)を入力します'
ACCESS_TOKEN_SECRET ='(ACCESSTOKENSECRET)を入力します'

次にtwitter APIの設定を行いましょう。.zshrcファイルからコピペをして設定をしてください。

PATH=/Users/kazuto/opt/anaconda3/bin:/usr/local/opt/mysql@5.6/bin:/Users/kazuto/.rbenv/shims:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

次にPATHを設定をしていきましょう。PATHも、.zshrcファイルが読み込まれていない関係上、PATHも通っていません。以下のコマンドを実行してください。

echo $PATH
/Users/kazuto/opt/anaconda3/bin:/usr/local/opt/mysql@5.6/bin:/Users/kazuto/.rbenv/shims:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

echoコマンドを実行すると、あなたの環境に設定されているPATHを取得する事ができます。実行結果をコピペをして、crontab ファイルに貼り付けておきましょう。

#(分) (時) (日) (月) (曜)  実行したいコマンド
1 9 * * *  ruby -Ku /Users/kazuto/projects/environment/weather/periodic_execution.rb >> /Users/kazuto/projects/environment/weather/cron.log 2>&1

次にジョブを設定をしていきましょう。

#(分) (時) (日) (月) (曜) 
1 9 * * * 

上記は、毎朝9時01分に実行となります。左から分、時、月、曜とジョブを実行する時間を設定できます。

-Ku

-kuとする事でUTF-8という文字コードに指定をしています。

 /Users/kazuto/projects/environment/weather/periodic_execution.rb >> /Users/kazuto/projects/environment/weather/cron.log 2>&1

こちらは、periodic_execution.rbファイルを実行した結果の標準出力と標準エラー出力の追加出力を行っています。
“>>”と記述する事で、指定したファイルの末尾にログを追加する事ができます。
“2>&1″は、標準エラー出力を標準出力に流すという意味です。つまり、エラーログと実行結果(periodic_execution.rb)をcron.logというファイルにまとめて出力をするという事です。

概要については、下記の表を参照してください。

識別番号 名称 概要
0 標準入力 入力した内容(コマンド)
1 標準出力 コマンドを実行したときに画面に表示されるもの
2 標準エラー出力 エラーが発生したときに表示されるエラーメッセージ

※識別番号について
OS(Linux)が入出力を識別するための番号。この識別番号を用いて、ファイルにログを書き込んでいきます。この様な識別子の事をファイルディスクリプタと言います。

echo Hellow world !! > Test.txt 
cat Test.txt
Hellow world !!

通常、コマンドを実行してエラーが起きなかった場合は、標準出力(1)の結果をファイル内に書き込みます。

ls ccc > Test.txt 
ls: ccc: No such file or directory
cat Test.txt
何も出力されない...

逆にコマンドを実行してエラーが起きた場合は、標準エラー出力(2)がされますが、ファイルに書き込まれません

ls ccc 2>Test.txt 
cat Test.txt 
ls: ccc: No such file or directory   

では、次に標準エラーをファイルに書き込んでみましょう。lsコマンドのファイル指定の次に2と「標準エラー」を表す記述を追加をしましょう。catコマンドでファイルの中身をみてください。エラー内容が書き込まれているのがわかると思います。

上記の一連の流れから、コマンドを実行する際は、識別番号を設定しなくとも、デフォルトで「標準出力(1)」である事がわかります。

> 上書き追加
& ビット単位でのAND
1 標準出力
2 標準エラー出力
[x]>&[y] 
[x]>&[y]が与えられると、xで示されるファイル記述子は、
出力ファイル記述子yのコピーになります。
2>&1
2で示されるファイル記述子は、
出力ファイル記述子1のコピーになります。
/Users/kazuto/projects/environment/weather/cron.log 2>&1

したがって、”2>&1″と記述をする事で、標準出力 と標準エラー出力 の両方を、 cron.logファイルに追加できます。

以上で、「vimを用いてcrontabファイルに時間を設定しよう。」の解説は終了になります。ここまで、実装ができたのなら、毎朝09:01にあなたが作成をした、天気予報 botが東京の天気情報を自動でツイートをしてくれます。では、最後のトピックで、時間を変更をして、定期実行をしてくれるかを試してみましょう。

天気予報bot 起動をしよう

では、crontabファイルの時間の設定を変更をして、天気予報 botを起動をしてみましょう。

crontab -e
#before
1 9 * * *  ruby -Ku /Users/kazuto/projects/environment/weather/periodic_execution.rb >> /Users/kazuto/projects/environment/weather/cron.log 2>&1
#after
*/1 * * * *  ruby -Ku /Users/kazuto/projects/environment/weather/periodic_execution.rb >> /Users/kazuto/projects/environment/weather/cron.log 2>&1

:wqをして保存をしておきましょう。

画像に alt 属性が指定されていません。ファイル名: 85af3c6399253ef6174c20659bc89a6e.png

crontabの設定を変更後、ご自身が作成したアカウントでツイートができているのを確認をしてください。ツイートを確認ができたらbotの定期実行に成功した事になります。

またcron.logファイルに「成功」と出力されているのを確認をしておきましょう。

以上で、「天気予報 botを定期実行しよう」の解説を終了します。今回は、ソースコードを書いていくよりも、 Linuxコマンドを実行する方が多かった気がします。

まとめ:天気予報 botを定期実行しよう

今回は、天気予報 botをcronコマンドを用いて、定期実行させていきました。実行する時間をセットできるのは、とても便利なコマンドだと思います。この定期実行という機能を他のAPI、サービスを用いれば、下記の事ができると思います。

  • 毎朝、LINE(LINE Notify)に天気情報を通知をする
  • 9時、15時、18時にYoutube APIを用いて、任意なキーワードに対して、再生回数が多い、上位3動画を集計をし、CSVファイルまたは、スプレッドシート(google)に書き込む。
  • 定期的にニュースサイトに対してスクレイピングをする。
  • 定期的にRSSから更新情報を取得をし、更新があれば、gmailに更新情報を送信をする。

などです。結構、簡単に実現ができそうです。時間があれば試してみても良いかもしれません。

以上、kazutoでした。