Help us understand the problem. What is going on with this article?

最新のハッカソンの開催情報を自動で集めて、お知らせするBotを作ったので頭の中を紹介

ハッカソンポータル

新着のハッカソン・ゲームジャム・アイディアソン・開発合宿の情報を自動的にお知らせしているBotです。よかったらフォローしてください!!

ちなみに頭の中(ソースコード)はこちらで公開しています。
hackathon_portal

QiitaやGoogleカレンダーの方がよりまとまった情報として紹介しています。
また、現在、日本で開催する情報を中心にお知らせしていますが、海外でこのような情報を収集できるサイトがあり、ニーズがありそうでしたら導入を検討します。

ボードゲームマニア

こちらは上記ハッカソンポータルの技術とほとんど同じことをして、違うコンセプトのものを作りました。
こちらはボードゲーム・アナログゲームについて近日開催されるイベントを紹介しているBotです。こちらもよかったらフォローしてください!!

本家サイト: BoardGameMania
頭の中(ソースコード)はこちらです。
board_game_mania

ボードゲームマニアではTwitterのみで紹介していますが、ご要望がありそうでしたら、QiitaやGoogleカレンダー連携したものも作成します。

技術的にはほとんど同じことをしています。
以降に技術的な解説もしていきます。

作成目的

インスパイア

2017年のハッカソン開催情報まとめ!
こちらの記事では手動で集めてくださっていました。そこで、「これ、自動的にデータを収集して、お知らせできるようにしたらいいのでは?」と考え、作成することにしました。

方針・コンセプト

  1. 自動化 手動で情報を収集、公開していたのでは膨大な労力がかかり、運用コストが大きいため、継続的に情報を発信し、続けることが難しくなってしまいます。そのため、この問題の解決のため、ほぼ自動で情報を収集、発信することができるようにしました。
  2. 定常化 情報は定期的に更新されるため、定期的に最新の情報を取得し、お知らせし続けられるようにする。
  3. 省コスト 個人でやっていくので、サーバーなどを持って運用すると、サーバー費用がかかてしまい継続的に運用することが難しくなります。(お金かけたくないし...) そのため、既存のWebサービスをフル活用することで、サーバーへのコストや負荷を抑え、サーバーを立てなくても運用できる形にしました。(実際は後述しますが常時運用のためサーバーを使用しています)

使用しているツール

使用しているツール

  • Ruby
  • Rails
  • Whenever
  • Nokogiri
  • MySQL

情報を集めているサービス

このほかに追加で収集してほしいサービスとかありましたら、issueなどで述べてください。また、管理ツールもあります。管理ツールを使ってみたい!!など、希望の方は個別にご連絡ください。

告知しているサービスおよびAPI

  • Twitter API
  • Qiita API
  • Google Calendar API

ランニングコスト

使用環境

  • AWS LightSail $5/月 プラン環境 aws_lightsail_price.png
  • OS: Ubuntu 18.04 LTS

解説

サーバーを立てる経緯

上記、ハッカソンポータルとボードゲームマニア他と共通のサービスを1つのサーバーで運用していまします。
サーバーを利用した理由として、常駐させる場合、自宅のデスクトップPCの電源を常にONにするので、電気代がかさむのと以下のルーチンのバッチ処理を実行中の時、CPU負荷が高くなり、一時的にPCがもっさりすることがあるので専用のサーバーを立てることにしました。

環境について

AWS Lightsailの5/月ドルにした理由は余計なデータをMySQLに保存しすぎてしまったためストレージが20GB SSDでは足りなかったためです。今後データを整理すれば、 3.5/月ドルのプランに置き換えるかもしれません。
(なお、3.5/月ドルで十分に稼働して、運用できることはすでに確認しました。)
以前はさくらのVPS、CentOS6の環境で運用していましたが、AWS Lightsailの方が安いのと、CentOSよりもUbuntuの方がほかの各種ライブラリとの親和性(Dockerとか)が高いため置き換えました。

Ubuntu 18.04 LTSの導入方法

AWS Lightsailでは初期設定ではUbuntu 16.04 LTSのみ導入することができます。AWS Lightsailでインスタンスを作成した後、sshでログインし、

do-release-upgrade 

と入力することでUbuntuのOSをUbuntu 18.04 LTSにアップグレードすることができます。

技術的な部分の紹介

基本的なルーチン

基本的に2種類のバッチを毎日定時に実行しています。

  1. 主にイベント告知サイトで新しく募集されたイベント情報をWebAPIまたはHTMLスクレイピングして情報をデータベースに貯める(Input)
  2. データベースに貯まっているデータの中から未来に開催され、Twitter, Qiita, Google Calendar(今後発信先が増える場合があります)において、まだ情報を発信していないイベント情報のみ、新たに発信する(Output)

これらのバッチを1 → 2の順番に毎日一定時刻になったら実行するようにしています。
現在、11時に1.のバッチを実行し(バッチが全て実行し、終わっているはずの)19時に2.のバッチを実行し、告知しています。

ハッカソンイベントなのかどうかの判別

表記ゆれのカバー

一言で「ハッカソン」と言っても表記は様々でした。「ゲームジャム」や「アイディアソン」もハッカソンの一種のため、集めた情報を発信する場合に精査して、発信するものを選別するようにしました。今回では、"hackathon", "ッカソン", "jam", "ジャム", "アイディアソン", "アイデアソン", "ideathon", "合宿"を精査対象とする条件としました。(詳しくはこちら)
全角、半角問題の区別は、charwidthを使い置き換えることでカバーしています。ひらがな表記は意図しないものが多く取れるため除外しています。
使い方についてはこちらを参照してください。
Ruby / Rails で全角・半角をいい感じに変換しよう!

ハッカソンなどと関係なさそうなイベントは除去

タイトルだけで判別するとハッカソンイベントであってもハッカソンでないと判別されるケースが多く発生し、本文で判別すると、明らかにハッカソンイベントではないものをお知らせしてしまうケースが多くありました。そこで、本文の中に含まれるキーワードでスコアを算出し、一定のスコア以上のものをイベントをハッカソンイベントとするようにしました。
(詳しくはこちら)

自動投稿

情報を投稿するにはAPIを利用する必要があります。基本的には投稿するにはOAuth認証が必要で、そのためにはサーバーを立ててエンドポイント作る必要があります。しかし、今回、使用しているサービスではエンドポイントを作ることなく自動的に投稿するBotの形にしました。このような形を実装する方法を以下に紹介していきます。

Twitterへの自動投稿

  • Twitter Appへとアクセスし、Twitterアプリを開発するための登録をする
  • 作成されたアプリを選択し、「Keys and Access Tokens」を選択する。 KeyAndAccessToken.png
  • 作成されたアプリからAccessToken(とAccessTokenSecret)を生成する。 twitter_accesstoken.png

ここで生成されたConsumer Key, Consumer Secret, Access Token, Access Token Secretを用いてTwitter::REST::Clientを生成し、updateメソッドを呼び出すことで、ツイートすることができます。
詳しくはこちらを参照してください。

Qiitaへの自動投稿

こちらで詳しく、記載があります。Qiita gemを使ってみる!

  • Qiita → 「設定」を開き、「アプリケーション」を選択する。
  • 個人用アクセストークンの中の「新しくトークンを発行する」を選択して、アクセストークンを発行する
  • 発行したアクセストークンを用いて、Qiitaに投稿する。

詳しくはこちらを参照してください。

Googleサービス(Googleカレンダー)への自動投稿

ハッカソンの開催情報をGoogleカレンダーに投稿するときに使用しました。
Googleのサービスに投稿するためには、上記のようなものとは別に本来ならエンドポイントが必要なOAuth認証が必要です。今回はエンドポイントを作らないでOAuth 2.0 Playground(Google APIにおけるOAuth認証を試し打ちするサイト)を使ってGoogle APIにPOSTする方法を紹介します。

  • Google Cloud Console → 「APIの概要に移動」 google_api_console.png
  • 「APIとサービスの有効化」を選択し、利用したいGoogleのサービスのAPIを有効にする。そして、「認証情報」を選択する auth_and_api.png
  • 「認証情報を作成」 → 「OAuth クライアントID」を選択 create_oauth.png
  • 「承認済みのリダイレクトURI」にhttps://developers.google.com/oauthplaygroundと入力し保存する redirect_uri.png
  • OAuth 2.0 Playgroundにアクセスする。設定アイコンを選択し、商事するプルダウンの中の「OAuth Client ID」と「OAuth Client Secret」の中に先ほど作成したことでできた、「クライアントID」と「クライアントシークレット」をそれぞれ入力し、OAuth認証する、Googleのサービスを選択して、チェックを入れる。そうすることで、「Authrize APIs」のボタンが有効になるのでそのボタンを押してOAuth認証を開始する。 oauth_service.png
  • OAuth認証が無事成功するとOAuth 2.0 Playgroundに戻ってきてSTEP2の項目が自動的に埋まっている。この状態で、「Exchange authorization code for tokens」のボタンを押すと、Refresh tokenとAccess Tokenの項目に文字列が入力されます。Googleの場合、Access Tokenは時間とともに使えなくなるため、Refresh tokenの値をコピーして控えます。 refresh_token.png

以降はrubyにてgoogle-api-ruby-client を使った認証の処理になりますが、他の言語でも似たような形で実装できます。
rubyではSignet::OAuth2::Clientインスタンスの中に認証に必要な情報を詰め込みます。
以下のように、OAuth認証に必要なものはクライアントID,クライアントシークレット,そして先ほど控えたrefresh tokenの値を指定することで、エンドポイントなしでOAuth認証することができます。(refresh tokenは名前の通り、新しいaccess tokenを作るためのものなので、期限内のaccess tokenがあるのなら、それを指定した方がいいです。)

oauth_client = Signet::OAuth2::Client.new
oauth_client.client_id = ENV.fetch("GOOGLE_OAUTH_CLIENT_ID", "")
oauth_client.client_secret = ENV.fetch("GOOGLE_OAUTH_CLIENT_SECRET", "")
oauth_client.authorization_uri = "https://accounts.google.com/o/oauth2/auth" 
oauth_client.token_credential_uri = "https://accounts.google.com/o/oauth2/token"
oauth_client.refresh_token = refresh_token

詳しいソースコードはこちら
そして、上記で情報を詰め込んだSignet::OAuth2::Clientインスタンスを以下のようにGoogle::Apis::CalendarV3::CalendarServiceインスタンスの認証情報に指定します。

require 'google/apis/calendar_v3'

service = Google::Apis::CalendarV3::CalendarService.new
service.authorization = oauth_client

こうすることで、この場合、Google::Apis::CalendarV3::CalendarServiceインスタンスであるserviceから、Googleカレンダーの各種APIを呼び出して利用することができるようになります。
あとはGoogleカレンダーにハッカソンの日程情報を書き込んで反映させていくことで、自動的にGoogleかれんだーに情報が書き込まれます。
詳しい処理はこちらを参照してください。

非公式API(HTML)へのアクセスと情報の取得と解析

Peatixからイベント情報を取得するときに使用しました。
ConnpassAtndなど、
どのようなWebサイトにも当てはまるのですが、Webブラウザで表示できている以上、通信状況を解析して、通信を送る場合の法則性を見つけることができれば、非公開APIやHTMLを解析して情報を取得することができます。
こちらでやり方などを解説しています。
画像クローラー
こちらと同様にブラウザのDeveloperToolのNetworkを開き、送られているリクエストの一覧を調べます。
network_profile.png
このリクエストの中から該当のリクエストを探し当て、試し打ちを繰り返して、法則性を見つけ出すことで、非公式APIやHTMLからの情報を取得できるようにしています。
(具体的な処理についてはこちらを参照)

今後の展望

  • 海外のハッカソンなど、インプット先のソースを増やしていきたい
  • ハッカソンやボードゲーム以外の情報においても、この技術を応用して、特定のジャンルの情報を自動的に発信し続けるものを作成したい
  • 囃しなどイベントが盛り上がるようなことも自動的にできるようにしてみたい

など、ほか、ご要望がありましたら申し付けてください。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした