概要
本記事では、医学系の文献データベースから前日に新たに登録された新型コロナウイルスに関連する文献を抽出し、LINEに自動で送信する方法を扱います。PubMedというデータベースから、あるキーワードにマッチする文献を抽出することが主な内容になります。
環境
Python 3.6.5
beautifulsoup4==4.9.0
requests==2.23.0
urllib3==1.25.9
データベースとキーワードの選定
今回は医学系の文献データベースとしてPubMedを利用します。PubMedは、NLM(米国国立医学図書)内の、NCBI(国立生物科学情報センター)が作成しているデータベースです。世界の主要医学系雑誌等に掲載された文献を検索できます。
次にキーワードですが、新型コロナウイルスについて調べてみると、"coronavirus"や"Covid-19"という単語がよく使われていました。そのため、今回は"coronavirus"もしくは"Covod-19"のどちらかの単語が含まれている文献を抽出することにしました。
PubMedのAPI
PubMedから文献を抽出する方法として、PubMedのAPIを利用しました。
PubMedで利用できるAPIは複数ありますが、利用したのはESearchとEFetchです。
詳しくはドキュメントを参考にして下さい。
ESearch_概要
ESearchでは検索式にマッチする論文のIDの一覧を取得することができます。
このURLがベースになり、
http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=
の"term="のあとに検索式をいれれば、その検索式にマッチするIDが返されます。
たとえば"coronavirus"でやってみます。
http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=coronavirus
ブラウザで上記URLを入力するとこのような結果が表示されます。
無事に論文のIDを取得できています。Countは検索式にマッチした文献の数、retmaxはマッチした文献のうち表示する文献の数を意味しています。retmaxは初期値だと20ですが、最大で100,000件まで取得することができます。
例えばretmaxを100に変えるには"retmax=100"をURLに加える必要があります。
http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=coronavirus&retmax=100
ブラウザで上記URLを入力すると、
のようになります。表示される文献の数が100に増えています。
"retmax"のように文献を抽出するうえでいくつかの条件をつけることができます。
今回は"retmax"以外にも、"field"、"mindate"、"maxdate"を利用します。
"field"では検索箇所を"title"や"abstract"などから選ぶことができます。
"mindate"、"maxdate"で文献がPubMedに登録された日付でいつからいつまでの文献を対象にするのか決めることができます。
例えば、2019年4月から2020年4月までの文献をタイトルだけから検索したい時は
&field=title&mindate=2019/4/1&maxdate=2020/4/31
を付け加えます。
ESearch_コード
まずは検索式に該当する論文のIDを調べるためのURLを作成します。
今回は"coronavirus"と"covid-19"をORで繋いだ検索式を利用しています。
importtimedefmake_url(yesterday,query):"""
Esearchを行うurl作成
引数:日付、検索式
戻り値:str型のurl
"""#Esearchの基本のURL
baseURL="http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term="#検索範囲をタイトルもしくはアブストラクトに限定
field="field=title/abstract"#取得できるIDの最大数を1000に変更
retmax="retmax=1000"#昨日の文献のみを対象にする
mindate="mindate={}".format(yesterday)maxdate="maxdate={}".format(yesterday)#それぞれの文字列を結合
url="&".join([baseURL+query,field,retmax,mindate,maxdate])time.sleep(5)returnurl
URLが作成できたら、それを利用してIDの一覧を取得します。
IDを取得しやすいようにBeautifulSoupを利用しています。
frombs4importBeautifulSoupfromurllib.parseimporturljoinimporturllib.requestdefget_id(url):"""
論文IDの取得
引数:リサーチurl
戻り値:idのリスト
"""#ESearchでIDの一覧を取得
article_id_list=urllib.request.urlopen(url)#IDのみを取得
bs=BeautifulSoup(article_id_list,"html.parser")ids=bs.find_all("id")returnids
EFetch_概要
論文のIDからタイトルやアブストラクトなどの情報を取得するときはEFetchを利用します。
このURLが基本になります。
https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id=
"id="に論文のidを入力することで、論文の情報を取得できます。
EFetch_コード
ESearchで取得したそれぞれのIDから論文の情報を取得します。
frombs4importBeautifulSoupimporturllib.requestimporttimedefget_summary(id):"""
論文のサマリーを取得
引数:id
戻り値:タイトル、論文のurl
"""#EFetchの基本のURL
serchURL="https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id="search_url=serchURL+id.text+"&retmode=xml"summary=urllib.request.urlopen(search_url)summary_bs=BeautifulSoup(summary,"html.parser")#文献のURLは論文のIDから作成
article_URL="https://pubmed.ncbi.nlm.nih.gov/{}/".format(id.text)#文献のタイトルを抜き出す
title=summary_bs.find("articletitle")title=title.texttime.sleep(5)returntitle,article_URL
LINE Notify_コード
あとは取得した論文の情報を出力します。
LINE Notifyを利用することでpythonからLINEにメッセージを送信することができます。
こちらの記事を参考にしました。
defoutput_line(line_access_token,message):"""
LINEに通知を送信
引数:アクセストークン、通知内容
戻り値:なし
"""line_url="https://notify-api.line.me/api/notify"line_headers={'Authorization':'Bearer '+line_access_token}payload={'message':message}r=requests.post(line_url,headers=line_headers,params=payload,)
コード全体
frombs4importBeautifulSoupfromurllib.parseimporturljoinfromdatetimeimportdate,timedeltaimporturllib.requestimportrequestsimporttimedefmain():"""
メインの処理
"""#LINEのアクセストークン
line_access_token='LINEアクセストークン'#日付取得
yesterday=date.today()-timedelta(days=1)yesterday="/".join([str(yesterday.year),str(yesterday.month),str(yesterday.day)])#検索式
query="coronavirus+OR+covid-19"#Esearchのリンク取得
URL=make_url(yesterday,query)#論文のidを取得
ids=get_id(URL)#新しい論文がないとき
ifids==[]:message="Covid-19の新しい論文はありません"output_line(line_access_token,message)#新しい論文があるとき
else:foridinids:#論文の題目とURLを取得
title,article_URL=get_summary(id)#LINEに通知を送る
message="""{}
{}""".format(title,article_URL)output_line(line_access_token,message)defmake_url(yesterday,query):"""
Esearchを行うurl作成
引数:日付、検索式
戻り値:str型のurl
"""#Esearchの基本のURL
baseURL="http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term="#検索範囲をタイトルもしくはアブストラクトに限定
field="field=title/abstract"#取得できるIDの最大数を1000に変更
retmax="retmax=1000"#昨日の文献のみを対象にする
mindate="mindate={}".format(yesterday)maxdate="maxdate={}".format(yesterday)#それぞれの文字列を結合
url="&".join([baseURL+query,field,retmax,mindate,maxdate])time.sleep(5)returnurldefget_id(url):"""
論文IDの取得
引数:リサーチurl
戻り値:idのリスト
"""#ESearchでIDの一覧を取得
article_id_list=urllib.request.urlopen(url)#IDのみを取得
bs=BeautifulSoup(article_id_list,"html.parser")ids=bs.find_all("id")returnidsdefget_summary(id):"""
論文のサマリーを取得
引数:id
戻り値:タイトル、論文のurl
"""#EFetchの基本のURL
serchURL="https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id="search_url=serchURL+id.text+"&retmode=xml"summary=urllib.request.urlopen(search_url)summary_bs=BeautifulSoup(summary,"html.parser")#文献のURLは論文のIDから作成
article_URL="https://pubmed.ncbi.nlm.nih.gov/{}/".format(id.text)#文献のタイトルを抜き出す
title=summary_bs.find("articletitle")title=title.texttime.sleep(5)returntitle,article_URLdefoutput_line(line_access_token,message):"""
LINEに通知を送信
引数:アクセストークン、通知内容
戻り値:なし
"""line_url="https://notify-api.line.me/api/notify"line_headers={'Authorization':'Bearer '+line_access_token}payload={'message':message}r=requests.post(line_url,headers=line_headers,params=payload,)if__name__=="__main__":main()
あとは、これをcronで実行させることで、毎日自動的にLINEに文献のタイトルとURLを送信することができます。