はじめに
最近、Pythonのbar_chart_raceで、色んな統計データを動くグラフを作っていて、古い統計データがPDFでしかなく、データが困難で困っておりました。
具体的には、在日外国人の人口データ、1964年から2005年まで。
2006年からエクセルデータです。
試した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で照らし合わせていけばいいかと思い、しばらくデータを作ってました。
改善とプログラム
対応中に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に貼り付けられるようにした。
「プログラム」
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] で、国名だけをスクショ
2.ocr.py の実行
3.[Win + Shift + S] で、数字だけをスクショ
4.ocr.py の実行
5.Excelへデータの貼り付け
成果物
半分宣伝もありますが、こんな感じで動画が作れました。
「検証グラフch」
在日外国人数の国籍別ランキング
https://www.youtube.com/shorts/LZxVpG47W8M
以上、もっと精度向上、使いやすくなる方法を模索します。