学校の休講補講情報をSlackに送ってみた話
こんばんは.nanaminです.
今回はプログラミングネタです.
読み返したら英単語とかカタカナの登場率がすごくて引いてる.でも固有名詞とか用語とかだからしょうがないです.
事の経緯
休講や補講の情報は学校のHPに掲載されるのですが,いちいち見に行くのも面倒.さらに教授が口頭でお知らせする場合もあるので,休講や補講の把握はかなり億劫でした.
そこで,休講補講情報をSlackに通知するWebアプリケーションを作ろうとなりました.あと最近Railsをやり始めてなにか作ってみたかったというのもあります.
結果
べんり〜
材料
開発に使ったものたち
- Web Application FrameworkとしてRuby on Rails (5.2)
- Web ScrapingするためにNokogiri
- 全角半角変換用にNKF
- RubyでSlack APIを扱えるSlack Ruby Client
- 公開用サーバーとしてHeroku
- Heroku上で定期実行するためのHeroku Scheduler
実装方法
まずはリポジトリへのリンクを貼っておきます(結論優先オタク)
概要
とりあえず,処理の流れから
- 休講補講情報が載っているページをNokogiriでScrapingする
- データベースへ保存して,前回Scrapingしたときとの差異をチェック
- 差異部分をSlackのチャンネルにpost
- また休講or補講日の前日にもリマインド用としてSlackにpost
定期実行するため, 1〜3と4をrakeタスクとしてまとめておきます
Scraping部分
ここが一番肝だったりする.なぜなら半角と全角が混在しているから...
僕の学校の休講補講情報は,1つのtable要素で1つの休講or補講情報を表示していました.そのため,ページにある全table要素に対して,全てのtd要素の内容を取得しています.Nokogiriくんべんり.
doc = Nokogiri::HTML(open(scrape_url)) doc.css('table').each { |node| table = Nokogiri::HTML(node.to_xhtml) table_values = table.css('td').map { |node| node.content } }
また,休講補講情報のフォーマットがガバガバ 多様性にあふれ全角数字と半角数字が混在していたので,NKFを使って半角に変換します.
# 全角英数字を半角英数字,全角スペースを半角スペース,半角カナを全角カナに変換 # さらに先頭と末尾の空白を除去 converted = NKF.nkf('-wZ1X', scraped_str).strip
あとはいつも通りデータベースとやり取りするだけです.
Slack用delivery_methodの実装
Slackへメッセージを送るには,Slack APIのchat_postMessage
メソッドを使います.
Scrapingする処理層でメッセージを送る処理を書いてもいいですが,それだと芸がないのでActionMailerを通して行うようにしてみます.
実装にあたって,以下のサイトがとても参考になりました.ありがとうございます. tech.unifa-e.com
delivery_methodは,ActionMailerのなかでmail
メソッドを使ったときに呼ばれるものです.
ここでメッセージの内容を受け取ってSlackに送信する処理を記述します.
class SlackMessageDeliveryMethod def initialize(value) self.settings = value end def deliver!(message) attachments = JSON.parse(message.body.to_s) channel = message['channel']&.value || self.settings[:default_channel] client = Slack::Web::Client.new(token: self.settings[:api_token]) client.chat_postMessage( channel: channel, attachments: [attachments], as_user: true ) end end
Slack用delivery_methodを登録
実装したdelivery_methodをActionMailer::Baseに登録します. ちなみに登録するとxxx_settingsというメソッドが自動で定義されるので,そこで初期化時のパラメータ(トークンなど)を渡しておきます. トークンを公開すると誰でもSlackにメッセージを送れるようになってしまうので,環境変数を使って隠蔽しましょう.
ActionMailer::Base.add_delivery_method(:slack_message, SlackMessageDeliveryMethod) ActionMailer::Base.slack_message_settings = { api_token: ENV['SLACK_API_TOKEN'], default_channel: ENV['SLACK_DEFAULT_CHANNEL'], }
送りたいメッセージを作成する
あとは,送りたいメッセージの内容を作成してmail
メソッドを呼び出すだけです.
僕はruby側でjson形式のデータを作成し,それをviewに埋め込むだけにしています.
class LectureMailer < ApplicationMailer default delivery_method: :slack_message def new_info(lecture) @attachments_json = { fallback: '新しい休講補講情報です', color: 'good', pretext: '新しい休講補講情報です', fields: to_attachment_fields(lecture), }.to_json mail end def to_attachment_fields(lecture) # 講義情報をSlack APIの引数のフォーマットに変換する end end
rakeタスクを作成
Heroku Schedulerで定期実行してもらうために,
- Scrapingして変更があった情報をSlackに通知
- 休講or補講日の前日にSlackにリマインド
の2つの処理を行うrakeタスクを作成します.
実装した2つのrakeタスクはこんなかんじ.
namespace :lecture do task scrape_and_send: :environment do before_time = Time.zone.now url = ENV['SCRAPE_URL'] class_name = ENV['TARGET_CLASS_NAME'] service = ScrapeLecture::WithUrlService.new(url) service.execute! created = Lecture.where( class_name: class_name, created_at: before_time..Time.zone.now ) updated = Lecture.where( class_name: class_name, updated_at: before_time..Time.zone.now ) updated = updated.reject { |i| i.created_at == i.updated_at } # slackのメッセージレイアウトの都合上,1件ずつ送信 created.each { |info| LectureMailer.new_info(info).deliver_now } updated.each { |info| LectureMailer.update_info(info).deliver_now } end task send_reminders: :environment do now = Time.zone.now class_name = ENV['TARGET_CLASS_NAME'] canceled = Lecture.where( class_name: class_name, canceled_from: now..now.since(1.days) ) supplemented = Lecture.where( class_name: class_name, supplemented_from: now..now.since(1.days) ) canceled.each { |info| LectureMailer.canceled_reminder(info).deliver_now } supplemented.each { |info| LectureMailer.supplemented_reminder(info).deliver_now } end end
Heroku Schedulerで定期実行
HerokuではアドオンとしてHeroku Schedulerというものが用意されています. これを使うことで,指定した時間ごとに設定したコマンドを実行してくれます.
インストールやrakeタスクの登録方法はこちらで紹介されています. インストールにはクレジットカード登録済みのアカウントが必要ですが,基本的に無料で使えます.とてもべんり devcenter.heroku.com
さっきのrakeタスクを登録するとこのような画面になりました.
感想
Heroku Schedulerたすかる
Webアプリケーションって手軽にそれっぽいものつくれて公開できるから良い.