2019/8/14 追記
現在、台風情報などに対応するためコードを修正中です。
しばしお待ちください m(._.)m
以下のものは、修正前のコードになります。
通常の天候の場合は正しく動きますが、
災害等が発生している場合は正しくデータ出力ができません。
TL;DL
最近、個人開発のメモ用にSlackを使っていて、
「あれ、時報的に天気予報流れてきたら便利じゃね?」
と思って自力でゴチャゴチャ頑張った記録です。
Motivation
- Slackに天気予報を流したい。
- 常時起動しているサーバーがあるので
cron
を使って定期的にSlackに投稿したい。 - 普段「Yahoo! 天気」を見ているので、その情報をSlackに流したい。
- あと、シェルの勉強。
仕組み
- 「Yahoo! 天気」から情報を取ってくる
- シェルスクリプトで出力を整える
- Slackへ投稿
これをcron
で定期的に実行させます。
もっと楽な方法があるとか言わない
実装
「Yahoo! 天気」から情報を取ってくる〜シェルスクリプトで出力を整える
@arabian9tsさんの「Linuxコマンドで天気予報を取得&表示するワンライン(on Mac)」を参考に。
まず、天気予報を取ってくるURLを探します。
Yahoo! パーソナル天気にアクセスし、郵便番号を入力。
例えば、京都府京都市下京区なら「〒600-8216」なので
URLは https://weather.yahoo.co.jp/weather/26/6110/26106.html となりました。
んで、私が作ったシェルスクリプトは次の通り。
かなり汚くなってしまった気がする
# !/bin/bash
function txt_edit(){
array=()
for i in `seq 9`
do
array+=(`awk "NR==$i" tmp$1.txt`)
done
echo -e ${array[*]} >> data.txt
sed -e '1,9d' tmp$1.txt > tmp`expr $1 \+ 1`.txt
}
url=https://weather.yahoo.co.jp/weather/26/6110/26106.html #ここを、さっきのURLにする
curl -s $url | sed -e 's/<[^>]*>//g' | grep -v '^\s*$' > tmp.txt
head -n 1 tmp.txt > weather.txt
sed -e '1,33d' tmp.txt > tmp0.txt
head -n 3 tmp0.txt > weather.txt
sed -e '1,3d' tmp0.txt > tmp1.txt
for i in `seq 5`
do
txt_edit $i
done
array=()
array2=("--")
for i in `seq 1 2 17`
do
array+=(`awk "NR==$i" tmp6.txt`)
j=`expr $i \+ 1`
array2+=(`awk "NR==$j" tmp6.txt`)
done
echo -e ${array2[*]} >> data.txt
echo -e ${array[*]} >> data.txt
sed -e '1,17d' tmp6.txt > tmp7.txt
N=$(head -n 1 data.txt | wc -w)
for i in `seq 1 $N`
do
awk '{print $'$i'}' < data.txt | tr '\n' '\t' >> weather.txt
echo >> weather.txt
done
head -n 4 tmp7.txt >> weather.txt
echo $url >> weather.txt
rm tmp*
rm data.txt
ざっくりと、スクリプトの中身としては
- URLから情報をごっそり取ってくる
- 必要な情報を取りやすいように下整形 → tmp.txt
- 行を指定して、文字列情報をいい感じに配列へ入れていく → data.txt ※一時ファイルはtmp(番号).txt
- data.txtのままだと見ずらいので、行と列を入れ替え(転置)して最終ファイルへ → weather.txt
- いらなくなったファイルを削除。
転置は http://kenbell.hatenablog.com/entry/20130604/1370308018 を参考にしました。
ターミナルで
$ chmod +x Kyoto.sh
$ ./Kyoto.sh
ちなみに、出力は
2019年8月3日 18時00分発表
今日の天気
- 8月3日(土)
時刻 天気 気温(℃) 湿度(%) 降水量(mm) -- 風向風速(m/s)
0時 晴れ 30 72 0 北東 1
3時 晴れ 29 74 0 静穏 0
6時 晴れ 28 76 0 北東 2
9時 晴れ 31 64 0 南西 2
12時 晴れ 35 48 0 東 2
15時 晴れ 37 38 0 東 3
18時 晴れ 34 51 0 南東 3
21時 晴れ 30 73 0 北西 1
京都市の警報・注意報
注意報
大雨、雷
京都市下京区の今の天気はどうですか?
https://weather.yahoo.co.jp/weather/26/6110/26106.html
Slackに流す時にTabが崩れるので、インデントずれとか縦がずれてるのとかは気にしない!
Slackに流す
@ik-fibさんの「SlackのIncoming Webhooksを使い倒す」あたりを参考に。
curlのURLと、その他オプションは適宜変更。
# !/bin/bash
if [ $# != 0 ] ; then
numLine=1
cat $1 | while read line
do
#echo $numLine: $line # 出力
numLine=$((numLine + 1)) # 行数を1増やす
str=$line
curl -X POST --data-urlencode "payload={\"channel\": \"#general\", \"username\": \"Weather bot\", \"text\": \"$str\", \"icon_emoji\": \":robot_face:\"}" https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX
done
else
echo ERROR: Please input argument.
fi
http://sweng.web.fc2.com/ja/program/bash/read-each-line.html をちょびっと参考にしました。
ターミナルで
$ chmod +x Slack_weather.sh
$ ./Slack_weather.sh weather.txt
cron
で定期実行
cron
を使えば、朝昼晩でも1時間毎でも1分毎でもなんでもいけますね!
お疲れ様でした & 反省会
- 「何行目から何行目」で情報を整理しているので、Yahoo側で仕様が変わると怖い。
- というか力技感、、、
- 警報・注意報あたりが場合によってはうまく出力されないかも?
- Slackに送信するとき、1行ごとに通知がいってしまう(今回のだと、一気に16通知くらい)。
もっともっと精進ですね。
綺麗でエレガントなプログラムを書けるようになりたい、、、
「こうするともっと良くなる!」などなどあれば教えていただければと思います!