ウェブサイトの差分を検知してメール通知するシェルスクリプト
2020年は数多くのブルベに参加することになったが、各BRMでウェブサイトの更新を監視するのは辛い。
無料のウェブサービスもあるが、登録件数が不足したり、どこが変更されたのか分からなかったりしたので、 変更を検知したら差分箇所をメールで送信するシェルスクリプトを書いてみた。
事前に必要なもの
- Linuxが動作するサーバ (ここではOracle CloudにUbuntu 18.04のインスタンスを作成した)
- メールを送信するためのアカウント (ここでは個人用のGmailアカウント)
Gmailのアカウントを使う時は、下記を参照してアプリパスワードを生成しておく。
ssmtpのインストール
sendmailのために、今回はssmtpを使って設定してみる。
postfixのほうが好きな方はそちらで。
まずはssmtpをインストール。
sudo apt install ssmtp
設定ファイル(/etc/ssmtp/ssmtp.conf
)を編集し、使うメールアカウントに沿って設定箇所を記入。
#
# Config file for sSMTP sendmail
#
# The person who gets all mail for userids < 1000
# Make this empty to disable rewriting.
root=***@gmail.com
# The place where the mail goes. The actual machine name is required no
# MX records are consulted. Commonly mailhosts are named mail.domain.com
mailhub=smtp.gmail.com:587
# Where will the mail seem to come from?
rewriteDomain=gmail.com
# The full hostname
hostname=gmail.com
UseTLS=Yes
UseSTARTTLS=Yes
AuthUser=***@gmail.com
AuthPass=********(生成したアプリパスワード)********
AuthMethod=LOGIN
# Are users allowed to set their own From: address?
# YES - Allow the user to specify their own From: address
# NO - Use the system generated From: address
FromLineOverride=YES
スクリプト本体
webchecker.sh
という名前で下記の内容を書き込む。
#!/bin/bash
SCRIPT_DIR=$(cd $(dirname $0);pwd)
LISTFILE=${SCRIPT_DIR}/checklist.txt
DATETIME=$(date '+%Y%M%d_%h%m%s')
MAILTO="***@gmail.com"
MAILFROM="***@gmail.com"
curl=/usr/bin/curl
diff=/usr/bin/diff
sendmail=/usr/sbin/sendmail
cut=/usr/bin/cut
awk=/usr/bin/awk
#for s in $SITES; do
cat ${LISTFILE} | while read s
do
name=$(echo $s | $cut -d'|' -f 1)
url=$(echo $s | $cut -d'|' -f 2)
begin=$(echo $s | $cut -d'|' -f 3 | sed 's|/|\\/|g')
end=$(echo $s | $cut -d'|' -f 4 | sed 's|/|\\/|g')
newfile="${SCRIPT_DIR}/result/$name/new.html"
oldfile="${SCRIPT_DIR}/result/$name/old.html"
newrange="${SCRIPT_DIR}/result/$name/new_range.html"
oldrange="${SCRIPT_DIR}/result/$name/old_range.html"
errorcount="${SCRIPT_DIR}/result/$name/count.txt"
if [[ "$name" == "" ]]; then
continue
fi
# 先頭が"#"の場合はスキップ
if [[ "${name:0:1}" == "#" ]]; then
continue
fi
echo "NAME: "$name
echo " URL: "$url
echo " BEGIN: "$begin
echo " END: "$end
echo ""
mkdir -p "${SCRIPT_DIR}/result/$name/"
statuscode=$($curl "$url" -o "${newfile}" -w '%{http_code}\n' -s)
if [[ "${statuscode}" != "200" ]]; then
echo "Status Code Error"
count=$(cat "${errorcount}")
echo $((++count)) > "${errorcount}"
if [[ ${count} -eq 3 ]]; then
tmp=$(mktemp)
echo "To: ${MAILTO}" > $tmp
echo "From: ${MAILFROM}" >> $tmp
echo "Subject: ${name} Error" >> $tmp
echo "" >> $tmp
echo "${url}" >> $tmp
$sendmail -t < $tmp
echo -n "MAIL Sent"
rm $tmp
fi
elif [[ -f "$oldfile" ]]; then
cat "$oldfile" | $awk "/${begin}/,/${end}/" > "${oldrange}"
cat "$newfile" | $awk "/${begin}/,/${end}/" > "${newrange}"
echo '0' > "${errorcount}"
if [[ ! -s "${newrange}" ]];then
cp "${newfile}" "${newfile}".$(date '+%Y%m%d%H%M')
fi
if ! $diff "${oldrange}" "${newrange}" >/dev/null 2>&1; then
echo -n "CHANGED "
tmp=$(mktemp)
echo "To: ${MAILTO}" > $tmp
echo "From: ${MAILFROM}" >> $tmp
echo "Subject: ${name} Changed" >> $tmp
echo "" >> $tmp
echo "${url}" >> $tmp
echo "" >> $tmp
$diff "${oldrange}" "${newrange}" -u >> $tmp
$sendmail -t < $tmp
echo -n "MAIL Sent"
rm $tmp
cp "${newfile}" "${oldfile}"
else
echo -n "NO CHANGED "
fi
else
echo -n "NEW "
mv "${newfile}" "${oldfile}"
fi
echo ""
done
実行権限を付与。
chmod +x webchecker.sh
設定ファイル
checklist.txt
という名前で監視対象のURLと範囲を設定するファイルをwebchecker.sh
と同じディレクトリに作成。
BRM229|https://randonneurs.tokyo/?p=9950|<header>|<footer>
BRM320|https://audax-kinki.com/20brm0320_600/|<section>|<footer>
BRM328|https://randonneurs.tokyo/?p=9960|<header>|<footer>
BRM411|http://www.aj-kanagawa.org/brmkako-no-kaisai/brm2020/brm411-300|<td id="sites-canvas-wrapper">|DNS連絡フォーム</h2>
BRM418|http://www.vcraoba.yokohama/2020/2020brm418.html|<section>|</section>
RM430|https://randonneurs.tokyo/?p=9599|<header>|<footer>
RM430-Cue|https://randonneurs.tokyo/?p=11738|<header>|<footer>
次の書式で入力。
- 1行につき1つの監視対象を記入
- 区切り文字は「|」(パイプ記号) ※URLに使われそうにない文字を適当に選定した
- 各フィールドには以下の順番で記入
- 名前(結果の保存ディレクトリ名やメールの件名に使用)
- 監視対象のURL
diff
をかける範囲の先頭行に含まれる文字列diff
をかける範囲の最終行に含まれる文字列
動作確認
bash上で
./webchecker.sh
とすると、初回は「NEW」、2回目以降で変更がなければ「NO CHANGED」と表示される。
2回目以降で前回取得時から変更があれば「CHANGED」と表示され、メールが届くはず。
なお、正常に取得できなかった時は3回目にメールするようにした(1回だと結構誤検知が発生した)。
cronの設定
あとはcron
で定期的に実行されるようにする。
crontab -e
5分おきに実行するなら下記のようにする。
*/5 * * * * /home/ubuntu/webchecker/webchecker.sh > /dev/null 2>&1
実行例
あとは設定がうまくできていれば、次のようなメールが届く。
https://randonneurs.tokyo/?p=9950
--- /home/ubuntu/webchecker/result/BRM229/old_range.html 2020-02-28 09:55:01.681675366 +0000
+++ /home/ubuntu/webchecker/result/BRM229/new_range.html 2020-02-28 09:55:01.685675416 +0000
@@ -20,7 +20,8 @@
<div id="the-content" class="entry-content">
- <p><span style="color: #ff0000;"><span class="red">【お知らせ/2月24日追記】</span><br />
+ <p><span style="color: #ff0000;"><strong>※BRM229東京300ウルトラオレンヂの開催は延期いたしました。</strong></span></p>
+<p><span style="color: #ff0000;"><span class="red">【お知らせ/2月24日追記】</span><br />
試走の結果、国135号の渋滞が想定以上であったためPC3 LAWSON伊東渚町店を通過チェックに変更します。最新のキューシート(V1.1)にも反映しましたのでご確認ください。<br />
特に復路の熱川温泉以降は側溝に蓋のない状態となりますので十分に注意してください。</span></p>
<p><span style="color: #000000;">ゴール受付場所が変更になります。概要欄の変更点を確認の上でご参加ください。</span></p>
diff
の内容も本文に入れることで、どこが更新されたのかを分かりやすくした。