【#RPA】管理者権限を持たないWindows環境に「jPortable」と「SikuliX」をインストールして「Python(Jython)」のスクリプトでGUI操作の自動化を試みる #pyconjp #PyLadiesTokyo #Excel #自動化 #SikuliX

管理者権限を持たないWindows端末に「jPortable」とRPAツールである「SikuliX」をインストールして「Python(Jython)」スクリプトでGUI操作の自動化を試みた際の内容を自分用のメモとしてまとめました。

# `SikuliX`とは
マサチューセッツ工科大学がオープンソースで開発/公開しているIDE(`SikulixIDE`)含めたRPAツール群です。
内部ではオープンソースの画像処理ライブラリ「`OpenCV`」を利用しており画像認識によるGUI操作の自動化が行えるのが特徴です。
`SikuliX`および`SikulixIDE`は JavaVM 上で動作し、自動化したい処理を記述するスクリプト部分は`Python(Jython)`もしくは`Ruby(JRuby)`で記述します。
そのため、`SikuliX`は一般的なRPAツールのような使い方もできますが、「Python」等のスクリプト言語でGUI操作自動化を行うためのツールと考えても良いかもしれません。
ちなみに`SikulixIDE`は↓のようなUIで直感的に操作することが可能です。

![capture_064_25072019_094117.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/a1fce131-e42d-ca35-dbb5-69a67d2973bc.jpeg)

---

#### まず、実行/開発環境を準備するにあたり、任意の場所に`SikuliX`という名前のフォルダーを作成し以下の3つのファイルをあらかじめダウンロードしておきます

|No. |ファイル名 |入手元URL |
|--- |--------- |--------- |
|1. |jPortable_8_Update_221_online.paf.exe |https://portableapps.com/apps/utilities/java_portable |
|2. |JavaPortableLauncher_5.0.paf.exe |https://portableapps.com/apps/utilities/java_portable_launcher |
|3. |sikulixsetup-1.1.3.jar |https://launchpad.net/sikuli/sikulix/ |

## 1. `jPortable`のインストール

`SikuliX`はJava環境で動作します。そのため、まずはJavaの実行環境がインストールされていない且つローカルの管理者権限を持っていなくてもJavaアプリを実行させることが可能なツールである`jPortable`をインストールします。

### □手順 1-1: あらかじめダウンロードしておいた`jPortable_8_Update_221_online.paf.exe`を実行します

### □手順 1-2: 言語の選択画面が表示されるので、そのまま(日本語のまま)`OK`ボタンをクリックします

![capture_038_25072019_093308.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/3df663a1-9b0e-d013-1167-9509640e247c.jpeg)

### □手順 1-3: ウィザードが起動するので`次へ`ボタンをクリックします

![capture_039_25072019_093312.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/d111e959-b02f-5e08-96b1-914b95504cc6.jpeg)

### □手順 1-4: ライセンス条件を確認し`同意する`ボタンをクリックします

![capture_040_25072019_093316.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/1c6f8c79-7329-a3d7-2bc9-829bf1f46658.jpeg)

### □手順 1-5: インストール先のパスを確認されるので、そのまま`インストール`ボタンをクリックします

![capture_041_25072019_093326.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/37095cb4-4157-c1aa-2722-774c71ba3b7f.jpeg)

### □手順 1-6: 無事にインストールが完了したことを確認し`完了`ボタンをクリックします

![capture_002_25072019_124050.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/18df512b-6418-6965-bb86-602b2586c9d1.jpeg)

## 2. `jPortable Launcher`のインストール

続いて`jPortable`がインストールされた環境で`jarファイル`を実行するためのランチャーツールである`jPortable Launcher`をインストールします

### □手順 2-1: あらかじめダウンロードしておいた`JavaPortableLauncher_5.0.paf.exe`を実行します

### □手順 2-2: 言語の選択画面が表示されるので、そのまま(日本語のまま)`OK`ボタンをクリックします

![capture_044_25072019_093354.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/b7f86775-b8f0-d5d6-b846-c69ed56bc5b3.jpeg)

### □手順 2-3: ウィザードが起動したら`次へ`ボタンをクリックします

![capture_045_25072019_093358.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/8d61a6a1-2af1-77f6-1460-a79a00b03548.jpeg)

### □手順 2-4: インストール先のパスを確認されるので、そのまま`インストール`ボタンをクリックします

![capture_046_25072019_093402.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/ba26e120-ff3f-1934-ef87-653bf8e38861.jpeg)

### □手順 2-5: 無事にインストールが完了したことを確認したら`jPortable Launcherを実行`にチェックを入れて`完了`ボタンをクリックします

![capture_048_25072019_093412.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/49b9417a-0943-a574-16a6-1de7bc26f362.jpeg)

### □手順 2-6: `jarファイル`の選択画面が表示されるのでこのまま`SikuliX`のインストールに進みます

![capture_049_25072019_093435.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/e5fbb6f7-8cc3-7df9-bef9-d4e748e494fa.jpeg)

## 3. `SikuliX`のインストール

`jPortable Launcher`を使って`sikulixsetup-1.1.3.jar`ファイルを実行し`SikuliX`のインストールを行います

### □手順 3-1: `sikulixsetup-1.1.3.jar`を選択して`開く`ボタンをクリックします

![capture_049_25072019_093435.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/e5fbb6f7-8cc3-7df9-bef9-d4e748e494fa.jpeg)

### □手順 3-2: `はい`ボタンをクリックします

![capture_050_25072019_093444.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/b8a33486-c540-c101-b947-821f01452a60.jpeg)

### □手順 3-3: `1-Pack1: Iwant SikuliX～`にチェックを入れて`Setup Now`ボタンをクリックします

#### ※使用するスクリプトとして Ruby(JRuby) を選択することも可能ですが、ここではデフォルトの Python(Jython) のみにチェックを入れます

![capture_052_25072019_093454.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/b255b433-d86e-be6d-a309-7a5cf8d37611.jpeg)

### □手順 3-4: 確認のメッセージが表示されるので`はい`ボタンをクリックします

![capture_053_25072019_093459.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/649e8928-5d4c-fef4-06ca-1654ed0ea0ff.jpeg)

### □手順 3-5: `Jython`のインストールについて確認を求められるため、そのまま`はい`ボタンをクリックします

![capture_056_25072019_093539.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/d9a9a310-f32e-550e-ecc8-8cbe9f1c1b05.jpeg)

以上でインストールが完了です

## 4. 不要ファイルの削除と`runsikulix.cmd`ファイルの編集

`JavaPortableLauncher`及びインストーラーやインストール時に生成されたファイルやログは不要なので削除をします。加えて、実行ファイル(cmdファイル)に環境変数`JAVA_HOME`を明示的に記載することでJava実行環境として`jPortabale`を使用するように編集します。

### □手順 4-1: 以下のファイルとフォルダを削除します

* `JavaPortableLauncher`フォルダ
* `SetupStuff`フォルダ
* `JavaPortableLaunher_5.0.paf.exe`ファイル
* `jPortable_8_Update_221_online.paf.exe`ファイル
* `SikuliX-1.1.3-Setuplog.txt`ファイル 

### □手順 4-2: `runsikulix.cmd`を任意のテキストエディタで開きます

### □手順 4-3: 18行目に`set JAVA_HOME=%SIKULIX_HOME%\CommonFiles\Java`と追記してテキストエディタを終了します

```bat:runsikulix.cmd
 1 @echo off
 2 SETLOCAL ENABLEEXTENSIONS
 3 set SJAR=sikulix
 4 
 5 if not defined SIKULIX_HOME goto NOHOME
 6 if EXIST "%SIKULIX_HOME%%SJAR%.jar" goto YESHOME
 7 if not EXIST "%SIKULIX_HOME%\%SJAR%.jar" goto BADHOME
 8 set SJAR=\sikulix
 9 
10 :BADHOME
11 echo +++ SIKULIX_HOME specified but not useable %SIKULIX_HOME%
12 
13 :NOHOME
14 set SIKULIX_HOME=%~dp0
15 
16 :YESHOME
17 set PARMS=-Xms64M -Xmx512M -Dfile.encoding=UTF-8 -Dsikuli.FromCommandLine
18 set JAVA_HOME=%SIKULIX_HOME%\CommonFiles\Java
19 if not defined JAVA_HOME goto CHECKJAVA
20 IF EXIST "%JAVA_HOME%\bin\java.exe" goto JAVA_OK
21 echo +++ JAVA_HOME specified but not useable %JAVA_HOME%
22 echo +++ looking for Java in system path and then in standard places
 :
中略
 :
```

## 5. SikuliX IDE の実行

### □手順 5-1: `runsikulix.cmd`ファイルを実行します

IDE が起動してきます。日本語化もされており細かい制御が不要であれば、Pythonの知識も不要で直感的に自動化スクリプトの定義が可能かと思います。

![capture_064_25072019_094117.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/a1fce131-e42d-ca35-dbb5-69a67d2973bc.jpeg)

## 6. GUI操作自動化サンプル

続いてGUI操作自動化のサンプルとして、あらかじめEXCELに入力されているデータを読み取り、そのデータを電卓に入力(GUI操作)、その結果をテキストファイルに出力してみます

### □手順 6-1: `インプット用Excelファイル`の準備

まずは`A列`にランダムな数字を記載しただけのExcelファイルを作成しデスクトップ上に`インプットファイル.xlsx`という名前で保存します

![capture_002_03082019_121450.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/8ae508fb-2b3d-8927-c7ec-7b60e1855fc6.jpeg)

### □手順 6-2: `SilulixIDE`を起動します

`runsikulix.cmd`ファイルを実行します

![capture_064_25072019_094117.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/a1fce131-e42d-ca35-dbb5-69a67d2973bc.jpeg)

### □手順 6-4: [ファイル]メニューから[名前を付けて保存]を選択し任意の名前で保存します

ここではデスクトップ上に`GUI操作自動化サンプル`という名前で保存します
するとデスクトップ上に`GUI操作自動化サンプル.sikuli`という名前でフォルダーが作成されます

### □手順 6-5: Excelファイル上のシートの読み取り

まずは、先ほど作成した`インプット用Excelファイル`のシートを "Python(Jython)" で読み込むところまでを記載します

```python:GUI操作自動化サンプル(抜粋)
import os
import subprocess
import xlrd
import datetime

# デスクトップ上にある"インプットファイル.xlsx"というExcelファイルから最初のシートを読み込みます
inputExcelFilePath = os.environ["USERPROFILE"] + "\Desktop\インプットファイル.xlsx"
inputExcelFile = xlrd.open_workbook(inputExcelFilePath)
inputExcelSheet = inputExcelFile.sheet_by_index(0)
 :
中略
 :
```

`.sheet_by_index(0)`で一番最初のシートを読み取ります
※`.sheet_by_index(1)`と記載すれば2番目のシート読み取ります

### □手順 6-6: [電卓]アプリの起動の自動化

次に`電卓`アプリを起動するところの自動化を記載します

アプリケーションの起動は次のように記載します

```python:GUI操作自動化サンプル(抜粋)
 :
中略
 :
# 電卓を起動します
App.open("calc.exe")
wait(<起動画面のスクリーンショット>)
 :
中略
 :
```

`App.open("プログラム名")`と記載することでアプリケーションの起動を自動化できます

`wait()`の部分は`SikulixIDE`の画面左のコマンドリストからスクリーンショットを取得することができます
スクリーンショットで取得した画像が画面上に表示されるまで次の処理がウェイトされます

![capture_003_03082019_122759.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/32133e58-252b-667f-4da3-9816fa7abfa6.jpeg)

### □手順 6-7: "インプットファイル.xlsx"に記載されている数字を順に[電卓]アプリに入力していく処理の自動化

"Python(Jython)" の`for`ループを使って、Excelシート上のデータを0行目から値が記載されている行まで順に読み取ります

```python:GUI操作自動化サンプル(抜粋)
 :
中略
 :
# 読み取ったExcelシートの0列目から順に値が記載されている内容を1行ずつ読み取り電卓に打ち込みます
for rowNumber in range(0,inputExcelSheet.nrows):
  type(str(inputExcelSheet.cell_value(rowNumber,0)))
  click(<電卓アプリ上の[+]ボタンのスクリーンショット>)  
  hover(<電卓アプリ上の[=]ボタンのスクリーンショット>)
 :
中略
 :
```

* `type()`を使ってキーボードのタイプを自動化します
* `click()`は、画面左のコマンドリストを使って取得したスクリーンショット部分のクリックを自動化します
* `hover()`は、画面左のコマンドリストを使って取得したスクリーンショット部分をクリックせずにマウスカーソルのみあわせます


### □手順 6-8: 計算結果をテキストファイルに出力する処理の自動化

`SikuliX`では[CTRLキー]などの特殊キーのタイプは次のように指示します

|特殊キー |タイプの指示方法 |
|------- |-------- |
|ENTERキー |type(Key.ENTER) |
|CTRLキー |type(Key.CTRL) |
|SHIFTキー |type(Key.SHIFT) |
|ALTキー |type(Key.ALT) |
|プリントスクリーン キー |type(Key.PRINTSCREEN) |
|PAGEUPキー |type(Key.PAGE_UP) |
|PAGEDOWNキー |type(Key.PAGE_DOWN) |
|HOMEキー |type(Key.HOME) |
|ENDキー |type(Key.END) |
|↑キー |type(Key.UP) |
|→キー |type(Key.RIGHT) |
|↓キー |type(Key.DOWN) |
|←キー |type(Key.LEFT) |
|TABキー |type(Key.TAB) |
|DELETEキー |type(Key.DELETE) |
|BACKSPACEキー |type(Key.BACKSPACE) |
|ファンクションキー |type(Key.F1) |
|ESCキー |type(Key.ESC) |
|SPACEキー |type(Key.SPACE) |
|Windowsキー |type(Key.WIN) |
|INSERTキー |type(Key.INSERT) |
|NUMLOCKキー |type(Key.NUM_LOCK) |
|/ |type(Key.DIVIDE) |
|* |type(Key.MULTIPLY) |
|- |type(Key.MINUS) |
|+ |type(Key.ADD) |
|CapsLockキー |type(Key.CAPSLOCK) |
|Pauseキー |type(Key.PAUSE) |
|ScrollLockキー  |type(Key.SCROLL_LOCK) |

まず、[CTRLキー]＋[C]で[電卓]アプリの計算結果をクリップボードに取り込みます
"Python(Jython)" を使ってクリップボードに取り込んだデータをテキストファイルに出力して保存します

```python:GUI操作自動化サンプル(抜粋)
 :
中略
 :
# CTRLキー＋Cでクリップボードに取り込んだ電卓の計算結果を変数に取り込みます
type("c",Key.CTRL)
from java.awt import Toolkit
from java.awt.datatransfer import DataFlavor
toolkit = Toolkit.getDefaultToolkit()
clipboard = toolkit.getSystemClipboard()
clipboardContents = clipboard.getContents(None)
culcurationResult = clipboardContents.getTransferData(DataFlavor.stringFlavor)

# 計算結果をテキストファイルに出力します
nowDatetime = datetime.datetime.now()
outputTextFilePath = os.environ["USERPROFILE"] + "\Desktop\アウトプットファイル_" + nowDatetime.strftime("%Y%m%d_%H%M") + ".txt"
outputTextFile = open(outputTextFilePath,"w")
outputTextFile.write("Culcuration result is " + culcurationResult + "." )
outputTextFile.close()
 :
中略
 :
```

### □手順 6-9: [ファイル]メニューから[保存]を選択して作成したスクリプトを保存します

ここまでの部分で作成したスクリプトです

```python:GUI操作自動化サンプル
import os
import subprocess
import xlrd
import datetime

# デスクトップ上にある"インプットファイル.xlsx"というExcelファイルから最初のシートを読み込みます
inputExcelFilePath = os.environ["USERPROFILE"] + "\Desktop\インプットファイル.xlsx"
inputExcelFile = xlrd.open_workbook(inputExcelFilePath)
inputExcelSheet = inputExcelFile.sheet_by_index(0)

# 電卓を起動します
App.open("calc.exe")
wait("1564793193116.png")

# 読み取ったExcelシートの0列目の内容を1行ずつ読み取り電卓に打ち込みます
for rowNumber in range(0,inputExcelSheet.nrows):
  type(str(inputExcelSheet.cell_value(rowNumber,0)))
  click("1564793209633.png")  
  hover("1564793224493.png")

# CTRLキー＋Cでクリップボードに取り込んだ電卓の計算結果を変数に取り込みます
type("c",Key.CTRL)
from java.awt import Toolkit
from java.awt.datatransfer import DataFlavor
toolkit = Toolkit.getDefaultToolkit()
clipboard = toolkit.getSystemClipboard()
clipboardContents = clipboard.getContents(None)
culcurationResult = clipboardContents.getTransferData(DataFlavor.stringFlavor)

# 計算結果をテキストファイルに出力します
nowDatetime = datetime.datetime.now()
outputTextFilePath = os.environ["USERPROFILE"] + "\Desktop\アウトプットファイル_" + nowDatetime.strftime("%Y%m%d_%H%M") + ".txt"
outputTextFile = open(outputTextFilePath,"w")
outputTextFile.write("Culcuration result is " + culcurationResult + "." )
outputTextFile.close()

# 計算結果を記録したテキストファイルを開きます
subprocess.Popen(["start",outputTextFilePath], shell=True)
```

### □手順 6-10: `SikulixIDE`画面上部の[実行]アイコンをクリックします

↓ Excelからのデータの読み込みとテキストファイルへの出力の部分は`Python(Jython)`で[電卓]アプリの操作の部分は`SikuliX`が行っています

![GIF.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/44745/2ae95d53-1af5-fef8-1b17-9c6a8f0fe7f7.gif)

---

以上、管理者権限を持たないWindows端末に「jPortable」とRPAツールである「SikuliX」をインストールして「Python(Jython)」スクリプトでGUI操作の自動化を試みた際の手順でした。