ある日付にpublishされたArxivの論文を一括で取得して翻訳するプログラムを作成してみた

# はじめに

最近Arxixの論文を漁ることが多いのですが、一括で取得できて尚且つ日本語に翻訳してくれるとさらに効率化されるなと思い、自作してみました。
使用する際は[arXiv Apiの利用規約](https://info.arxiv.org/help/api/tou.html)を参照の上、リクエスト回数などに気をつけてください。
基本的な構造は下の流れになっています。

1. 任意の日付と任意のカテゴリ※を指定
1. arXiv Apiで該当する論文情報を取得
1. Google Translateでタイトルとabstractを日本語に翻訳
1. Excelに保存

※カテゴリは以下のサイトで確認することができます。
[Category Taxonomy](https://arxiv.org/category_taxonomy)

# arXiv Apiで論文情報を取得

ここでは以下のサイトを参考にプログラムを作成しました。
ここではarXivが公開しているAPIのラッパーであるライブラリarxivを使います。

- [PythonでarXiv APIを使って論文情報取得、PDFダウンロード](https://note.nkmk.me/python-arxiv-api-download-rss/)
- [lukasschwab/arxiv.py: Python wrapper for the arXiv API](https://github.com/lukasschwab/arxiv.py)

## arxivライブラリのinstall

他のpythonライブラリ同様以下のコマンドでインストールします。

```
pip install arxiv
```

## pythonプログラム

最初にarxivから情報を取ってくる箇所のプログラム全体をお見せします。

```python
import arxiv
import pandas as pd
from googletrans import Translator


date_default = "20240515"
cat_default = "quant-ph"
max_result_default = 100
max_chunk_results_default = 1000


class ImportArxivInfo:

    def __init__(self, date=None, cat=None, max_result=None) -> None:

        self.date = date_default
        self.cat = cat_default
        self.max_result = max_result_default
        self.max_chunk_results = max_chunk_results_default

        if date is not None: self.date = date
        if cat is not None: self.cat = cat
        if max_result is not None: self.max_result = max_result

        self.query = None
        self.result_list = None
        self.result_df = None
    
    def _make_query(self):
        # 元のqueryを作成
        query = ""
        # categoryのqueryを作成
        query_cat = "cat:{}".format(self.cat)
        query += query_cat
        # 日付のqueryを作成
        start = self.date + "0000"
        end = self.date + "2359"
        query_date = "submittedDate:[{} TO {}]".format(start, end)
        query += " AND " + query_date

        # 作成されたクエリを表示
        print("作成されたクエリ：\n{}\n".format(query))

        self.query = query
    
    def _to_dataframe(self):
        # listで出力されたarxivの情報をpandasのdfに変換する関数
        l = [] # 最終的にdfにするリスト
        i = 1
        for r in self.result_list:
            tmp = [] # 一時的なリスト
            tmp.append(i)
            tmp.append(self.date)
            tmp.append(r.title)
            tmp.append(None) # あとで翻訳したタイトルを入れる列
            tmp.append(r.summary)
            tmp.append(None)
            tmp.append(r.pdf_url)
            l.append(tmp)
            i += 1
        
        colunms = ["NO", "Date", "TITLE", "TITLE_jpn", "ABS", "ABS_jpn", "PDFlink"]
        df = pd.DataFrame(l, columns=colunms)
        df = df.set_index("NO")

        if __name__ == "__main__": print(df)

        self.result_df = df


    def run(self):

        self._make_query()

        client = arxiv.Client()

        search = arxiv.Search(
            query=self.query, 
            max_results = self.max_result, 
            sort_by = arxiv.SortCriterion.SubmittedDate
        )

        self.result_list = client.results(search)
        self.result_list = list(self.result_list)
        
        if __name__ == "__main__":
            print("取得したデータを表示")
            for r in self.result_list:
                print(r.title)
        
        self._to_dataframe()
```

### _make_query

arXiv APIで論文情報を取得するのには検索式を定義する必要があり、それをqueryと呼びます。
このメソッドではqueryを作成します。
ここでは使用しているqueryのみについて説明しますが、詳しく知りたい方は[こちら](https://note.nkmk.me/python-arxiv-api-download-rss/)のドキュメントを参照してください。

#### カテゴリの指定

catの後にカテゴリを指定することで、検索対象とするカテゴリを指定することができます。
※カテゴリは以下のサイトで確認することができます。
[Category Taxonomy](https://arxiv.org/category_taxonomy)

```python
    query_cat = "cat:{}".format(self.cat)
    # cat:quant-ph
```

#### 日付の指定

今回作成したプログラムは、指定した任意の日付の間にpublishされた論文情報を取得するので、以下のような形で指定しています。

```python
    # 日付のqueryを作成
    start = self.date + "0000"
    end = self.date + "2359"
    query_date = "submittedDate:[{} TO {}]".format(start, end)
    # submittedDate:[202405150000 TO 202405152359]
```

#### query完成系

カテゴリと日付を指定してAND条件で繋げると下のような形になります。

```
cat:quant-ph AND submittedDate:[202405150000 TO 202405152359]
```

#### _to_dataframe

データの扱いやすさからpandasのdataframe型に格納する形にしています。

#### run

作成したqueryを実際に流すメソッドです。
基本的には記載しているプログラムの通り、という形になりますが、詳しく知りたい方は[こちら](https://note.nkmk.me/python-arxiv-api-download-rss/)のドキュメントを参照してください。

# Google Translateでタイトルとabstractを日本語に翻訳

このパートは次のサイトを参考にしています
- [Pythonでgoogletransを使って翻訳](https://qiita.com/optimisuke/items/e44e66c2646e763d1f7b)

## googletransのinstall

次のコマンドでライブラリをinstallします

```
pip install googletrans
```

## pythonプログラム

dataframeに入っている英文のタイトルとabstractをそれぞれ和訳しています
※もう少し綺麗な実装にしたいと思っているので、そのうち更新します。

```python
    def translate(self):

        translator = Translator()

        # 翻訳を実行
        for row in range(self.result_df.shape[0]):

            self.result_df.iloc[row, 2] = translator.translate(self.result_df.iloc[row, 1], dest="ja").text
            self.result_df.iloc[row, 4] = translator.translate(self.result_df.iloc[row, 1], dest="ja").text

        if __name__ == "__main__": print(self.result_df)
```

# Excelに保存

pandasのto_excelを使ってエクセルに保存しています。
今後さらに使いやすくするための機能を追加しようと思っています。

```python
    def save_to_excel(self, filename=None):
        # Excelに保存
        # ファイル名に特に指定がなければ日付をファイル名として保存する
        if filename is None: filename = self.date
        self.result_df.to_csv("{}.xlsx".format(filename))
```

# 最後に

作業コストを減らすためにこのようなプログラムを作成してみたので公開しましたが、arXiv APIの利用規約にもある通り、適度なアクセス回数に抑えるなどの節度ある使い方をする必要があります。
また、そもそものGoogle翻訳の精度の問題で論文の内容を完全に理解するには至らないと思うので、この機能を使って気になる論文を洗い出して、その後にしっかり自分の目で内容を確認する必要があるかなと思いました。（それはそう）

作成したプログラムの全体を載せます

```python
import arxiv
import pandas as pd
from googletrans import Translator


date_default = "20240515"
cat_default = "quant-ph"
max_result_default = 100
max_chunk_results_default = 1000


class ImportArxivInfo:

    def __init__(self, date=None, cat=None, max_result=None) -> None:

        self.date = date_default
        self.cat = cat_default
        self.max_result = max_result_default
        self.max_chunk_results = max_chunk_results_default

        if date is not None: self.date = date
        if cat is not None: self.cat = cat
        if max_result is not None: self.max_result = max_result

        self.query = None
        self.result_list = None
        self.result_df = None
    
    def _make_query(self):
        # 元のqueryを作成
        query = ""
        # categoryのqueryを作成
        query_cat = "cat:{}".format(self.cat)
        query += query_cat
        # 日付のqueryを作成
        start = self.date + "0000"
        end = self.date + "2359"
        query_date = "submittedDate:[{} TO {}]".format(start, end)
        query += " AND " + query_date

        # 作成されたクエリを表示
        print("作成されたクエリ：\n{}\n".format(query))

        self.query = query
    
    def _to_dataframe(self):
        # listで出力されたarxivの情報をpandasのdfに変換する関数
        l = [] # 最終的にdfにするリスト
        i = 1
        for r in self.result_list:
            tmp = [] # 一時的なリスト
            tmp.append(i)
            tmp.append(self.date)
            tmp.append(r.title)
            tmp.append(None) # あとで翻訳したタイトルを入れる列
            tmp.append(r.summary)
            tmp.append(None)
            tmp.append(r.pdf_url)
            l.append(tmp)
            i += 1
        
        colunms = ["NO", "Date", "TITLE", "TITLE_jpn", "ABS", "ABS_jpn", "PDFlink"]
        df = pd.DataFrame(l, columns=colunms)
        df = df.set_index("NO")

        if __name__ == "__main__": print(df)

        self.result_df = df


    def run(self):

        self._make_query()

        client = arxiv.Client()

        search = arxiv.Search(
            query=self.query, 
            max_results = self.max_result, 
            sort_by = arxiv.SortCriterion.SubmittedDate
        )

        self.result_list = client.results(search)
        self.result_list = list(self.result_list)
        
        if __name__ == "__main__":
            print("取得したデータを表示")
            for r in self.result_list:
                print(r.title)
        
        self._to_dataframe()

    def translate(self):

        translator = Translator()

        # 翻訳を実行
        for row in range(self.result_df.shape[0]):

            self.result_df.iloc[row, 2] = translator.translate(self.result_df.iloc[row, 1], dest="ja").text
            self.result_df.iloc[row, 4] = translator.translate(self.result_df.iloc[row, 3], dest="ja").text

        if __name__ == "__main__": print(self.result_df)


    def save_to_excel(self, filename=None):
        # Excelに保存
        # ファイル名に特に指定がなければ日付をファイル名として保存する
        if filename is None: filename = self.date
        self.result_df.to_csv("{}.xlsx".format(filename))
```

# 参考文献一覧

- [arXiv Apiの利用規約](https://info.arxiv.org/help/api/tou.html)
- [Category Taxonomy](https://arxiv.org/category_taxonomy)
- [PythonでarXiv APIを使って論文情報取得、PDFダウンロード](https://note.nkmk.me/python-arxiv-api-download-rss/)
- [lukasschwab/arxiv.py: Python wrapper for the arXiv API](https://github.com/lukasschwab/arxiv.py)
- [Pythonでgoogletransを使って翻訳](https://qiita.com/optimisuke/items/e44e66c2646e763d1f7b)