TopImage

SlackにbioRxivのSynthetic Biology分野の新着論文・人気論文をながす方法

みなさん、新着論文をどのように探していますか?
近年の研究業界では、日々大量の論文が生み出され、それを読むことができる状態になりつつあります。そんな中で、有益な情報素早く、労力をかけずに見極めるための補助ツールとして、本記事を参考にしていただけるといいなと思います。本記事では、Synthetic Biologyについて取り扱いますが、bioRxivで扱うジャンルでは、どのようなものでも作成が可能です。

概要

この記事では近年バイオ領域で注目を集めているプレプリントサーバーであるbioRxivのジャンルごとの新着論文、人気論文をSlackに毎週ながすための方法をまとめてあります。主にGASを使いますので、ローカル環境を汚さずに手軽に管理でき、すべての機能については無料で構築が可能になっております。コードは最後にまとめてあります。

注意: 2019年の夏頃作成したものです。2020年4月では動作しておりますが、状況の変化は早いので、最新情報も確認するようにしてください

モチベーション

bioRxivはプレプリントサーバーであり、情報の信頼度は高くないが、査読前の論文などが上がっており、情報のスピードが速いのが特徴です。


しかし、それらの特徴の反面、大量の論文がアップされ、全てを網羅することは不可能に近いです。さらに、その中でも本当に有用な論文は一握りです。

時間を無駄に浪費しないで、有用な論文に素早くたどり着けるように、なるべく毎回のコストを少なくするにはどうすれば良いかということから、このようなスタイルになりました。


1. GASでbioRxivの最新記事を取得する

GASとはGoogle Apps ScriptというGoogleが提供しているクラウドベースのプログラミングツールです。書き方はJavaScriptに似ています。

(GASは怠惰な生活を送るためのツールを開発するにはちょうどいいと思う。)


GASでプロジェクトを立ち上げる

Google Driveにアクセスし、新規作成 > その他 > Google Apps Scriptを選択することで、新規プロジェクトが立ち上がります。





次にスプレッドシート連携し、スプレッドシートを簡易DBとして使用します。まずGoogle Drive内にスプレッドシートを新規作成してください。

そして、このようになっているリンクのxxxspreadsheet_idxxx部分を記録します。

https://docs.google.com/spreadsheets/d/xxxspreadsheet_idxxx/



次にシートの名前をmainにして、DBの項目を以下のように作成します。
id, Doi, title, title_japanese, url, date, up_data, altmetric_pct|, altmetric_score, how_altmetric_check, score_flag

これらを1列目に記入しておきます。これはコードと紐付けるため、場所が重要です。
* 参考ですので、各自変更してもらって構いません




プログラムを実行すると認証ページが出てくることがあります。
開発者である場合問題ありませんので、こちらの方の記事などから認証お願いします。




GASでスクレイピング

bioRxivにはカテゴリーわけがすでにされています。
今回はSynthetic Biologyに興味がありますので、

http://connect.biorxiv.org/biorxiv_xml.php?subject=synthetic_biology


ここの情報をとってきたいです。最後の部分を目的のカテゴリーに変更することで、様々なカテゴリーで可能になります。

スクレイピングはParserライブラリを使用します。
設定方法につきましてはこちらの方の記事などからお願いします。


準備が整ったら、スクレイピングをしていきます。

目的部分を抽出して、先ほどのスプレッドシートに追記していきます。
記事の重複は避けたいので、DBに登録してある直近の50論文のDOIを確認し、未登録な最新論文のみ新規登録していきます。

注意 : 最初に始める時は50論文もないのでエラーが出るかもしれません。適宜変更してください


この時、論文タイトルも取得できますが、英語であるため、Google 翻訳のライブラリを導入し、日本語のタイトルも登録しています。




2.bioRxivの記事の流行度合いを確認する

DOIを使用し、論文のSNSでの流行度合いを簡単に調べることができる、AltmetricのAPIを利用します。


Altmetricでのscoreを取得するために、先ほどのスクレイピングと同様に、Parserライブラリを使用し、APIにアクセスし、情報を取得します。スコアは0 ~ 100に正規化された'pct'を利用します。

90以上のスコアで流行しているものだと判断するようにしました。(週1本ぐらいが90以上です)


今回はDBにあるすべての論文に対して、流行度を調べ続けるのではなく、4回(1週間ごとだと1ヶ月)のみ調べるようにしています。

これまでの条件を元に、取得した情報を分類して、スプレッドシートに上書きしていきます。

ここまでで、bioRxivの論文を適切に分類することアプリケーションは完成です。


3. GASとSlackを連携する

エンドポイントとしてSlackに分類されたデータをながれるようにします。
*エンドポイントはTwitterでもDiscordでもなんでも、APIさえあれば基本的には可能です。


まずSlackと連携するために、Slack側で媒介するアプリを作成し、slack api tokenを取得します。
主な手順は

  1. slack apiにアクセスし、Create Appを選択しアプリを作成する
  2. OAuth & Permissons > Scopes > SelectPermission ScopesでSend messages as xxxxを選択する
  3. Slack側でアプリを登録し、slack api token( OAuth Access Token)を取得する 


slack api tokenをGAS側に記述し、メッセージの送信を可能にします。
そして、メッセージを送りたいチャネルを選択します。

設定方法につきましてはこちらの方の記事などからお願いします。(定期的にプログラムを実行する方法も書かれています。)



4.定期的にプログラムを実行する

GASではプログラムを自動で定期的に実行することができます。

GASの 編集>すべてのトリガー から指定した時間にプログラム( 今回だったらmain)を実行できるように設定します。

その機能を利用して、1週間に1回決まった時間にプログラムを実行するように設定しています。

これで完成です。1週間に1回、新着論文と人気論文をチェックすることができるようになりました!



5. コード

function main() {
 //スプレッドシートのid  
 var id="xxxspreadsheet_idxxx" // 各自変更してください
 var sheet_main = spreadsheet_select(id,'main');

 // スクレイピングの部分
 var keyword = 'synthetic_biology'
 var url_path = 'http://connect.biorxiv.org/biorxiv_xml.php?subject=' + keyword
 var html = UrlFetchApp.fetch(url_path).getContentText();
 var parser = Parser.data(html);

 // 細かくする
 var doi = Parser.data(html).from('doi:').to('').iterate();
 var date = Parser.data(html).from('').to('').iterate();
 var up_data = Parser.data(html).from('').to('').iterate(); 
 var title = Parser.data(html).from('').iterate();
 var link = Parser.data(html).from('').iterate();

 //Logger.log(parser);
 //Logger.log(doi);

 // slack用
 var slackallinfo = []
 var slackhotinfo = []
  
 // DBに格納する
 var Main_lastRow = sheet_main.getLastRow();
 var db_id = sheet_main.getRange('B2:B'+Main_lastRow).getValues(); 
 for (i = title.length - 1; i >= 0; i--) { 
 //Logger.log(title[i]);
 var old_check_flag = 0
 for (j = Main_lastRow - 1;j >= Main_lastRow-51; j--) { // 最初は51を適切に変更してください
  if (db_id[j] == doi[i]){
  old_check_flag = 1
  break;
  }else if (doi[i] == '10.1101/825406'){ // たまにエラーになる記事がある
  old_check_flag = 1;
  break;
  };
 };

 if (old_check_flag == 0){
  Main_lastRow += 1
  Logger.log(doi[i]);
  var japanese_title = LanguageApp.translate(title[i], "en", "ja")
  sheet_main.getRange('A'+Main_lastRow).setValue(Main_lastRow-1);
  sheet_main.getRange('B'+Main_lastRow).setValue(doi[i]);
  sheet_main.getRange('C'+Main_lastRow).setValue(title[i]);
  sheet_main.getRange('D'+Main_lastRow).setValue(japanese_title);
  sheet_main.getRange('E'+Main_lastRow).setValue(link[i]);
  sheet_main.getRange('F'+Main_lastRow).setValue(date[i]);
  sheet_main.getRange('G'+Main_lastRow).setValue(up_data[i]);
  sheet_main.getRange('J'+Main_lastRow).setValue(0);
  sheet_main.getRange('K'+Main_lastRow).setValue(0);
  slackallinfo.push([title[i],japanese_title,link[i]]);
 };
 };

 // score調べる
 var check_raw = Main_lastRow + 0; 
 for (i=check_raw; i > 0; i--){
 // 何回チェックしたか、4回(1ヶ月)行ったら終わり
 var check_count = sheet_main.getRange('J'+ i).getValues(); 
 if (check_count < 4){
  // altmetric_scoreを調べる
  var check_doi = sheet_main.getRange('B'+ i).getValues(); 
  try {
  var check_url = "https://api.altmetric.com/v1/doi/" + check_doi
  var check_html = UrlFetchApp.fetch(check_url).getContentText();
  var check_parser = Parser.data(check_html);
  var check_pct = Parser.data(check_html).from('"pct":').to(',"higher_than"').iterate();
  var check_score = Parser.data(check_html).from('"score":').to(',"history":').iterate();
  var altmetric_flag = true
  }
  catch (e) {
   var altmetric_flag = false
  };

  if (altmetric_flag == true){
  sheet_main.getRange('H'+i).setValue(check_pct[1]);
  sheet_main.getRange('I'+i).setValue(check_score);
  sheet_main.getRange('J'+i).setValue(parseInt (check_count) + 1);

  if (check_pct[1] > 89){ // 89以上で人気と判断
   if (sheet_main.getRange('K'+ i).getValues() == 0){
   sheet_main.getRange('K'+i).setValue(1);
   slackhotinfo.push([
     sheet_main.getRange('C'+ i).getValues(),
     sheet_main.getRange('D'+ i).getValues(), 
     sheet_main.getRange('E'+ i).getValues()]); // title, jp_title, link
   };
  };
  } else { 
  sheet_main.getRange('H'+i).setValue(0);
  sheet_main.getRange('I'+i).setValue(0);
  sheet_main.getRange('J'+i).setValue(parseInt (check_count) + 1);
  };
 } else if(check_count == 4){
  break;
 };
 };

 // slack
 var all_new = '今週追加された論文\n';
 var hot_new = '今週話題になった論文\n';
 slackFunction(all_new, slackallinfo, '#task'); // 各自変更してください
 slackFunction(hot_new, slackhotinfo, '#random'); // 各自変更してください
}

// Slack部分
function slackFunction(ms, info, channel) {
 //送信メッセージ
 var mss = ms
 for (i = 0; i < info.length; i++) { 
 mss += info[i][0] + "\n" + info[i][1] + "\n" + info[i][2] + "\n\n";
 };

 //送るパラメータの定義
 var payload = {
 "token" : "xxxxslack_api_tokenxxxx", // 各自変更してください
 "text" : mss,
 "channel" : channel
 }
 var options = {
 "method" : "POST",
 "payload" : payload
 }
 UrlFetchApp.fetch("https://slack.com/api/chat.postMessage", options);
}

function spreadsheet_select(path, name) {
 var ss = SpreadsheetApp.openById(String(path));//スプレッドシート名
 var sheet_active = ss.getSheetByName(String(name));//シートの名前
 return sheet_active
}






参考文献

多くの方の記事を参考にさせていただきました。ありがとうございます。
今回の主なベース (プログラムをGASに変更しました。)
imamachi-n.hatenablog.com

GASでのスクレイピング
www.kotanin0.work

GASとSlackの連携
breezegroup.co.jp

GASの認証
tonari-it.com


質問・意見 などがありましたら、
yomogy までお願いします。