部屋を掃除したら漫画が沢山出てきたので書く日記

漫画とか合唱とかUNIXとかLinuxとかについて書く日記です。

かかりつけ医院のWebサイトに更新があったらメールで通知するシステム

はじめに

インフルエンザワクチンの予防接種を我が家の私以外の家族(妻、子供)は近所のかかりつけ医院で受けています。こちらの医院はインフルエンザワクチンの予防接種は予約制となっていますが、今年は予約希望者が多いらしく、ワクチンの在庫が無くなると予約が出来なくなります。
ワクチンの入荷はホームページでお知らせされますが、依然として希望者が多いので見つけたらすぐ電話して予約しないと在庫切れとなってしまいます。
という事で、Webサイトを定期的にチェックして更新があったらメールでお知らせするシステムを用意する事にしました。
しました、と書きましたが、以前、全日本合唱連盟の合唱名曲シリーズ(全日本合唱コンクール課題曲集)の発表が行われたら検知してメールで通知する仕組みを作ったことがあるので、それを転用しました。

動作の概要

  1. 以下のような動作をするプログラムを用意する
    1. 病院のWebサイトURLに対してHTTP GET実行
    2. GET結果をHTMLファイルとして保存
    3. HTMLファイルのmd5チェックサムを作成
    4. 前回実行時のmd5チェックサムと差分比較
    5. 差分ありの場合、メール通知
    6. mdチェックサムを次回実施の「前回実行時のmd5チェックサム」として保存
  2. プログラムを定期的に実行する。

必要なもの

  • 常時稼働しているLinuxサーバ

-- さくらインターネットVPSで契約しているCentOS 6.10サーバを使用。余談だがそろそろサポート期間がヤバい)

プログラムについて

メインプログラム

「メインプログラム」と表現するのもおこがましいbashスクリプトです。

check_Kakarituke.sh
#!/bin/bash -x
export LC_ALL="ja_JP.UTF-8"
TAG="Kakarituke_Clinic"

URL='http://example.com/cgi-bin/general/topics.cgi'
WORKDIR='/home/bata64/sh/check_Kakarituke'
OUT='/home/bata64/sh/check_Kakarituke/output.html'
InfoFile="/home/bata64/sh/check_Kakarituke/messages.txt"
RcptTo="hoge@example.com,hoge2@example.com"
MD5SUM=md5sum.txt
MD5SUMPRE=md5sum_pre.txt

date
cd $WORKDIR
curl $URL -o $OUT
md5sum $OUT > $MD5SUM
diff $MD5SUM $MD5SUMPRE > /dev/null 2>&1
if [ $? -eq 0 ]; then
    logger -i -p 6 -t $TAG "No Change at $URL "
else
    cd /home/bata64/py/; python3.6 ./mailsend.py $TAG $InfoFile $RcptTo
    logger -i -p 6 -t $TAG "Some Change Occuerd at $URL "
fi
cd $WORKDIR
rm $OUT
cp -p $MD5SUM $MD5SUMPRE
メール送信プログラム

以前ならPerlでNet::SMTP、あるいはEmail::Senderなどを使って書いていましたが、日本語でSubjectや本文を書く時に色々考慮が必要でした。
Pythonだとsmtplibという標準のモジュールでサクッと書けました。すばらしい・・・。

mailsend.py [件名] [メッセージ本文記載のテキストファイルのパス] [宛先メールアドレス(複数の場合はカンマ区切り)]

という感じで動作します。

import smtplib
import sys
from email.message import EmailMessage

# コマンドライン引数取得
args = sys.argv
subject = args[1]
msgtxt = args[2]
rcptto = args[3]

with open(msgtxt,'r') as fp:
    # Create a textplain message
    msg = EmailMessage()
    msg.set_content(fp.read())

msg['Subject'] = 'お知らせ about ' + subject
msg['From'] = 'bata64@example.ne.jp'
msg['To'] = rcptto

# Send the message via our own SMTP server.
s = smtplib.SMTP('smtp.example.ne.jp',587)
s.ehlo('example.ne.jp')
s.login('bata64@example.ne.jp', 'password')
s.send_message(msg)
s.quit()
メッセージ本文記載テキストファイル

ホームページが更新されていたらお知らせするメールに記載する文章です。
HTMLファイルの中身を記載しようかとも思いましたが、受け取った人が実際にアクセスしてみる形が実装上の手間、確実に確認するプロセスとして良いなと思ったので以下のようにしました。

messages.txt
○○クリニックのページに更新があります

http://example.com/
定期的に実行する仕組み

メインプログラム、メール送信プログラムを実行するパーミッションがあり、それぞれ実際に実行してみて想定する動作をする事が確認出来たら、定期的に実行するように設定します。設定には、LinuxUnix系OSで用意されているcronを利用し、7時から20時の間、30分間隔で実行する事にしました。さくらのVPSで契約しているCentOSサーバに設定した内容は以下の通りです。

/etc/cron.d/bata64
## かかりつけ医院のお知らせページの更新確認(2020年度下期のインフルエンザワクチン入荷状況チェック)
07,37 7-20 * * * bata64 ( /home/bata64/sh/check_Kakarituke/check_Kakarituke.sh > /home/kawabata/sh/check_Kakarituke/check_Kakarituke.sh.log 2>&1 )

動作確認

CentOSサーバにSSHでアクセスして各ファイルを所定の場所に格納したのち、

% tail -f /var/log/cron

で、時間になったらcronに設定したスクリプトが起動しているかを確認しましょう。起動していたら以下のようなメッセージが出力されます。

Nov 22 20:37:01 www6057uj CROND[22339]: (bata64) CMD (( /home/bata64/sh/check_Kakarituke/check_Kakarituke.sh > /home/kawabata/sh/check_Kakarituke/check_Kakarituke.sh.log 2>&1 2>&1 ))

初回実行時は前回実施ファイルが無いので「差分無しではない」という判定になりメールが届きます。

ちょっとした解説

アクセス先URL

(以下URLは全てダミーです)
かかりつけ医院のホームページのURLは

http://example.com/

ですが、お知らせページはフレームの中にあり、URLは

http://example.com/cgi-bin/general/topics.cgi

であることがわかりましたので、こちらに直接アクセスしてチェックする事にしました。
なお、フレームのURLはChromeでホームページにアクセスしたのちフレームにマウスカーソルを合わせて右クリックメニューから「フレームのソースを表示」を実行して表示される

view-source:http://example.com/cgi-bin/general/topics.cgi

から「view-source:」を取り除く事で確認しました。

syslogに通知

メインプログラムにて

TAG="Kakarituke_Clinic"
    logger -i -p 6 -t $TAG "No Change at $URL "
    logger -i -p 6 -t $TAG "Some Change Occuerd at $URL "

と記述し、メールだけでなくsyslogにもメッセージを残すことにしました。syslog監視をすれば検知も可能ですが実施は今後考えます。

メール送信

近年、ISPやメール送信サービスにおける迷惑メール対策は厳しくなっている事から以前のように単純にSMTPサーバにport25でアクセスして送信するだけでは宛先メールアドレスに届かない場合が多くなりました。

上記の場合は私の契約しているISPで払い出されているメールアドレスおよびメールサーバを利用し、port587を使ったSMTP Auth(いわゆるOP25B)で送るようにしています。

では。