📆

使いやすくなったconnpassのAPIで、イベント一覧をメールで毎日通知する【GAS】

に公開

1. はじめに

1.1 課題

技術イベントや勉強会で刺激を受けるのが好きで、connpassをよく使っています。

基本的には大好きなサービスなのですが、「自分で主体的にconnpassのサイトにアクセスして探しにいく必要があること」と「参加できる時間や場所に合うよう絞り込まないといけないこと」を少々手間に感じていました。

そのため、一定のやる気がある時期じゃないと、そもそもconnpass開かない、となりがちで、おもしれーイベントの情報が流れ去って行ってしまい、後からよく過去のおもしれーイベントの情報を見つけて、(゚*´Д⊂グスンと思っておりました。

1.2 作ったもの


この課題をなんとかしたくて、「平日夜または日曜」かつ「東京または神奈川」で開催されるイベントだけを毎日自動でチェックし、毎日メール通知してくれるスクリプトをGASとconnpassのAPIで作りました。

イベント名に「LT」を含む、とか、イベント名に「Ruby」を含まない、みたいな絞り込みも、今回と同じ方法で実現可能です。そのため自分が興味ある技術とかに応じて調整して使えると思います。

2. 使用技術

Google Apps Script (GAS)

無料で定期実行ができることや、Gmailとの連携が簡単に行えることから、基本の処理にはGASを使うことにしました。

connpass API

スクレイピングすることも考えたのですが、connpassは規約にスクレイピング禁止を明記しているので、「さすがにだめか...ショボン」と思ってconnpass APIを使うことにしました。
connpass APIには利用申請が必要なので、このフォームから事前に申請します。

https://docs.google.com/forms/d/e/1FAIpQLScLAulm95yER9bppbDRiR6ZiVVDf1P4-PiIqNdzWJGc001ncQ/viewform

API利用目的について結構雑に書きましたが大丈夫でした。数日で承認されAPIキーがメールで送られてきました。

3. 処理の流れ

①connpassのAPIにアクセスする

2日後に開催予定の、東京・神奈川・オンライン開催のイベント一覧を取得します。
開催日や都道府県をパラメータで指定する方法については公式ページに書いてあります。
https://connpass.com/about/api/v2/#tag/イベント/operation/connpass_event_event_api_v2_views_event_search
APIをたたくと、↓のような感じのJSONが返ってきます。
情報もりだくさんで本当にありがとうございます。

②イベントを条件でフィルタリングする

取得したイベントに対して、歯を食いしばりながらIF文を書いて、次の条件に合うものだけを残します:

  • 日曜開催 または 平日19時以降に開始(オンラインの場合は18時以降)
  • 申し込み人数が2人以上

③条件に合うイベントをメールで通知

該当イベントがあれば、自分宛にGmailで通知が届きます

一連の流れができたら、GASで毎日自動実行されるように、トリガー設定をします。
私は毎日17時~18時の間に通知されるようにしました。

実際のコード(そこまで大したことはしていないです)

myFunction()

👉メイン関数。いろんな関数を呼び出します。

function myFunction() {

  const DAY_OFFSET = 2; // 今日から何日後のイベントを対象にするか(例: 2日後)

  var asatte = new Date();
  asatte.setDate(asatte.getDate()+DAY_OFFSET);  // 2日後の日付を取得

  const events = fetchConnpassEvents(targetDate=asatte);  // connpass APIからイベント一覧を取得

  const ok_events = filterEvents(events); // 条件に合致するイベントをフィルタリング

  sendMail(asatte, ok_events);  // フィルタ結果をメールで通知
}

fetchConnpassEvents()

👉 connpassのAPIから、指定日・東京/神奈川/オンラインのイベントを取得します。

function fetchConnpassEvents(targetDate){

  // 指定した日付のイベント一覧を取得する関数

  const targetMonthNum = targetDate.getMonth() + 1;
  const targetDateNum = targetDate.getDate();

  const targetMM = String(targetMonthNum).padStart(2,"0");  // 月を2桁形式に整形
  const targetDD = String(targetDateNum).padStart(2,"0");  // 日を2桁形式に整形
  const targetYear = targetDate.getFullYear();

  var options = {
    "method": "get",
    "headers": {
      "X-API-Key": "hogehogehogehoge", // 自分のAPIキーを書く
      "User-Agent": "esusaki" //ここは適当に好きな名前を書いていいっぽい
    }
  }

  var response = UrlFetchApp.fetch(`https://connpass.com/api/v2/events?ymd=${targetYear}${targetMM}${targetDD}&prefecture=tokyo,kanagawa,online&order=2&count=100`, options); // 日付・地域を指定してAPIを呼び出し

  var data = JSON.parse(response.getContentText());

  if(data["results_available"]===0){
    throw new Error("検索結果が0件でした。")
  }

  if(data["results_available"] > data["results_returned"]){
    throw new Error("検索結果が多いため、すべてを取得することができませんでした。")
  }

  var events = data["events"];

  events.reverse(); // デフォルトだと開催日時で降順になっているが、昇順にする

  return events;
}

filterEvents()

👉 平日19時以降(オンラインなら18時以降)や日曜のイベントで、参加者2人以上のものをフィルタリングします。

function filterEvents(targetEvents){ 

  //イベントの一覧から「参加しやすい時間」「すでに申し込みしている人数」の条件にあうものをフィルターする
  
  var events_ok = [];

  function is_time_place_ok(start_time_string, address){

    const start_time = new Date(start_time_string);
    const dayIndex = start_time.getDay();

    // 日曜→OK
    if (dayIndex==0){
      return true
    }

    // 土曜→NG
    if (dayIndex==6){
      return false
    }

    // 平日19時以降→OK
    if (start_time.getHours() >= 19){
      return true
    };

    // 平日18時以降 かつ オンライン→OK
    if (start_time.getHours() >= 18 && address == "オンライン"){
      return true
    }
    return false // 上記以外は参加しづらいため除外
  }

  targetEvents.forEach(
      (event)=>{
          if (event["accepted"] >= 2 && is_time_place_ok(event["started_at"], event["address"])){
            events_ok.push(event);
          }
      }
  )

  if (events_ok.length===0){
    return;
  } 

  return events_ok;
}

sendMail()

👉 フィルタ後のイベントをHTMLメールに整形し、自分宛に送信します。

function sendMail(targetDate, events){


  var mailBody = "" // HTMLメール本文を初期化

  function event2HTML(e){
    // イベント情報をHTML形式に整形(タイトル・場所・日時)
    return `<p><h1 style='font-size:18px'><a href='${e["url"]}'>${e["title"]}</a></h1><div>${e["address"]}</div><div>${e["started_at"]}</div></p><hr>`
  }

  events.forEach(
    (ok_event)=>{
      if (ok_event["address"]!="オンライン"){
        mailBody += event2HTML(ok_event); // メールのなかでオフラインイベントを前半に表示させたい
      }
    }
  )

  events.forEach(
    (ok_event)=>{
      if (ok_event["address"]=="オンライン"){
        mailBody += event2HTML(ok_event); // メールのなかでオンラインイベントを後半に表示させたい
      }
    }
  )

  const targetMonthNum = targetDate.getMonth() + 1;
  const targetDateNum = targetDate.getDate();

  GmailApp.sendEmail(recipient = "example@gmail.com",
                     subject = `${targetDate.getFullYear()}年${targetMonthNum}月${targetDateNum}日のおすすめconnpassイベント`,
                     body = "",
                     {htmlBody : mailBody} // HTMLメールとして送信
            ) 
}

4.おわり

実はconnpassのAPIは、色々と仕様変更が多く、昔は気軽に使えたのですが、ある時期からは固定IPが必要になり、個人で使うハードルが高いものでした。しかし、つい先日(ちょうど3か月前!)API v2がリリースされて、固定IPが不要になり 無料で安定して使えるようになりました㊗
https://x.com/connpass_jp/status/1907605187671503309

ありがとう、connpass!

とは言え、この調子だと1-2年後にはAPI有料化されてる可能性もある 便利なものは、使えるうちは使っておこう! ということで今回のスクリプトを作りました!㊗

おまけ:効果


これを使い始めて以来、1週間で3回という異常なペースで技術イベントに参加することに成功しました!w
自分、チョロすぎる...

Discussion