学会誌・論文誌のタイトル等をCrossrefのAPIを使ってまとめて取得する

自分はジャーナルと呼ばれる学術論文集や学会誌の検索はそれぞれの学会のホームページか横断的に調べるときは[Google Scholor](https://scholar.google.co.jp/)や[J-STAGE](https://www.jstage.jst.go.jp/browse/-char/ja)、[CiNii](https://ci.nii.ac.jp/)、[KAKEN](https://kaken.nii.ac.jp/)で調べてたりします。
その中でも一つのジャーナルを昔の分からまとめて見たいと思ったときはそこのホームページの使いやすさに大きく依存します。

自分のジャンルだとAIAA(アメリカ航空宇宙学会）のジャーナルを調べることが多いです。[ARC](https://arc.aiaa.org/)というサイトで調べて行く作業になります。このとき雑誌の過去の論文をあさりたいときに、もっさりしたページをたどっていくのですが、めんどくさいし時間がかかります。

そこで、最初はウェブスクレイピングしようかと思いましたが、ちょっとしたことをするとBOTだと見破られて弾かれます。そこで調べると、Crossrefという機関が出しているAPIを使うと素早く取得できることがわかりました。
さらに、CrossrefのAPIを使いやすくするpythonのライブラリの[crossrefapi](https://github.com/fabiobatalha/crossrefapi)があり、便利なので使い方含めて書きます。

## crossrefapiインストール
pythonとpipがインストールされている状態で

```
pip install crossrefapi
```

https://github.com/fabiobatalha/crossrefapi
に使い方は書いていますが、ここでは自分の使い方を紹介します。

## 使い方基礎１： ジャーナル自体を探す場合

```python:sample_crossref_1.py
# ジャーナル自体を探す場合
from crossref.restful import Journals
journals = Journals().query('AIAA')  # 例えば'AIAA'で検索
for item in journals:
    print(item["title"])
    print(item["ISSN"])
```
実行すると
>AIAA Journal
>['1533-385X', '0001-1452']

と出力されます。AIAA（アメリカ航空宇宙学会）と名前が付いているジャーナルはAIAA Journal一つだけでした。そのときのISSN（国際標準逐次刊行物番号、分かっていると便利、普通に調べて出てくる番号）なども取得できます。

## 使い方基礎2： ジャーナル自体を複数条件で探す

```python:sample_crossref_2.py
# 複数条件でも探せる
from crossref.restful import Journals
journals = Journals().query('aerospace', 'japan')  # 複数検索の時はカンマでつなげる
for item in journals:
    print(item["title"])
    print(item["ISSN"])
```

>AEROSPACE TECHNOLOGY JAPAN THE JAPAN SOCIETY FOR AERONAUTICAL AND SPACE SCIENCES
['1884-0477']
TRANSACTIONS OF THE JAPAN SOCIETY FOR AERONAUTICAL AND SPACE SCIENCES AEROSPACE TECHNOLOGY JAPAN
['1884-0485']

と出ました。日本航空宇宙学会の英文ジャーナルが出てきています。

## 使い方基礎3： ISSNが既知の場合のジャーナル詳細情報

```python:sample_crossref_3.py
# ISSNがわかっている場合のジャーナルの詳細を表示
from crossref.restful import Journals
import pprint # キレイに表示するための標準モジュール

journals = Journals()
j = journals.journal('1476-4687') # Nature本誌
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(j)
print(j['title'])  # dictで情報が格納されているので各要素にアクセスもできる
```

## 使い方基礎4： 各論文のDOIから情報を得る
[DOI（デジタルオブジェクト識別子）](https://ja.wikipedia.org/wiki/%E3%83%87%E3%82%B8%E3%82%BF%E3%83%AB%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E8%AD%98%E5%88%A5%E5%AD%90)は各論文のIDみたいなものです。
このDOIがわかっていると各論文の詳細情報が取得できます。

```python:sample_crossref_4.py
# 各論文のDOIから情報を得る
from crossref.restful import Works
import pprint # キレイに表示するためのモジュール

works = Works()
paper = works.doi('https://doi.org/10.2514/1.B36144')
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(paper)
```

## 使い方応用
実用的な応用として、ISSNのわかっているジャーナルの論文タイトルとDOI（必要だと思ったらアクセスできるように）をまとめて取得します。
ここでは試しに「Journal of Propulsion and Power」というジャーナルの一覧を取得します。Pandasを用いてDataFrameに格納したあと、CSV出力しています。
このジャーナルは今日までに５５００程度の記事があり、全て取得までに時間がかかりますのでプログレスバーで表示させます。

本筋とは関係ないけど、プログレスバーを表示したい場合はコマンドラインで下記を実行して、pythonのtqdmライブラリをインストールしておいてください。

```
pip install tqdm
```

```python:sample_crossref.py
# !pip install crossrefapi
# !pip install tqdm
from crossref.restful import Works
import pandas as pd
from tqdm import tqdm

# データ格納のためにpandas.DataFrameを作っておく
df = pd.DataFrame(columns=['year', 'month', 'volume', 'page',
                  'title', 'URL', 'authors', 'journal'])

works = Works()
r = works.filter(issn='0748-4658')  # ISSNからJournal of Propulsion and Powerを指定

pbar = tqdm(total=r.count())  # プログレスバーを表示する

for item in r:
    # 最初に各paperの情報をキレイにする。抜けている情報はNoneや0で埋める
    if ('author' not in item):
        item['author'] = None
    if ('page' not in item):
        item['page'] = None
    if ('volume' not in item):
        item['volume'] = 0
    # このジャーナルではprintとonlineの両方があるので出版日を調整
    if ('published-print' in item):
        year = item['published-print']['date-parts'][0][0]
        month = item['published-print']['date-parts'][0][1]
    elif ('published-online' in item):
        year = item['published-online']['date-parts'][0][0]
        month = item['published-online']['date-parts'][0][1]
    temp_se = pd.Series([year, month, item['volume'], item['page'],
                        item['title'][0], item['URL'], item['author'],
                        item['container-title'][0]], index = df.columns)
    df = df.append(temp_se, ignore_index = True)  # DataFrameに行追加
    pbar.update(1)  # プログレスバーを進める

pbar.close()
# csvで保存する
df = df.sort_values(['year', 'month', 'URL'])  # 順番バラバラなのでソートする
file_name = item['container-title'][0] + '.csv'
df.to_csv(file_name, index=False, encoding='utf-8')
```

スクリプトを見るとわかりますが、データ取得自体は簡単です。キレイでないデータからエラーを吐かないように処理している部分がコードの半分を占めます。
これは各雑誌によって配信されているデータが違うので、細々調整しないと行けない部分です。うまく調整してみてください。for文の中のitemを表示すると中身がわかりますので、うまいことします。（丸投げ）

```python
print(item)
```

CSVに保存できたのであとは煮るなり焼くなりご自由に。
Crossrefにあまり出てこない雑誌もあるので統一的には出来ないのは残念なところです。