重複投稿を防ぐしくみ
前回までで、Google Apps Script(GAS)とSlackのWebhookを連携し、arXivの最新論文情報を自動投稿するBotが完成しました。
ただし、このままだと同じ論文を何度もSlackに投稿してしまう可能性があります。
今回はこの問題を解決するために、「投稿済みの論文IDを記録し、次回以降はスキップする」という仕組みを実装します。
投稿済みの論文をどうやって判別する?
arXivのフィードには、すべての論文に固有の id
(例:http://arxiv.org/abs/2405.12345
)があります。
この id
をスプレッドシートに保存しておけば、「前回までに投稿済みかどうか」を判別できます。
スプレッドシートに「Posted」シートを追加
シート名:Posted(列は1列のみ)
A列(arXiv ID) |
---|
http://arxiv.org/abs/2405… |
http://arxiv.org/abs/2405… |
このシートに投稿済みの論文IDを蓄積していきます。
getPostedIds() ― 投稿済みID一覧を取得
まずは記録されているIDを配列で取得する関数です。
ただし、シートが空の場合はエラーになるので、例外を防ぐチェックを入れます。
function getPostedIds() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Posted');
if (!sheet) return [];
const lastRow = sheet.getLastRow();
if (lastRow === 0) return [];
return sheet.getRange(1, 1, lastRow, 1)
.getValues()
.map(row => row[0]);
}
savePostedId() ― 投稿が終わったらIDを記録
新しい論文を投稿した後は、Posted
シートにIDを追加しておきましょう。
function savePostedId(arxivId) {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Posted');
if (!sheet) return;
sheet.appendRow([arxivId]);
}
postArxivToSlack() に統合する
メインの投稿関数を以下のように改良しましょう。
function postArxivToSlack() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
// Posted シートがなければ作る
if (!ss.getSheetByName('Posted')) {
ss.insertSheet('Posted');
}
const settings = getSettings();
const SLACK_WEBHOOK_URL = settings['SLACK_WEBHOOK_URL'];
const CATEGORY = settings['CATEGORY'] || 'cs.CL';
const MAX_RESULTS = parseInt(settings['MAX_RESULTS'], 10) || 5;
const postedIds = getPostedIds();
const url = `http://export.arxiv.org/api/query?search_query=cat:${CATEGORY}&sortBy=submittedDate&sortOrder=descending&max_results=${MAX_RESULTS}`;
const response = UrlFetchApp.fetch(url);
const xml = response.getContentText();
const doc = XmlService.parse(xml);
const entries = doc.getRootElement().getChildren('entry', doc.getRootElement().getNamespace());
entries.forEach(entry => {
const ns = doc.getRootElement().getNamespace();
const arxivId = entry.getChildText('id', ns).trim();
if (postedIds.includes(arxivId)) {
Logger.log(`Skip duplicate: ${arxivId}`);
return;
}
const title = entry.getChildText('title', ns).trim();
const summary = entry.getChildText('summary', ns).trim();
const payload = {
text: `*${title}*\n${summary}\n<${arxivId}|Read more>`
};
UrlFetchApp.fetch(SLACK_WEBHOOK_URL, {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload)
});
savePostedId(arxivId); // 記録!
});
}
動作確認
- スクリプトを実行(初回はすべて投稿される)
Posted
シートにIDが記録される- 次回以降、同じIDは投稿されずスキップされる
おまけ:投稿済みデータをリセットしたいときは?
Posted
シートの中身を手動で削除すればOKです。空になった状態でスクリプトを動かすと、再度すべて投稿されます。
まとめ
このパートでは、**同じ論文を何度もSlackに投稿しないための「重複防止機能」**を実装しました。
Posted
シートに投稿済みIDを記録getPostedIds()
で過去投稿をチェックsavePostedId()
で新規投稿を保存- シートが空でも落ちない安全設計に!
次回は、投稿メッセージを翻訳付きにしたり、キーワードフィルターをつけたり、より便利な機能を紹介していきます。