Kuportの情報取得するgem作った

この記事は Kogakuin Univ Advent Calendar 2016 - Adventar の15日目です。
かなり遅れました、ほんとすみません。

概要

github.com

みんな大好きkuportからデータを取得してJSONに変換して出力します。
ライブラリとしても使用可能です。
MechanizeとかNokogiri使いました。

詳細はREADME.md

データは全てJSONに変換されるため jqjid で閲覧してください。

jidは見ての通りインタラクティブにフィルタできるのでおすすめです。
ただ、マルチバイト文字の間にスペースが入るのが欠点です。

https://github.com/simeji/jid/wiki/images/demo-jid-main-640.gif

※内部の情報を公開するのは良くない気がするので、実行結果のスクショありません。

導入

gem install kuport

最新の機能は避けたつもりですが、古いRubyだと動かないかもしれません。

使い方ざっくり

--idで学籍番号を指定して実行するとパスワードが求められます。
キャシュが効くので一度ログインしたら暫く--idは不要です。

ログイン

$ kuport --id jx99123 
Pasword>

個人宛お知らせを取得

各メッセージのタイトル、内容、リンクを取得します。
-mオプションにreadを渡すと既読メッセージを取得できます。

$ kuport -m > messages.json

jidで閲覧

$ kuport -m | jid 

メッセージの添付ファイルをダウンロード

kuport -m | jidでメッセージをフィルタリングしてリンクを出力すれば添付ファイルをダウンロードできます。
--downloadには-mで取得したリンク要素のJSONをそのまま渡せます。 JSONを渡せばブラウザでダウンロードするのと違ってまともなファイル名を付けてくれます。

$ kuport --download "$(kuport -m | jid)"
jqでフィルタリング

添字でメッセージを選択できます。

$ kuport --download  "$(kuport -m | jq '.[0].links')"

時間割

時間割がJSONとして出力されます。
jid使ってもかなり見づらいです。

$ kuport -t | jid

ライブラリとして

おおまかな使い方

require 'kuport' 
kp = Kuport.new 
kp.login('jx91234')

messages = kp.messages
timetable = kp.timetable

m = messages[0]
puts m.title, m.body, m.links
puts m.json
puts messages.to_json

timetable.compact
puts timetable.to_json

kp.download(url, name)
kp.download([{name: 'File.pdf', path: 'https://example.com/file.pdf'}, ])

kp.cookies_clear # Logout

ハマったこと

文字コードが合わなくてパース中にエラー

CharsetはEUC-JPなのにCP932が混ざってるページがあって困りました。
幸いにもMechanizeはパーサを指定できるので、強制的にUTF-8に変換して処理するパーサを作りました。

MechanizeをrequireするとStringtoutf8メソッドが加わるので、それを使用します。

class Parser
  def self.parse(text, url = nil, encoding = nil, options = Nokogiri::XML::ParseOptions::DEFAULT_HTML, &block)
    Nokogiri::HTML::Document.parse(text.toutf8, url, 'UTF-8', options, &block)
  end
end

agent = Mechanize.new
agent.html_parser = Parser 

お知らせに共通するCSSクラスが無い

お知らせのクラスはざっと見た所3つありました。

  • message_normal
  • message_emergency
  • message_check

Nokogiriでクラス指定で要素を抜き出すときはcssメソッドが使えますが、これは正規表現ワイルドカードは使えないようです。
上記3つにマッチする要素を取り出すにはxpathメソッドを使いました。

doc.xpath(".//*[contains(@class, 'message')]")

これでクラス名に'message'を含む要素を取得できます。
xpathなかなか強力ですね。

TODO

  • 電子教材一覧
  • インターフェース(TUI)
  • テスト

終わり

なぜか公開後数分で10DL超えました。
間違って入れる人が沢山いるようですね。

当初はncurseswを使ってUI作ろうと思ってたんですが挫折しました。
padが表示されない...
Curses::Padが動いたのでTUI作成中。

バグがあったりしたら、なんでもいいので気軽に連絡してください。
プルリク大歓迎です。