こんにちは、のびすけです。
管理しているアドベントカレンダーの動きを知りたい
カレンダーを投稿してくれた人がいたらとても嬉しいので、コミュニティのDiscordなどに流したいですよね。
ただここは忘れがちだったり自分で情報を見にいくのも大変です。
また、アドベントカレンダー管理者は自分が管理しているヒヤヒヤしてると思います。
ちょうどIoTLTのカレンダーでも5日目が抜けてしまっていて(誰か登録してくれていたけど気づいたらキャンセルになっていた)セルフチェックで気付けました。
キャンセル自体はよくあるので問題ないのですが早く気づけると嬉しい
そんなことを11月ほどに思って作って試してみた話です。12/25の後日談も。
Difyのスケジュールトリガーで動きの差分を検知
最近使えるようになった定期実行トリガーで QiitaのサイトからHTMLを取得して差分を検知しつつDiscordに通知する仕組み を作ってみました。
※過度なことはしてないですが、スクレイピングなのでQiitaから怒られたらやめます。
大まかな流れです。
1. アドベントカレンダーの情報を取得(A)
2. カレンダーの情報を保存しておく
3. 保存してあった前回実行時のカレンダー情報(B)と今回取得したカレンダー情報(A)を比較する
4. 比較して差分があったら差分の情報を元にDiscordに通知
こんな流れで作ってみました。
大枠はこんな流れです。
作り方
細かくは解説しないのですが、要点を紹介します。
最初はトリガーで開始する
ワークフローじゃないとトリガーは選べない ので注意です。
トリガーを選択
スケジュールトリガーを選択します。
HTMLの要素特定
アドベントカレンダーのページのカレンダー本体部分のHTMLを取得します。
HTTPリクエストノードでカレンダーのURLを指定しますが、その後にコード実行ノードでコンテンツの中身の抽出をしています。
正規表現で<table aria-label="Calendar"のあたりの要素を抜き出すと良さそうだなと思ったのでここを抽出しています。
コードは以下のように書いていて後で扱いやすいようにJSON文字列にしています。
function main({ html_content }) {
const extractedItems = [];
//ステップ1: <table aria-label="Calendar">...の部分抽出
const tableRegex = /<table aria-label="Calendar"[^>]*>[\s\S]*?<\/table>/g;
const tableMatches = html_content.match(tableRegex) || [];
const itemRegex = /href="\/([^"]+)"\s+class="style-zfknvc"[\s\S]*?<div\s+class="style-mpez5z">\s*(?:<a\s+href="([^"]+)"[^>]*>)?\s*([^<]+)/g;
//ステップ2: 取得したテーブルHTMLごとにループ処理
tableMatches.forEach(tableHtml => {
let match;
// 同じ正規表現オブジェクトを使い回すため、インデックスをリセット
itemRegex.lastIndex = 0;
// テーブル内のすべての要素に対してマッチングを行う
while ((match = itemRegex.exec(tableHtml)) !== null) {
extractedItems.push({
author: match[1], // ユーザー名
url: match[2] || null, // URL (なければnull)
title: match[3].trim() // タイトル (前後の空白削除)
});
}
});
//最後はJSON文字列へ
return {
result: JSON.stringify(extractedItems)
};
}
情報の保存 KVdb
KVdb( https://kvdb.io )というサービスがあり、簡単に文字列を書き込み&読み込みが出来るAPIサービスです。
中身の信頼などは置いておいて一時保存に便利でした。
このような形で前回の実行内容を保存しておき、今回の実行内容と比較することで差分を検出させてみました。
- 初回
- HTTPリクエスト
- コード実行
- KVDBに保存
- 2回目
- 最新を実行
- HTTPリクエスト
- コード実行
- KVDBに保存
- KVDBから初回のデータを取得
- 初回と2回目の実行を比較(LLM)
- 3回目
- (あとは繰り返し)
DSLファイル
URLなどのhttps://hogehoge.comと適当なものにしてますが多分動く気がします。
https://gist.githubusercontent.com/n0bisuke/479f3dcbb64bc1d2d1f1a9e6065e01f5/raw/3f1fc60353a69ed91923382a4d5291ad3b0e9a6d/dify-qiita-cal.yml
使える方はインポートしてお試しください。
全体はこんな感じ。
終わりに 12/25まで運用してみて
(上の章までは11月くらいに書いていて、ここから12/25の最終日に書いてます。)
結果良い感じに通知してくれてよかった!ってところもありますが概ねちゃんと運用は出来ませんでした。
キャンセルが見えるのはいいことなのか...?
xxxさん書くっていってたのになー
といったネガティブな感情が多少生まれちゃいます。
アドカレはコミュニティ文化なので仕事でもないのでカジュアルに参加やキャンセルしちゃって良いよねって僕は思ってたりしますが、これが見えちゃうと考えすぎちゃうので良くないなぁーとも思ったりしました。
結果途中からあんまりみなくなるという結果でした... 苦笑
あと多分プロンプトとKVDBからの情報取得タ&更新イミングなど何個かありそうですが差分だけ知りたいのに色々URL送ってくるタイミングもあり、精度は現状いまいちな状態です。
結局コミュニティー側には使わず
そんな感じもあり、自分用の通知限定で利用しました。
キャンセルがみんなに見えちゃうのは良くない気もしますよね。
本当はコミュニティのDiscordへいい感じに通知したかったんですけど、キャンセルの部分などの実装修正をする時間を取らずにそのまま行ってしまいました。
12月に入るとあっというまだったので11月までに仕上げておきたかったですね。
これは来年へ持ち越しです。(覚えてたら)
その他 実装学びなど
- 無料なのはありがたい
Discordは通知したりとAPIは無料で使えますし、LLMはGroq Cloudを使いましたがこれくらいの範囲で1日1回回すくらいだと無料で使えてお手軽です。
- KVdb
KVdbというサービスをしれたのは今回試して調べてみて良かった点です。これはこれで面白いのでSDK作ってみつつ記事にもしてみました。
- 他への応用
もう12/25になったので一旦このフローも止めようかと思いますが、似た仕組みは使えそうですね。
セルフ通知などの参考になれば幸いです。
アドカレお疲れ様でした!
そんなこんなでアドカレ今年は完走賞いけそうだったので狙って記事書いてましたがなんとか25記事 いけそうです。 いけました〜
管理しているIoTLTカレンダーもおかげさまで盛り上がりました!
12/27にイベントで記事振り返りもするので良かったら配信みにきてください。
今年もお疲れ様でした〜 メリークリスマス!&良いお年を!














