PyAutoGUIパッケージのlocateOnScreen関数を使った時にOSErrorが発生する原因と回避方法について考えてみた件。（日本語パス問題）

## 実行環境 :computer:
+ Windows 10
+ Python 3.10
![パイソン.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222624/cd021dad-27e4-364e-5ae9-66d17e2fcfe8.jpeg)

## エラーの原因
　 <font color="red">**PyAutoGUI**</font> で画像認識をする時に、pyautogui.locateOnScreen("画像ファイルのパス")というコードを使用するが、その「画像ファイル」までのパス中に <font color="LightCoral">**日本語**</font> が含まれていると、 <font color="Crimson">**エラー**</font> が発生すると思われる。
![pyautoguiのlocateOnScreenによるエラーコード.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222624/10be4487-b9ab-55da-234a-a8ca1686aad6.jpeg)

　「<font color="Orange">ユーザー</font>」や「<font color="Gold">パブリック</font>」はエクスプローラー上で日本語表記であるが、パスを取得すると「<font color="Orange">Users</font>」や「<font color="Gold">Public</font>」というように英語で表記される。
![ユーザー名.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222624/6f4ada08-a371-4815-2865-eedc64af067c.jpeg)
　コードを書く方法ではなく、画像ファイルの命名や配置によってエラーを解消するには、画像ファイルの名前をアルファベットや数字のみにし、ユーザー・フォルダーの直下に画像ファイルを配置する方法がある。ただしユーザー名が日本語だとエラーは解消されないと思われる。

## エラーを回避する方法
　画像ファイルの名前に日本語が含まれており、またファイルがデスクトップのフォルダ中などの自由な場所に配置されている状態でも、正しくlocateOnScreen関数が動作するようにする方法について説明していく。注意点としては、画像認識の基となるファイルまでのパスに日本語が含まれてはいけないため、Tempフォルダ内に作成された一時フォルダ内に、さらに日本語が含まれるフォルダを作ったりすると、エラーになると思われる。

### 重要なモジュール
- <font color="Blue">tempfile</font>
![Tempフォルダ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222624/59134d12-c998-b4cb-afb2-71b351fda992.jpeg)
- shutil

## プログラムの概要 :pencil:
　事前に用意した電卓アプリのスクリーンショット画像を基にPyAutoGUIで画像認識を行い、画面上に電卓アプリが出現した後に、計算式の入力を行う。

<dl>
<dt>手順①</dt><dd>必要なモジュールをインポートする。Python標準ライブラリ（platform, subprocess, time, tempfile, os, shutil）。コマンドラインで「pip install pyautogui」と「pip install opencv_python」を実行してPyAutoGUIとOpenCVを入手してね。</dd>
<dt>手順②</dt><dd>画像認識に使用する画像ファイルの絶対パスを入力する。（ファイル配置や命名は自由。）</dd>
<dt>手順③</dt><dd>一時ディレクトリを作成する。（ランダムな文字列がフォルダ名に付与される。）</dd>
<dt>手順④</dt><dd>複製する画像ファイルの名前を指定する。（日本語が含まれないようにする。）</dd>
<dt>手順⑤</dt><dd>コピー元となる画像ファイルが存在するか確認し、手順④で決めた名前で画像のコピーを作成する。</dd>
<dt>手順⑥</dt><dd>電卓アプリを起動し、コピーした画像を基に画面上から電卓アプリを探す。</dd>
<dt>手順⑦</dt><dd>電卓に入力したいキーを送信する。</dd>
<dt>手順⑧</dt><dd>コピーした画像ファイルごと、一時フォルダを完全に削除する。</dd>
</dl>

### 期待通りに動作させるための前提条件
* 複製する画像ファイルの名前に<font color="Chocolate">日本語</font>を使わないこと。
* ユーザー名に<font color="Chocolate">日本語</font>が含まれないこと。
* コピーした画像ファイルの絶対パス"C:\Users\ユーザー名（英数字）\AppData\Local\Temp\コピーした画像ファイル（英数字）"のどこにも<font color="Chocolate">日本語</font>が入っていないこと。

![電卓スクリーンショット画像.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222624/45fa1c86-f522-8e3f-28bd-6840c1243b74.png)

~~~python:Calculator_AutoGUI改.py
import platform, subprocess, time
import pyautogui

import tempfile
import os
import shutil

# 参照するPNG画像までの絶対パス内に日本語が含まれていると、エラーが発生する。
# 一時的にディレクトリを作成して、エラーを回避してみる。

calculator_png = r"C:\Users\ユーザー名\OneDrive\デスクトップ\任意フォルダ１\任意フォルダ２\任意フォルダ３\電卓スクリーンショット画像.png"



tempdir = tempfile.TemporaryDirectory()

# 生成されたディレクトリ名を確認
print("一時フォルダ：", tempdir.name)

source = calculator_png
name = "calc.png" # 日本語を含まない名前を指定
name = name.replace("/", "-").replace("\\", "-").replace("|", "-").replace("!", "-").replace("<", "-").replace(">", "-").replace("?", "-").replace("*", "-").replace("　", "-")
# バツ　/ // \ \\ | ! < > ? * 　（全角スペース）
# マル　[ ] ( ) { } - _ = ^ ~ ' # $ % & , . + @ ` ; :  (半角スペース)
destination = tempdir.name + "\\" + name
if os.path.isfile(calculator_png):
    calc_png = shutil.copy(source, destination)
else:
    print("画像ファイルのパスが正しくありません。")
    tempdir.cleanup()
    exit()



if platform.system() == 'Windows':
    application = [r'c:\Windows\System32\calc.exe']
elif platform.system() == 'Darwin':
    application = ['open',
                   '/System/Applications/Calculator.app']

subprocess.Popen(application)

coordinate = None
for i in range(10):
    coordinate = pyautogui.locateOnScreen(calc_png,
                                          grayscale=True, confidence=0.8)
    if coordinate is None:
        time.sleep(1)
        print('電卓アプリを探しています・・・')
        continue
    break
if coordinate is None:
    pyautogui.alert('画面上に電卓アプリが見つかりません。用意したスクリーンショット画像が正しくないかもしれません。')
    tempdir.cleanup()
    quit()
print('見つかりました：', coordinate)

if platform.system() == 'Windows':
    pyautogui.write('2*3=', interval=0.3)
else:
    pyautogui.write('6')
print('キー送信完了')

# 最後は下記で一時フォルダを閉じるのを忘れずに。
tempdir.cleanup()
print("一時フォルダの削除完了")
~~~

### その他
+ エクスプローラー等で対象のファイルやフォルダーを選択した状態（チェックマーク☑が付いた状態）で、<font color="Cyan">Shiftキーを押しながらマウスを右クリック</font>すると、「パスのコピー」という項目が出現する。
![パスのコピー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222624/0b95cf6a-63b9-1b72-64f0-86962799690e.jpeg)
+ 一時ディレクトリ（Tempディレクトリ）の場所は、tempfileモジュールの「tempfile.gettempdir()」で確認できる。
+ フォルダ名までのパスを取得するには、osモジュールの「os.path.dirname(ファイルパス文字列)」を使う。
+ ユーザーフォルダ名は5文字で切れる。

#### 参考
[[Python] 一時ファイルを作成する(tempfileモジュール）](https://hibiki-press.tech/python/tempfile-md/2829 "tempfileモジュール")
+ シゴトがはかどるPython自動処理の教科書 （著者：クジラ飛行机）