【Python】英語学習のために英作文を翻訳するプログラムを作成してみた

最近、英語学習をはじめました。
その際に英作文の添削をしてもらっているため、後で日本語のみで英作文をしたいと思い至りました。

そこで、添削がかかった文章のPDFを翻訳し、日本語のみのスクリプトを作成するプログラムがあったら便利なのではと思い、実際に作ってみました。

その際にPDF関連のライブラリなど学びが多かったのでシェアいたします。

# 実装
```python:trans.py
from googletrans import Translator

from pdfminer.pdfpage import PDFPage
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams

import pathlib

import re

# PDFファイルのパスを取得
p_temp = pathlib.Path('./files').glob('*.pdf')
# ファイル名をリストで取得
temps = [p.name for p in p_temp]

# Layout Analysisのパラメーターを設定
laparams = LAParams()

# 共有リソースを格納するPDFリソースマネージャーオブジェクトを作成
resource_manager = PDFResourceManager()

# 翻訳のオブジェクト作成
tr = Translator(service_urls=['translate.googleapis.com'])

def interpreter_pdf(input_file, output_file):
  """PDFファイルのテキストデータを抽出し、テキストファイルに出力する関数

  Args:
      input_file (_type_): 読み込むPDFファイル (io.BufferedReader)
      output_file (_type_): 出力先ファイル (io.TextIOWrapper)
  """
  # テキストに変換
  device = TextConverter(resource_manager, output_file, laparams=laparams)

  # ページの内容を処理するためのPDFインタプリタオブジェクトを作成
  interpreter = PDFPageInterpreter(resource_manager, device)

  # ドキュメントに含まれる各ページを処理
  for page in PDFPage.get_pages(input_file):
      interpreter.process_page(page)
      
  # ファイルを閉じる
  output_file.close()

def translate_file(w_list):
  """PDFファイルから作成したテキストファイルを翻訳し、リストに格納する処理

  Args:
      w_list (_type_): 翻訳後のテキストを格納するリスト (list)

  Returns:
      _type_: list
  """
  # PDFからテキストデータのみ書き込んだファイルを読み込む
  with open(f"./txt/{f_name}.txt") as f:
    # ファイルを行数分リストに格納
    l_strip = [s.strip() for s in f.readlines()]
    
    for strip in l_strip:
      # 行に英字が存在する場合
      if re.search(r"[a-zA-Z]", strip):
        # 英語文字列をリストに格納
        # w_list.append(strip)
        
        # 英語を翻訳する
        result = tr.translate(strip, dest="ja")
        # 翻訳語の文字列をリストに格納
        w_list.append(f"{result.text}\n")
      
    f.close()
    
    return w_list

def distinct_list(w_list):
  """リストの重複を取り族関数

  Args:
      w_list (_type_): 翻訳後のテキストを格納しているリスト (list)
  """
  with open(f"./txt/{f_name}.txt", 'w') as f:
    # 重複を除去したリストをファイルに書き込む
    f.write('\n'.join(list(dict.fromkeys(w_list))))
    f.close()

# PDFファイル数分繰り返し
for temp in temps:
  # ファイル名称部分のみの文字列に置き換える
  f_name = temp.replace('.pdf', '')

  # PDFファイル読み込み
  input_file = open(f"./files/{f_name}.pdf", 'rb')
  # txtファイルでの出力先ファイル
  output_file = open(f"./txt/{f_name}.txt", 'w')
  
  # PDFファイルを処理する関数を呼び出し
  interpreter_pdf(input_file, output_file)
  
  # 翻訳前後のテキストをリストにする関数の呼び出し
  w_list = translate_file(w_list=[])
  
  # リストの重複を除去する関数の呼び出し
  distinct_list(w_list)
```

まずは、`pathlib`ライブラリを使用して、PDFファイルのパスを取得します。その後、ファイル名をリストで格納しました。
なぜ、こんなことをしているのかというと、PDFファイル分処理をループしたいという意図もありますが、翻訳したファイルの名前もPDFファイルと合わせたかったからです。

続く`LAParams`と`PDFResourceManager`はPDFからテキストのみを読み込むのに必要となるライブラリです。
※ 詳細は、記事の最下部の**参考文献**を参照ください。

続く`Translator`は翻訳をするためのライブラリです。

これで処理の準備は整ったのでメインの処理の解説に移ります。

## PDFファイルをテキストデータにする
まずは、PDFファイルと出力先のファイルを定義します。
PDFの場合、バイナリーデータのためモードは`rb`で読み込みます。

そして、PDFのデータをテキストに変換するため`TextConverter`を作成します。
さらに続けて、`PDFPageInterpreter`を作成し、PDFの内容を処理する準備をします。

続くfor文でようやくPDFの内容を処理します。
ページ分ループを回しPDFファイルの内容を処理内容に従い、出力先のファイルに書き込んでいきます。

### 翻訳処理
次に翻訳処理ですが、PDFから抽出したテキストデータを書きこんでいるテキストファイルのデータを読み込み、それを1行ずつ翻訳し、リストに格納するという処理を行います。

まずは、リスト内包表記でファイルの行数分をリストに格納します。
その後、そのリストをループさせ英字が含まれている場合のみ、翻訳し、翻訳後のテキストをリストに格納する処理を行いました。

ここでは翻訳するために`Translator`の`translate()`メソッドを使用し、引数に翻訳したい文字列と、翻訳後の言語を指定します。

そして、関数の返り値として翻訳後のテキストリストを返すようにします。

最後に、私の個人的に必要となった処理として添削前と添削後の英文で重複があったため、重複をなくす処理を実装しています。

このようにすると、以下のように日本語訳のスクリプトができ、これを利用して、日本語のみで英作をするという復習が可能となりました。
![スクリーンショット 2022-07-03 12.20.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/879778/f54d398c-0cad-0c1f-8815-dfcc7a679dc1.png)

![スクリーンショット 2022-07-03 12.16.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/879778/8f6bc882-be22-b73d-e31a-04f9aefee160.png)

ただ、PDF内で改行があると単語として訳されるのが難点でした。
また、翻訳の精度もところどころ悪いので、大枠はこの処理を使用して、細かい部分は手を入れるということになりそうです。

面倒ですが、それでも1からスクリプトを作成するより多少、時短になるのではないでしょうか。

# 参考文献
- [【Pythonで自動化】コピペしていない？大量PDFからテキスト情報を一瞬で取得](https://kino-code.com/python-pdf/)
- [【python】googletransの『AttributeError: 'NoneType' object has no attribute 'group'』対策【2021/01/12追記】](https://qiita.com/_yushuu/items/83c51e29771530646659)
- [Pythonでリスト（配列）から重複した要素を削除・抽出](https://note.nkmk.me/python-list-unique-duplicate/)