arXivの論文をチェックするbot

AIの最新の動向を追いたいならarXivをチェックしないわけにはいきません!

しかし、

自分の業界のキーワードにマッチする論文は数ヶ月に1回あるかないか...

毎日チェックするのは面倒

そこでボットを作ってチェックすることにしました

システム構成

システムは以下のような感じです。 今回も?Herokuを使います。無料バンザイです。

f:id:sanshonoki:20190302220149p:plain

arXivにはAPIが用意されているのでrubyスクリプトからarXivAPIを叩きます。

rubyスクリプトをHerokuにデプロイし、スケジューラアドオンを追加し定期実行させます。 通知済みの論文の履歴はDB(postgresql)に保存し、新しい論文だけを通知します。

arXivAPI

arXivAPIが用意されています。 GETだけでのシンプルなものなので使い方は簡単です。 Perl, Ruby, Python, PHPの簡単なサンプルも用意されています。 ただ、レスポンスがJSONではなくXMLなのでパースは若干面倒。

慣れないXMLに少しハマりかけましたがググって解決。

APIを叩いてパースするコアとなるコードはこちら

  def search(keywords, max_results = 3)
    query = build_query(keywords)
    url = URI.parse("http://export.arxiv.org/api/query?search_query=#{query}&start=0&max_results=#{max_results}&sortBy=submittedDate&sortOrder=descending")
    res = Net::HTTP.get_response(url)

    xml = res.body
    doc = REXML::Document.new(xml)

    # https://medium.com/tech-batoora/xml-50488ec69b20
    entries = REXML::XPath.match(doc, '//feed/entry').map do |entry|
      {
        id: entry.elements['id'].text,
        updated: Date.parse(entry.elements['updated'].text),
        published: Date.parse(entry.elements['published'].text),
        title: entry.elements['title'].text,
        summary: entry.elements['summary'].text
      }
    end
    entries
  end

  private

  def build_query(keywords)
    cat = 'all'
    keywords.inject('') do |param, kw|
      if param.empty?
        param = "#{cat}:#{kw}"
      elsif kw.start_with?('+')
        param = "#{param}+OR+#{cat}:#{kw[1..kw.size]}"
      elsif kw.start_with?('!')
        param = "#{param}+ANDNOT+#{cat}:#{kw[1..kw.size]}"
      else
        param = "#{param}+AND+#{cat}:#{kw}"
      end
      param
    end
  end

40行ちょっとのコードです。keywordのANDやORも指定できるので一部対応しました。 (自分の関心のある論文はキーワード1個で十分なので対応してなくもよかったけど)

通知

通知先はとりあえずとしてメールとSlackです。

Slackは前に使ったことのあるslack-notifierのgemを利用させてもらい、WebHook URL経由で送信します。

メールはGmailSMTPサーバーを使って送ります。

テストでGmailから送ってみると Net::SMTPAuthenticationError が出力されてしまいました..。

あれ?以前他のプログラムからメール送信していたときはこんなの出てなかった気がするけど

と思ったけどコードにコメントが残っていて実は対策をしていた。。

今回も同じ対策をします。

Gmail を使って Net::SMTPAuthenticationError が出力される場合の解決法 - 大学生からの Web 開発」の通りにやればok。

Googleアカウントのページにいって、セキュリティの変更をします

  • 二段階認証を設定し、その後アプリ用のパスワードを発行する
  • もしくは、「安全性の低いアプリのアクセスを許可」


1年ぶりのrubyのコーディングで少し手こずりましたが無事稼働するようになりました。 気長に論文を待とうと思います。

と思ってたら、こんな感じでいきなり通知がやってきました!

f:id:sanshonoki:20190301233651p:plain

やったー。想像してた以上に便利でうれしい

今回のコードはこちら。もし興味ある方がいたらのぞいてみてください github.com

今回までやったことなかったのですがHerokuはwebアプリじゃなくてもデプロイできちゃうんですね。 今後もお世話になろうと思います。