OCRで読み込めないPDFをpyocrでなんとかデータ化した話

## はじめに
最近、Pythonのbar_chart_raceで、色んな統計データを動くグラフを作っていて、古い統計データがPDFでしかなく、データが困難で困っておりました。

具体的には、在日外国人の人口データ、1964年から2005年まで。
2006年からエクセルデータです。

こんな感じ：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249830/b7553276-a35c-48b4-df27-91c68391a163.png)

原本：
https://www.e-stat.go.jp/stat-search/files?page=1&layout=datalist&toukei=00250012&tstat=000001018034&cycle=7&year=19640&month=0&tclass1=000001060436&result_back=1&cycle_facet=tclass1&tclass2val=0


## 試したOCR
・iLovePDF（無料版）
・light PDF（無料版）
・PDF Reader（有料版OCR）
　→体験7日間以内に止めたので、実質無料

総じてダメダメでした。
全くExcelに貼り付けられる状態じゃない。

## 最初の設計
設計：全部OCR化するのは諦めて、重要なデータのみを抽出することに
1.PDFを開いて、国名を[Win+Shift+S]でスクリーンショット
2.PythonのPGでクリップボード→画像ファイル→OCR→文字をクリップボード→Excelへ
3.PDFを開いて、人口を[Win+Shift+S]でスクリーンショット
4.[2]と同じ

### 環境・インストール
「環境」
・VS Code
・Python 3.11（このバージョンじゃないとbar_chart_raceが動かない）

「pythonのモジュールインストール」
・pyocr
・pyperclip
・Tesseract

参考サイト：
https://note.nkmk.me/python-pyperclip-usage/
https://takaaki-hobby-blog.com/python/python_ocr/

# 実践
さてやってみたところ、国の精度がよろしくない。

|結果|国名|OCR結果|
|:-:|:---|:---|
|×| アフダニスタン     | アフガニスタン |
|×| アラブ首長国逢芦   | アラブ首長国連邦 |
|×| ミャシマ           | ミャンマー |
|×| バハレシ           | バーレーン |
|×| プタン             | プータン |
|×| バンクタラテシュ   | バングラディシュ |
|◯| プルネイ           | ブルネイ |
|×| カンポテディア     | カンボジア |
|◯| スリランカ         | スリランカ |
|×| い団               | 中国 |
|×| すキマチホネ       | サイプラス |
|×| ィシド             | インド |
|◯| インドネシア       | インドネシア |
|◯| イラン             | イラン |
|×| ィラク             | イラク |
|◯| イスラエル         | イスラエル |
|×| ジショルダン       | ジョルダン |
|×| 森国剣鉄           | 韓国・朝鮮 |
|×| クウェイト         | クウェート |
|×| ラォス             | ラオス |

全体的な精度として、20%くらい。
数字の方は、結構いいです。

国名はそこまで変わらないので、ご認識データベースを用意して、Vlookupで照らし合わせていけばいいかと思い、しばらくデータを作ってました。

Excelデータ部：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249830/5bf17502-f1ee-122b-64dc-2a48c1fffade.png)

国マスタ：
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249830/cbfafb59-9e9b-034b-fd51-03f3e80ef655.png)

# 改善とプログラム
対応中にPGを色々変えました。

1.OCR結果に改行が多く含まれてしまうので、改行コード2つを、1つにreplace
> replace('\n\n','\n')

2.ファイルの有無で国と値を使い分けて、OCRの言語ファイルを切替
これにより、国データと値を一気に貼り付けが出来るように

3.よく間違える文字をreplace
「国名」
.replace(' ','')   # 半角スペース除去
.replace('ー','')  # なぜかハイフンが多いので、除去
.replace('=','ニ') # カナ[に]がイコールになるので、置換

「数字」
.replace(' ','')   # 半角スペース除去
.replace(',','')   # カンマ[,]除去
.replace('.','')   # ドット[.]除去
.replace('B','8')  # B を 8 へ置換

4.2回に分けて実行し、国名とデータをTSV形式でクリップボードへ貼り付けて、Excelに貼り付けられるようにした。

「プログラム」
```python:ocr.py
import os
import sys
import shutil

from datetime import datetime
#PyOCRを読み込む
from PIL import ImageGrab, Image
import pyocr
import pyperclip

# ルートディレクトリのパスを指定
ROOT_PATH = 'C:\\kensho_files\\python_project\\temp\\'

TEMP_IMG_FILE_COUNTRY_V = 'clipboard_image_t.png'
TEMP_IMG_FILE_VALUE_V   = 'clipboard_image_c.png'

TEMP_IMG_FILE_COUNTRY = ROOT_PATH + TEMP_IMG_FILE_COUNTRY_V
TEMP_IMG_FILE_VALUE = ROOT_PATH + TEMP_IMG_FILE_VALUE_V

TEMP_RM_FOLDER_VALUE = ROOT_PATH + 'end'
#sys.path.append(ROOT_PATH)

img = ImageGrab.grabclipboard()

ocr_flg = False

#print(img)
if img != None:
    # <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=200x71 at 0x105E68700>
    #print(isinstance(img, Image.Image))
    # True
    #print(img.size)
    # (200, 71)
    #print(img.mode)
    # RGB

    # 国ファイルが存在するかどうかをチェック
    if os.path.isfile(TEMP_IMG_FILE_COUNTRY):
        # 存在する場合、値として保存
        img.save(TEMP_IMG_FILE_VALUE)
        # OCR実施
        ocr_flg = True
    else:
        # 存在しない場合、国として保存
        img.save(TEMP_IMG_FILE_COUNTRY)
else:
    # 両方のファイルが有ればOCR実施
    if os.path.isfile(TEMP_IMG_FILE_COUNTRY) and os.path.isfile(TEMP_IMG_FILE_VALUE):
        ocr_flg = True

# OCRを実施しないなら、終了
if ocr_flg == False:
    sys.exit()

#################################
# 以下OCR処理
#################################

#Tesseractのインストール場所をOSに教える
tesseract_path = "C:\Program Files\Tesseract-OCR"
if tesseract_path not in os.environ["PATH"].split(os.pathsep):
    os.environ["PATH"] += os.pathsep + tesseract_path

#OCRエンジンを取得する
tools = pyocr.get_available_tools() 
if len(tools) == 0:
    print("OCRエンジンが指定されていません")
    sys.exit(1)
else:
    tool = tools[0]

## OCR読み鉾処理
def exec_ocr(cv_value):
    #画像の読み込み
    if cv_value == 'c':
        img = Image.open(TEMP_IMG_FILE_COUNTRY)
    else:
        img = Image.open(TEMP_IMG_FILE_VALUE)

    #文字を読み取る
    builder = pyocr.builders.TextBuilder(tesseract_layout=6)
    #result = tool.image_to_string(img,lang="jpn",builder=builder)
    if cv_value == 'c':
        result = tool.image_to_string(img,lang="jpn",builder=builder)
    else:
        result = tool.image_to_string(img,lang="eng",builder=builder)

    if result.find('\n\n'):
        result = result.replace('\n\n','\n')

    lines = result.split('\n')

    #print ('件数：'+str(len(lines)))
    print ('**************')
    print ('件数：'+str(len(lines)))
    i = 0
    for a in lines:
        if cv_value == 'c':
           s_ocr_result.append('') 

        if s_ocr_result[i] == '':
            s_ocr_result[i] = a.replace(' ','').replace('ー','').replace('=','ニ')
        else:
            s_ocr_result[i] += '\t' + a.replace(' ','').replace('.','').replace(',','').replace('B','8')
        i += 1


# OCRの値を配列の取得する
s_ocr_result = []

exec_ocr('c')
exec_ocr('v')

s_value = ''
for s in s_ocr_result:
    if s != '':
        s_value += s + '\r\n'

# クリップボードに値を貼り付け
pyperclip.copy(s_value)

############################
# 事後処理
############################

# 現在の日時を取得
now = datetime.now()
# 日時を文字列に変換（フォルダ名として使用可能な形式）
folder_name = now.strftime("%Y%m%d_%H%M%S")
# フォルダが存在しない場合に新しいフォルダを作成
os.mkdir(TEMP_RM_FOLDER_VALUE + '\\' + folder_name)

# ファイルを移動
shutil.move(TEMP_IMG_FILE_COUNTRY, TEMP_RM_FOLDER_VALUE + '\\' + folder_name + '\\' + TEMP_IMG_FILE_COUNTRY_V)
shutil.move(TEMP_IMG_FILE_VALUE, TEMP_RM_FOLDER_VALUE + '\\' + folder_name + '\\' + TEMP_IMG_FILE_VALUE_V)

sys.exit(1)

```

# 使い方（備忘録）

### 1.[Win + Shift + S] で、国名だけをスクショ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249830/3dca0e9b-2179-2af0-c7ae-5bcc79f2d05e.png)

### 2.ocr.py の実行

### 3.[Win + Shift + S] で、数字だけをスクショ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249830/226b2dfa-733f-1f38-c47a-f14b3a9f737e.png)

### 4.ocr.py の実行
### 5.Excelへデータの貼り付け
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/249830/f04e8df5-67b0-ea10-e252-20aa3fee1d00.png)


# 成果物
半分宣伝もありますが、こんな感じで動画が作れました。

「検証グラフch」
在日外国人数の国籍別ランキング
https://www.youtube.com/shorts/LZxVpG47W8M


以上、もっと精度向上、使いやすくなる方法を模索します。