PyAutoGUIとNuitkaでマクロを実行するアプリをつくる

## はじめに
タイトルの通り，Pythonを使って簡単なアプリを作ります。
今回のモチベーションはこれ。
![ad.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348972/9a9ed99e-770d-1c37-0b18-133322ebdffa.png)
Wordで数式を書く際にMathtypeのLite版を使用しているのですが，先日から数式を編集するたびに毎回このメッセージが出てくるようになりました。無料で使っている以上文句は言えないですが，とはいえ鬱陶しいので，このメッセージが出たら自動で閉じる(ボタンを押してくれる)アプリを作りました。

## PyAutoGUIについて
[PyAutoGUI](https://pyautogui.readthedocs.io/en/latest/index.html)について簡単に説明すると，Pythonプログラムからマウスやキーボードを操作するためのライブラリです。マクロ作成用ライブラリと言ってもよいかもしれません。

【参考】
[【PyAutoGUI】Pythonでマウスとキーボードを操作する](https://tech-blog.rakus.co.jp/entry/20220613/python)
[すばらしきpyautogui](https://qiita.com/ryo0819/items/d50ea8e19ba4855510ed)

## Nuitkaについて
Pythonプログラムを実行ファイル形式にしたい場面は往々にして発生しますが，そのようなツールとしておそらく現在一番有名なものは[Pyinstaller](https://pyinstaller.org/)だと思います。すでに多くの方が使い方の説明をされていますし，それ用のGUIアプリケーションなんかも提供されています。実際，私が以前公開したアプリ[BOXVIA](https://yamanaka-lab-tuat.github.io/BOXVIA/)についても，Pyinstallerで実行ファイル形式にして配布しています。

【参考】
[PyInstallerでexeファイル化](https://qiita.com/takanorimutoh/items/53bf44d6d5b37190e7d1)
[Pythonファイルを超簡単にexeファイル化するGUIソフト](https://qiita.com/osorezugoing/items/4ea5249c43c0ba8b89aa)
[【BOXVIA】ベイズ最適化用GUIアプリケーション](https://qiita.com/akmt-ishii/items/1d5354a1f1f75556281a)

一方で，Pyinstallerは「ファイルサイズが大きい」「起動が遅い」といった短所も持っています。特に，numpyやpandasのようなサイズの大きいライブラリを使った場合には数百MBにまで達することがあり，これをonefile形式(=ソースコードが見えないように単一ファイルにまとめること)で実行ファイルを作成すると，起動に数十秒～数分と目も当てられない状況になります。オープンソースとしてアプリを開発する場合は，onefile形式にせずに配布することである程度高速化はできますが，WindowsやLinuxではフォルダ内に大量のデータファイルが作成され，実行ファイルを探すのに手間取ります。

これに対して，Pythonプログラムを実行ファイル形式に変換する別のツールとして[Nuitka](https://github.com/Nuitka/Nuitka)があります。NuitkaはPythonプログラムを一度C言語に変換・コンパイルしてから実行するため起動が速く，また実行ファイルへの変換過程で圧縮されるためファイルサイズも抑制することができるようです。

【参考】
[PyInstaller より圧倒的に優れている Nuitka の使い方とハマったポイント](https://blog.tsukumijima.net/article/python-nuitka-usage/)

Nuitkaに関しては，[NUITKA-Utility](https://github.com/Nuitka/NUITKA-Utilities)というものが提供されており，これを使った実行ファイルの作り方の解説記事もいくつか存在します。が，このNUITKA-UtilityはNuitka本体のバージョンアップに対して更新されておらず，今使うと逆にいろいろなエラーが出てきてしまいます。NUITKA-Utilityのgithubの説明にも，"This is considered obsolete and unmaintained. Use Nuitka, it's gaining all the features previously here. (意訳:NUITKA-Utilityはメンテされてなくて古いから，ここにあった機能をもう全部持っているNuitra本体を使ってね)"と書かれています。

【参考】
[NUITKA-Utilitiesで簡単Pythonコンパイル](https://qiita.com/dinosauria123/items/abbbc01362cf41d6b9d8)
[簡単にPythonスクリプトから実行ファイルを作れるNUITKA-Utilities hinted-compilationの使い方](https://qiita.com/Miyabi1456/items/e44864d307e6d253cd30)
[NuitkaでPlotlyをアプリケーション化する](https://qiita.com/3ne4ge/items/313a8d7d432b0bcd8261)

## ライブラリのインストール
今回の作業環境は，**Windows10 64bit**, **Python3.8.10**です。
Anacondaは使わず，pipでインストールしていきます。

まずPyAutoGUIと，依存関係にあるOpenCVを入れます。OpenCVにはnumpyも必要なので，もし無ければ入れてください。
```bash
pip install pyautogui opencv-python
```
さらに，Nuitka本体と，関連するライブラリを入れていきます。
```bash
pip install nuitka zstandard ordered-set
```
zstandardは圧縮や解凍に使うライブラリらしく，onefile形式で作成するために必要なそうです。ordered-setについては無くても動きますが，これの有無で実行ファイル作成に要する時間が大きく変わってくるので，入れておきましょう。

## プログラムの作成
メッセージボックスを閉じるためのプログラムを作ります。
[こちらの記事](https://qiita.com/ryo0819/items/d50ea8e19ba4855510ed)を大いに参考にしました。

```python:adclose.py
import pyautogui as pag
pag.FAILSAFE = True
pag.PAUSE = 1.0

img = "ad.png"

while True:
    try:
        if pag.locateOnScreen(img, confidence=0.9) is None:
            continue
        else:
            x, y = pag.locateCenterOnScreen(img, confidence=0.9)
            pag.click(x+50, y+30)

    except KeyboardInterrupt:
        exit('Terminated')
    except:
        pass
```

ad.pngはこの記事の冒頭に示したメッセージボックスの画像です。この画像と概ね一致する (信頼度0.9の) 画像がスクリーンに現れたら，その位置を参照して閉じるをクリックするという仕組みです。


## Nuitkaで実行ファイルを作る
では，Nuitkaを使って実行ファイルを作成します。以下のコマンドを実行してください。

```bash
 nuitka --mingw64 --assume-yes-for-downloads --follow-imports --enable-plugin=numpy --include-data-files=ad.png=ad.png --onefile adclose.py
```

このとき，ad.pngはadclose.pyと同じ場所に置いてください。NuitkaはPyinstallerよりも実行ファイルを作成するのにかなり時間がかかるため，しばらく待ちましょう。問題なくいけば，フォルダに「adclose.exe」が出来上がっているはずです。
(adclose.build, adclose.dist, adclose.onefile-buildというフォルダも発生していますが，これはexeファイルが出来上がった後なら消してしまって構いません。)

adclose.exeを実行し，何も表示されないコンソールが出れば問題ありません。その状態でMathtypeのメッセージボックスが出れば，自動で消してくれます。コンソールを非表示にすることもできますが，そうするとバックグラウンドでアプリが起動し続けることになるので，今回はこれでひとまず完成ということにしておきます。なお，ad.pngとadclose.exeは常に同じ場所に置くようにしてください。