研究者にとって、日々の新着論文チェックは非常に重要です。
実際にジャーナルのトップページに行き新着文献をチェックするのも良いとは思いますが、最近では多くの研究者が新着論文のチェックに RSS を活用していると思います。
Feedly などの RSSリーダー を登録しておくと各ジャーナルのページにいちいちアクセスせずに新着論文チェックができるので、非常に便利です。
しかし、RSS を使っていても不便な点はあります。
それは、所属する研究機関のネットワーク経由でないと論文の pdf をダウンロードできない点です!
自宅や出張先でも新着論文はチェックしたいものです。
そこで、今回の記事では RSS の情報をもとに自身の研究に関連する新着論文を自動的にダウンロードして、メールで送付してくれる python スクリプトを紹介します!
一応、記事としては、これまでの python でのスクレイピングの続きになります。
参考:Webスクレイピング で文献検索を効率化!第1回s【Python】
参考:論文 PDF のダウンロードを効率化!【Webスクレイピング 第2回】
目次
使い方の説明
ファイルのダウンロード
まずは、一連のファイルを下記リンクからダウンロードして、path の通してあるディレクトリに移し、解凍しましょう。
以下のファイルが揃っていることを確認してください。
- RSS_ACS.py
- RSS_Wiley.py
- RSS_RSC.py
- log.txt
- keyword.txt
- Author.txt
- RSS_download.sh
キーワードの設定
このプログラムでは、keyword.txt 内にあるキーワードが論文タイトルに含まれている新着論文と、Author.txt 内にある著者名が含まれている新着論文を自動的にダウンロードするよう設定してあります。
そこで、keyword.txt と Author.txt の中身を自分用に編集してください。キーワードを “,” で区切って入力してください。
ディレクトリの設定
三つの python ファイル内にはダウンロード用のファイル path が書いてあります。これをご自身のお使いの環境に書き換えてください。
Chrome Driver の設定
ACS など多くの雑誌は、プログラムがウェブブラウザを介さずに直接 pdf をダウンロードすることを禁止しています。
そのため、今回の python スクリプトでは、一度 Google Chrome を起動して自動的に pdf をダウンロードするように設定してあります。
python から Google chrome を使用するには、chrome driver を設定しなくてはいけません。
こちらのページからご自身のお使いの Google chrome の version に一致した chrome driver をダウンロードし、path の通ったディレクトリに移動してください。
時折 Google Chrome が自動アップデートされてしまい、chromeDriver のバージョンが一致しなくなる場合があります。ですので、数週間に一回はchromeDriver のバージョンを確認するようにしてみて下さい!
実行
sh RSS_download.sh
と入力するとプログラムが実行されます。
python スクリプトの説明
上記の説明の通り実行すれば新着論文をダウンロードすることはできます。ここからは、もう少し詳しいスクリプトの動作について知りたい人向けに書きます。
今回のプログラムには 3 つの python スクリプトが含まれていますが、これらは第一引数に雑誌名を取ります。
例えば、
python RSS_ACS.py JACS
として実行すると JACS の RSS ページに行き、新着論文のチェックとダウンロードを開始します。
しかし、雑誌ごとにいちいち以下のようにコマンドを打つのは非常に面倒です。
python RSS_ACS.py JACS python RSS_ACS.py OL python RSS_ACS.py JCTC
そこで、RSS_download.sh にまとめて実行するようにします。
RSS_download.sh 内には
python RSS_ACS.py JACS python RSS_ACS.py OL python RSS_ACS.py JCTC ... python RSS_Wiley.py Angew python RSS_Wiley.py JCC ... python RSS_RSC.py OBC python RSS_RSC.py NPR
と記述されています。
あとは、これを研究室に置きっ放しにしてあるパソコンで cron を利用して定期的に実行するだけで、自動的に論文をダウンロードしてメールで送付してくれるようになります。
cron は、あるプログラムを特定の時間に(定期的に)実行してくれる便利な仕組みです。
crontab -e で編集します。
例えば、毎朝 6:00 にプログラムを実行したいのであれば
00 6 * * * source ~/.bashrc; sh /Users/hogehoge/paper_RSS.sh
と設定すれば OK です。
(上記の hogehoge のところに適切な path を書き込んでください。)
ReadCube も連携させよう!
メールで論文 pdf を送信するのが利用規約に抵触しそうで怖いという方は、Readcube を利用した方が良いと思います。
Chem-Station さんのこちらの記事にもあるように Readcube の「Add a Watch Folder」機能を使うことで、ダウンロードした論文を自動的に ReadCube に追加することが可能です。
これで、同期しているタブレットなどでも論文を読めるようになるのではないでしょうか?
でも、Readcube は Linux サポート外らしいので、そうすると研究室に常設してある Mac または Windows を使うことになりそうです。。。
それか、Dropbox を使うという方法もありますが。。。
より詳しいスクリプトの説明
ここから下は、より詳しいスクリプトの説明です。
ACS 系の雑誌をダウンロードするスクリプトを例に説明します。まず最初に対応している雑誌の一覧があります。もし、自分の興味のあるものが無い人は、追加して下さい。
#! /usr/local/bin/python3 #ACS 系の以下の雑誌に対応 #JACS: Journal of the American Chemical Society #JCTC: Journal of Chemical Theory and Computation #JPCA: The Journal of Physical Chemistry A #JPCB: The Journal of Physical Chemistry B #JOC: The Journal of Organic Chemistry #Omega: ACS Omega #ChemBio: ACS Chemical Biology #Catalysis: ACS Catalysis #ChemRev: Chemical Reviews #OL: Organic Letters #SynBio: ACS Synthetic Biology import re import os import sys import time import glob import datetime import smtplib import feedparser import mimetypes from os.path import basename from selenium import webdriver from email import encoders from email.utils import formatdate from email.mime.text import MIMEText from email.mime.base import MIMEBase from email.mime.application import MIMEApplication from email.mime.multipart import MIMEMultipart args = sys.argv argc = len(args)
ここから下は、 chrome の設定などです。通常ブラウザには pdf ビューワーがついていますが、それを OFF にすることで pdf をダウンロードできるようにしています。
#PDF download 用の設定 download_dir = "/Users/hogehoge/RSS" #pdf のダウンロード先 #chrome の設定 options = webdriver.ChromeOptions() options.add_experimental_option("prefs", { "download.default_directory": download_dir, "download.prompt_for_download": False, "download.directory_upgrade": True, "plugins.plugins_disabled": ["Chrome PDF Viewer"], "plugins.always_open_pdf_externally": True }) options.add_argument("--disable-extensions") options.add_argument("--disable-print-preview") #RSS の設定とダウンロード driver = webdriver.Chrome(options=options) d = feedparser.parse('https://feeds.feedburner.com/acs/jacsat') #キーワードや著者名の追加 if args[1] == 'author': with open('./Author.txt', mode='a') as f: f.write(args[2] + ", ") sys.exit() if args[1] == 'key': with open('./keyword.txt', mode='a') as f: f.write(args[2] + ", ") sys.exit() #雑誌名の指定 if args[1] == 'JACS': d = feedparser.parse('https://feeds.feedburner.com/acs/jacsat') if args[1] == 'JCTC': d = feedparser.parse('https://feeds.feedburner.com/acs/jctcce') if args[1] == 'JPCA': d = feedparser.parse('https://feeds.feedburner.com/acs/jpcafh') if args[1] == 'JPCB': d = feedparser.parse('https://feeds.feedburner.com/acs/jpcbfk') if args[1] == 'JOC': d = feedparser.parse('https://feeds.feedburner.com/acs/joceah') if args[1] == 'Omega': d = feedparser.parse('https://feeds.feedburner.com/acs/acsodf') if args[1] == 'ChemBio': d = feedparser.parse('https://feeds.feedburner.com/acs/acbcct') if args[1] == 'Catalysis': d = feedparser.parse('https://feeds.feedburner.com/acs/accacs') if args[1] == 'ChemRev': d = feedparser.parse('https://feeds.feedburner.com/acs/chreay') if args[1] == 'OL': d = feedparser.parse('https://feeds.feedburner.com/acs/joceah') if args[1] == 'SynBio': d = feedparser.parse('https://feeds.feedburner.com/acs/asbcd6')
ここで、Author.txt や Keyword.txt や log.txt の中身を読み込んでいます。その後、RSS のページに行き pdf の URL や論文のタイトル、著者名などを読み込んでいます。
一度読み込んだ新着論文の ID は、log.txt というファイルに保存されるため、同じ論文を何度もダウンロードする、ということは起きません。
#キーワードや著者名の読み込み Authors=[] Keywords=[] logs=[] Key_num=0 with open('./Author.txt') as fa: s = fa.read() for i in s.split(", "): Authors.append(i) with open('./keyword.txt') as fk: s = fk.read() for i in s.split(", "): Keywords.append(i) Key_num +=1 with open('./log.txt') as fl: s = fl.read() for i in s.split("\n"): logs.append(i) #検索キーワードの設定 #著者名は、頭文字だけ大文字 keyword_dir = "./keyword.txt" Author_dir = "./Author.txt" JACS_title=[] JACS_author=[] filenames=[] num=0 for entry in d.entries: #if "Energy" in entry.title: #print(entry.authors) name_str = str(entry.authors).replace('[{\'name\':','').replace('*','').replace('†','').replace('§','').replace('?','').replace('#','').replace('‡','').replace('\' ','').replace('}]','').replace('and','') for auth in Authors: if auth in name_str: pdf_URL = "https://pubs.acs.org/doi/pdf/" + entry.id[18:] if entry.id in logs: continue driver.get(pdf_URL) num += 1 JACS_title.append(entry.title) JACS_author.append(auth) name_split=entry.id.split("/") name=name_split[-1] filenames.append(name + ".pdf") logs.append(entry.id) with open('./log.txt', mode='a') as f: f.write(entry.id + "\n") time.sleep(1) for Key in Keywords: if Key in entry.title: pdf_URL = "https://pubs.acs.org/doi/pdf/" + entry.id[18:] if entry.id in logs: continue driver.get(pdf_URL) num += 1 JACS_title.append(entry.title) name_str = str(entry.authors).replace('[{\'name\':','').replace('*','').replace('†','').replace('§','').replace('?','').replace('#','').replace('‡','').replace('\' ','').replace('}]','').replace('and','') JACS_author.append(name_str) name_split=entry.id.split("/") name=name_split[-1] filenames.append(name + ".pdf") with open('./log.txt', mode='a') as f: f.write(entry.id + "\n") time.sleep(1)
ここから下は、メールの送信設定です。今回は、Gmail を利用して送信する設定にしてあります。
FROM_ADDRESS には 送信元の gmail アドレス、MY_PASSWORD には Gmail にログインするためのパスワード、TO_ADDRESS には送信先のアドレス(自分がメインで使用しているメールアドレスなど)を記述して下さい。
#メールの設定 FROM_ADDRESS = 'hogehoge@gmail.com' MY_PASSWORD = 'hogehoge' TO_ADDRESS = 'hogehoge@yahoo.co.jp' SUBJECT = args[1] + ' の新着記事が ' + str(num) + ' 件あります' body = 'pythonでメール送信' def attachment(filename): fd = open(filename, 'rb') mimetype, mimeencoding = mimetypes.guess_type(filename) if mimeencoding or (mimetype is None): mimetype = 'application/octet-stream' maintype, subtype = mimetype.split('/') if maintype == 'text': retval = MIMEText(fd.read(), _subtype=subtype) else: retval = MIMEBase(maintype, subtype) retval.set_payload(fd.read()) encoders.encode_base64(retval) retval.add_header('Content-Disposition', 'attachment', filename=filename) fd.close() return retval def create_message(from_addr, to_addr, subject, message, files): msg = MIMEMultipart() msg['Subject'] = subject msg['From'] = from_addr msg['To'] = to_addr msg['Date'] = formatdate() body = MIMEText(message, _subtype='plain') msg.attach(body) for filename in files: msg.attach(attachment(filename)) return msg def send(from_addr, to_addrs, msg): smtpobj = smtplib.SMTP('smtp.gmail.com', 587) smtpobj.ehlo() smtpobj.starttls() smtpobj.ehlo() smtpobj.login(FROM_ADDRESS, MY_PASSWORD) smtpobj.sendmail(from_addr, to_addrs, msg.as_string()) smtpobj.close() time.sleep(1) for i in range(num): print(str(i) + ":\t" + JACS_title[i] + "\n\t" + JACS_author[i]) #メールの本文の編集 body = args[1] + " の新着文献が " + str(num) + " 件あります\n\n" for i in range(num): body += str(i) + ":\t" + JACS_title[i] + "\n\t" + JACS_author[i] + "\n" body += "\npythonでメール送信\n" to_addr = TO_ADDRESS subject = SUBJECT print("body\n\t" + body) for i in range(num): while os.path.exists(filenames[i]) == False: time.sleep(2) # pdf のダウンロードに時間がかかる場合があるため #メール送信 if num != 0: msg = create_message(FROM_ADDRESS, to_addr, subject, body, filenames) send(FROM_ADDRESS, to_addr, msg) time.sleep(1) driver.quit()
もしもメールでの通知機能はいらないという方は、最後の driver.quit() と以下のループだけ残して、メール実装部分はコメントアウトされるのが良いと思います。
for i in range(num): while os.path.exists(filenames[i]) == False: time.sleep(2) # pdf のダウンロードに時間がかかる場合があるため
まとめ
今回の記事では、新着文献のチェック、ダウンロードという部分を自動化するスクリプトを紹介しました。
しかもメールで送付する機能も実装されているため、自宅や学外にいる時でも新着文献を読むことが可能です。
このように日々行う退屈なルーティーンワーク作業は全部 python にやらせて、もっとクリエイティブな作業に時間を割くようにしましょう!