blog
更新日 : 2023/09/19
GASを利用し、RSS FeedをGoogle Chatに通知する実装例
目次
●GASを利用し、RSS FeedをGoogle Chatに通知する実装例
・概要
・Google SheetsでSpreadsheetを作成し、GASを入力
■GAS
・参考
概要
定期的にGAS (Google Apps Script)でRSS Feedを取得し、Google Chatに更新を通知する実装例を示す。 概要図は以下の通り。
Google Chatに通知するための準備
Webhookの作成
Google Chatに移動し、左上のワークスペース名をクリック、[アプリと統合]をクリックする。
[Webhookを追加]をクリックする。
[名前]、[アバターのURL]に入力し、保存をクリックする。
後で利用するので、右下のコピー用のアイコンをクリックして、WebhookのURLをコピーして、取っておく。
Webhookで通知するスレッドの作成 (スキップ可能)
作成したWebhook URLを利用して、ワークスペースにメッセージを送信する。 RSS Feedの更新を特定のスレッドに送信するため、一意なスレッドキーを生成し、指定する。
# UUIDなど同じスペース内で一意な任意の値を設定
THREAD_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
WEBHOOK_URL='https://chat.googleapis.com/v1/spaces/XXXXXXX_XXX/messages?key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
WEBHOOK_URL_REPLY_THREAD="${WEBHOOK_URL}&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD&threadKey=${THREAD_KEY}"
# textの値は、スレッドに対する最初のメッセージなので、適宜変更
curl -X POST "${WEBHOOK_URL_REPLY_THREAD}" \
-H "Content-Type: application/json" \
-d '{"text": "First message for thread"}'
Google SheetsでSpreadsheetを作成し、GASを入力
Spreadsheetを作成し、情報を入力
以下画像のようにGoogle Spreadsheetを作成し、収集するRSS Feedの情報を入力する。 シートタブは、「list」とする。
それぞれの列の意味は以下の表の通り。
列名 | 定義 | 必須 | 備考 |
---|---|---|---|
# | 文字列 | X | 入力済の場合に、通知対象になる。 そのため、その他の項目を入力後に、入力する。 |
title | 文字列 | プログラムでは利用しないため、自由に入力する。 | |
rssUrl | RSS FeedのURL | X | |
lastDate | GASのDate.parse で読み込み可能なフォーマット | 確認した入力は以下の通り。 – 2023-09-02T09:00:00+09:00 – Sun Sep 02 2023 09:00:00 GMT+0900 (Japan Standard Time) RSS Feedを取得した最新の日付が格納される。 | |
googleChatWebhookUrl | Webhookの作成で作成したWebhookのURL | X | |
googleChatThreadKey | Webhookで通知するスレッドの作成で生成したスレッドキーまたは、新規で生成するユニークなキー | X |
[拡張機能>Apps Script]をクリックし、GASの編集画面を開く。
GAS
Apps Scriptの画面に移動するので、プロジェクト名やファイル名を例えば以下のように変更する。
スクリプトとして、以下を入力する。
function main() {
// 列名に対するSpreadsheetの列番号を表す
const columnRowNum = 1;
const columnRssUrl = 3;
const columnLastDate = 4;
const columnGoogleChatWebhookUrl = 5;
const columnGoogleChatThreadKey = 6;
// RSSを取得したときに、1回でもエラーが発生したら、true
let didErrorHappen = false;
let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("list");
for (let i = 2, rowNum = sheet.getRange(i, columnRowNum).getValue(); rowNum != ""; ++i, rowNum = sheet.getRange(i, columnRowNum).getValue()) {
let rssUrl = sheet.getRange(i, columnRssUrl).getValue();
let lastDateRange = sheet.getRange(i, columnLastDate);
let lastDateStr = lastDateRange.getValue();
let lastDate = new Date(lastDateStr);
// 最後に更新した日付(lastDate)が存在しない場合に、lastDateを現在時刻から15分前にする
if (Number.isNaN(lastDate.getTime())) {
lastDate = new Date();
lastDate.setMinutes(lastDate.getMinutes() -15);
console.log(`lastDateが存在しません。${lastDate}以降のRSS Feedを調べます。`);
}
let googleChatWebhookUrl = sheet.getRange(i, columnGoogleChatWebhookUrl).getValue();
let googleChatThreadKey = sheet.getRange(i, columnGoogleChatThreadKey).getValue();
let rssInfo;
try {
rssInfo = getRssV2(rssUrl, lastDate);
} catch (e) {
console.error(e);
didErrorHappen = true;
continue;
}
rssInfo["messages"].forEach((message) => postGoogleChat(message, googleChatWebhookUrl, googleChatThreadKey));
lastDateStr = rssInfo["lastDate"].toString();
console.info(`[#${rowNum}] rssUrl: ${rssUrl}, lastDate: ${lastDateStr}`)
lastDateRange.setValue(lastDateStr);
}
if (didErrorHappen) {
throw Error("Error happens. Please see logs.");
}
}
/**
* Ver2.0のRSSからfromTime以降のpubDateのitemを取得する。
* @param {string} rssUrl - 取得するRSSのURL
* @param {Date} fromTime - fromTime以降のitemを取得
* @returns {Object} Jsonデータのオブジェクト
*/
function getRssV2(rssUrl, fromTime) {
let options = {
"method" : "get",
"contentType": 'application/xml; charset="UTF-8"',
};
const requestDate = new Date();
let response = UrlFetchApp.fetch(rssUrl, options);
let lastDate = new Date(response.getHeaders()["Date"]);
// 万が一、レスポンスヘッダにDateフィールドが含まれない場合に、リクエスト時の時間を入れる
if (Number.isNaN(lastDate.getTime())) {
console.info(`レスポンスヘッダにDateフィールドを含みません。[url: ${rssUrl}]`)
lastDate = requestDate;
}
let xmlText = response.getContentText();
// XMLを解析
let document = XmlService.parse(xmlText);
let root = document.getRootElement();
let rssVersion = root.getAttribute("version").getValue();
if(rssVersion != "2.0") {
throw new Error(`対応していない形式です。[rss version: ${rssVersion}]`);
}
// RSSフィード内の記事を取得
let items = root.getChildren("channel")[0]
.getChildren("item");
let filteredItems = items.filter((item) => {
let pubDate = new Date(item.getChild("pubDate").getText());
return pubDate.getTime() >= fromTime.getTime();
})
filteredItems.sort((item1, item2) => {
let item1PubDate = new Date(item1.getChild("pubDate").getText());
let item2PubDate = new Date(item2.getChild("pubDate").getText());
return item1PubDate.getTime() - item2PubDate.getTime();
})
let messages = filteredItems.map((item) => {
let pubDate = new Date(item.getChild("pubDate").getText());
let title = item.getChild("title").getText();
let link = item.getChild("link").getText();
return `${pubDate}\ntitle: ${title}\nlink: ${link}`;
});
/**
* @type {Object}
* @property {Date} lastDate - 取得時の時間。通常、RSS Feedに対するレスポンスヘッダのDateフィールドの時間。Dateフィールドがない場合、リクエスト時の時間。
* @property {string[]} messages - RSS Feedのitem要素の一部をテキストにしたものの配列。pubDateで昇順ソートしている。
*/
return {"lastDate": lastDate, "messages": messages};
}
/**
* Web Hookを利用して、Google Chatのスレッドにmessageを送信する。
* @param {string} message - Google Chatのスレッドに投げるmessage
* @param {string} webHookUrl - Google Chatに送信するためのWeb HookのURL
* @param {string} threadKey - Google ChatのThread Key
*/
function postGoogleChat(message, webHookUrl, threadKey) {
let url = `${webHookUrl}&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD&threadKey=${threadKey}`;
let payload = {
"text": message
};
let options = {
"method" : "post",
"contentType": "application/json",
// Convert the JavaScript object to a JSON string.
"payload" : JSON.stringify(payload)
};
let response = UrlFetchApp.fetch(url, options);
if (response.getResponseCode() != 200) {
throw Error(`failed to send message to google chat.[response code: ${response.getResponseCode()}][message: ${message}][webHookUrl: ${webHookUrl}][threadKey: ${threadKey}]`);
}
}
トリガーの作成
左上の時計アイコンにマウスオーバーをし、[トリガー]をクリックする。
右下の[トリガー]をクリックする。
例えば、以下のように設定し、[保存]をクリックする。 [時間ベースのトリガーのタイプを選択]、[時間の間隔を選択]、[エラー通知設定]など、自由に変更する。
参考
着信 Webhook を使用して Google Chat にメッセージを送信する
https://developers.google.com/chat/how-tos/webhooks?hl=ja#start_or_reply_to_a_message_thread
GASの概要
https://developers.google.com/apps-script/overview?hl=ja
GAS (Google Apps Script) のリファレンス