Slackで論文収集botを作る

目次


概要

SlackのIncoming Webhooksという機能を使うと、簡単にプログラム上からSlackに投稿ができます。その機能を用いて、Arxivから興味のある論文を自動で検索して投稿してくれるbotを作りたいと思います。

実装したプログラムはここに置いています。
https://github.com/kushanon/oreno-curator/blob/master/arxiv.py
開発環境はAnaconda2-4.3.0を用いています。

類似の機能を提供しているサービスとしては、Google Scholarのアラート機能があり、それを使うと設定したキーワードに関連する論文が投稿されたらメールでアラート送ってきてくれます。

それと比較して、今回提案するやり方の嬉しいところとしては、
  • Slack上のbotなので、botを既存の研究開発関連チャンネルに追加しておくことでスムーズな議論を行うことができる。僕の場合も、チームで研究開発をする際に、開発している内容に関連する情報を適宜教えてくれる用途で使っています。
  • 自分でプログラムを自由に書き換えられるので融通がきく
となっています。

1. arXivのAPIを通して、設定したキーワードに関連する論文を取得

arXivのAPIについての説明は、ここに概要が載っていて、ここに細かい仕様が載っています。
import urllib
url = 'http://export.arxiv.org/api/query?search_query=all:electron&start=0&max_results=1'
data = urllib.urlopen(url).read()
print data
From https://arxiv.org/help/api/index

こんな感じでHTTPのGETやPOSTリクエストを適切なURLに送ることでAPIを利用することができます。
そして、URL中のパラメータを変更することで取得する情報を変更することができます。
詳しい説明は先述のUser Manualを参照していただきたいのですが、このURLのパラメータに取得したい情報を記述します。

search_queryの部分で引っ張ってくる論文の選び方を指定できます。例えばsearch_queryで、ti:Machine\ Learningとうつと、Machine Learningという単語がタイトルに入っている論文を引っ張ってきてくれます。ti以外のprefixも色々と用意されています。例えば、Abstractはabs、catはarXivでのカテゴリーです。arXivでのカテゴリーについてもUser Manualにくわしい記載があります。
また、Boolean演算子やグルーピング演算子も使えるので細かい指定も可能です。

例えば、サンプルプログラムにあるように、
(cat:stat.ML+OR+cat:cs.CV+OR+cs.HC+OR+cs.IR)+AND+((abs:emotion)+OR+(abs:ECG)+OR+(abs:time\ series))のようにうすると、

カテゴリーが、stat.ML、cs.CV、cs.HC、cs.IRのいずれかで、アブストの中にemotion、ECG、time seriesという単語のいずれかが含まれる論文を検索することができます。


2. Incoming Webhooksを通して、対象となる論文をSlackに投稿

https://my.slack.com/services/new/incoming-webhook/にアクセスしてもらうと、

こんな画面が出てくると思います。
①の箇所でbotを追加したいSlackチームを選んで、
②の箇所でbotを追加したいチャンネルを選んで、
③を押します。

すると以下のようなページが出てきます。
④にURLがあるのでそれをメモしてください。

ちなみに、このページに書かれて居るように、botの見かけや、アカウント名を変えたり、表示する文字をカスタマイズできたりします。

PythonでこのURLにポストする場合こんな感じでかけます。
import requests
requests.post(api_url, json={"text": "Hello!!"})

api_urlの部分に先程メモしたURLを貼り付けて実行すると、設定したSlackチームのチャネルにHello!と投稿されます。


以上をまとめたPythonのプログラムは
import re
import requests
import pickle
import os
def parse(data, tag):
# parse atom file
# e.g. Input :<tag>XYZ </tag> -> Output: XYZ
pattern = "<" + tag + ">([\s\S]*?)<\/" + tag + ">"
if all:
obj = re.findall(pattern, data)
return obj
def search_and_send(query, start, ids, api_url):
while True:
counter = 0
# url of arXiv API
# If you want to customize, please change here.
# detail is shown here, https://arxiv.org/help/api/user-manual
url = 'http://export.arxiv.org/api/query?search_query=' + query + '&start=' + str(start) + '&max_results=100&sortBy=lastUpdatedDate&sortOrder=descending'
# Get returned value from arXiv API
data = requests.get(url).text
# Parse the returned value
entries = parse(data, "entry")
for entry in entries:
# Parse each entry
url = parse(entry, "id")[0]
if not(url in ids):
title = parse(entry, "title")[0]
# abstract = parse(entry, "summary")[0]
date = parse(entry, "published")[0]
message = "\n".join(["=" * 10, "No." + str(counter + 1), "Title: " + title, "URL: " + url, "Published: " + date])
requests.post(api_url, json={"text": message})
ids.append(url)
counter = counter + 1
if counter == 10:
return 0
if counter == 0 and len(entries) < 100:
requests.post(api_url, json={"text": "Currently, there is no available papers"})
return 0
elif counter == 0 and len(entries) == 100:
# When there is no available paper and full query
start = start + 100
if __name__ == "__main__":
print("Publish")
# Set URL of API
# Please change here
api_url = API_URL
# Load log of published data
if os.path.exists("published.pkl"):
ids = pickle.load(open("published.pkl"))
else:
ids = []
# Query for arXiv API
# Please change here
query = "(cat:stat.ML+OR+cat:cs.CV+OR+cs.HC+OR+cs.IR)+AND+((abs:emotion)+OR+(abs:ECG)+OR+(abs:time\ series))"
start = 0
# Post greeting to your Slack
requests.post(api_url, json={"text": "Hello!!"})
# Call function
search_and_send(query, start, ids, api_url)
# Update log of published data
pickle.dump(ids, open("published.pkl", "wb"))
view raw arXiv to Slack hosted with ❤ by GitHub
のようになります。
既にSlackに投稿したものはログをとっておき投稿しないようにし、arxivのstat.ML, cs.CV, cs.HC, cs.IRカテゴリから,アブストの中にemotion, アブストの中にECG, アブストの中にtime seriesが入っている最新の論文から順番に10本ずつSlackに投稿してくれるような仕組みになっています。 これをcronを用いて定期実行できるようにします。

3. cronを用いて定期実行できるようにする。

cronはスクリプトを自動実行できるデーモンプロセスで、Unix系OSではデフォルトで入っています。詳しくはhttp://www.server-memo.net/tips/crontab.htmlなどに書かれています。

注意すべき事項としては、cronではrootからのpathでアクセスされるので、上記プログラムではプログラムを実行する前に、cdをしてプログラムが置いてあるディレクトリに移動する必要があります。また、PyenvやAnacondaなどの環境を用いている場合は、
/home/***/.pyenv/versions/anaconda2-4.3.0/bin//python arxiv.py

のように、Pythonの実行ファイルを指定する必要があります。

実行例

実行するとこんな感じで投稿してくれます。


1 件のコメント :