GoogleAppScriptとスプレッドシートを使って北海道内の最新のコロナ感染者状況を通知するSlackBotを作りました。
北海道内感染者状況はこちら
特に説明する事もないのでコード貼り付けていって解説していきます。
let notify = [];
const SHEET = SpreadsheetApp.getActiveSheet();
const DATA = SHEET.getDataRange().getValues();
const MAX_PERSON_ID = DATA.map(person => person[0]).reduce((a,b) => a>b?a:b);
1行目は単純にSlackに通知するデータを後々格納する為の配列です。今は関係ありません。
サイト上でテーブルで扱われているので、こちらも同じ感じで扱うためスプレッドシートを用います。
上記2,3行でシートと、シートに存在するデータを取得しています。
シートでは以下の画像のようにデータを持っています。初期状態は1行目のみでした。
4行目でスプレッドシートに登録されてるIDカラムの最大値を取得します。
これと後々取得するデータのIDを比較する事で最新か通知済みかを判定させます。
const ENDPOINT = "http://www.pref.hokkaido.lg.jp/hf/kth/kak/hasseijoukyou.htm";
const CONTENT = UrlFetchApp.fetch(ENDPOINT).getContentText('UTF-8');
const INFECT_DATA = CONTENT.replace(/ /g,'').replace(/\r?\n/g, '').match(/<tr>.*?<\/tr>/g);
この3行でエンドポイントを指定し、データを取得し、必要な部分のみを抽出しています。
3行目INFECT_DATA
定数で行っているreplace処理は、1つ目は取得したHTMLデータの中にnon breaking spaceがあり邪魔だったので除外しています。2つ目は改行を消してます。その後に、テーブル内のtr要素のみを取り出しています。
これでINFECT_DATAはテーブルに存在するデータを1レコードを1要素とした配列になります。
for(let infectPerson of INFECT_DATA) {
const INFO = infectPerson.match(/<td>.*?<\/td>/g);
const ID = INFO[0].replace(/<.*?>/g, '').replace(/./g, s => String.fromCharCode(s.charCodeAt(0) - 0xfee0));
const DATE = INFO[1].replace(/<.*?>/g, '');
const AGE = INFO[2].replace(/<.*?>/g, '');
const SEX = INFO[3].replace(/<.*?>/g, '');
const RESIDENCE = INFO[4].replace(/<.*?>/g, '');
if (ID > MAX_PERSON_ID) {
const mes = "\n" + DATE + " | " + ID + "例目" + " | 年齢: " + AGE + " | 性別: " + SEX + " | 居住地: " + RESIDENCE;
notify.push(mes);
SHEET.appendRow([ID, DATE, AGE, SEX, RESIDENCE]);
}
}
INFOは各レコードから更にtd要素で分割された要素の配列です。
ID、日付、年齢、性別、居住地をそれぞれ宣言していますが、各td要素の中にもbrやa要素などが存在していたのでそれらを除去しています。
IDに関しては全角数値で取得してたので半角になおしています。
先程取得したMAX_PERSON_IDとIDを比較し、true(未通知の最新データ)であればメッセージを作ってnotifyに追加し、シートの最終行にも挿入しています。
if (notify.length > 0) {
slack(notify);
}
通知部分です。こんな書き方にしてるのは、後々LineBotや他のSNS等への通知を簡単に追加したかったからです。
通知フラグとか持たせてT/F判定よりは、notifyが0じゃなければ通知内容があると思ったので長さで判定しています。
function slack(notify) {
const ENDPOINT = "https://hooks.slack.com/services/TEAMID/BOT/TOKEN";
const TEXT = "北海道内の最新コロナ感染状況です。" + notify.join("");
const BODY = {
"text": TEXT
};
const PAYLOAD = JSON.stringify(BODY);
const OPTION = {
"method": "post",
"contentType": "application/json",
"payload": PAYLOAD
};
UrlFetchApp.fetch(ENDPOINT, OPTION);
}
slack通知の中身はこのようになってます。
これで全てです。コード全体は以下のようになっています。
function myFunction() {
let notify = [];
const SHEET = SpreadsheetApp.getActiveSheet();
const DATA = SHEET.getDataRange().getValues();
const MAX_PERSON_ID = DATA.map(person => person[0]).reduce((a,b) => a>b?a:b);
const ENDPOINT = "http://www.pref.hokkaido.lg.jp/hf/kth/kak/hasseijoukyou.htm";
const CONTENT = UrlFetchApp.fetch(ENDPOINT).getContentText('UTF-8');
const INFECT_DATA = CONTENT.replace(/ /g,'').replace(/\r?\n/g, '').match(/<tr>.*?<\/tr>/g);
for(let infectPerson of INFECT_DATA) {
const INFO = infectPerson.match(/<td>.*?<\/td>/g);
const ID = INFO[0].replace(/<.*?>/g, '').replace(/./g, s => String.fromCharCode(s.charCodeAt(0) - 0xfee0));
const DATE = INFO[1].replace(/<.*?>/g, '');
const AGE = INFO[2].replace(/<.*?>/g, '');
const SEX = INFO[3].replace(/<.*?>/g, '');
const RESIDENCE = INFO[4].replace(/<.*?>/g, '');
if (ID > MAX_PERSON_ID) {
const mes = "\n" + DATE + " | " + ID + "例目" + " | 年齢: " + AGE + " | 性別: " + SEX + " | 居住地: " + RESIDENCE;
notify.push(mes);
SHEET.appendRow([ID, DATE, AGE, SEX, RESIDENCEP]);
}
}
if (notify.length > 0) {
slack(notify);
}
}
function slack(notify) {
const ENDPOINT = "https://hooks.slack.com/services/TEAMID/BOT/TOKEN";
const TEXT = "北海道内の最新コロナ感染状況です。" + notify.join("");
const BODY = {
"text": TEXT
};
const PAYLOAD = JSON.stringify(BODY);
const OPTION = {
"method": "post",
"contentType": "application/json",
"payload": PAYLOAD
};
UrlFetchApp.fetch(ENDPOINT, OPTION);
}