Sikuli - 監視・イベントに関するメソッド一覧

Sikuliでは監視を行うことで、画像が見つかったときや消えたとき、変化したときにイベントを発生させコールバック関数を呼び出すことができます。

監視・イベントに関数するメソッドは下記の通りです。
(PSはPatternオブジェクト、Stringオブジェクトを表します。)

監視・イベントのメソッド一覧

メソッド 説明
onAppear(PS, handler) PSが見つかったときに呼び出すhandlerを設定する。
onVanish(PS, handler) PSが消えたときに呼び出すhandlerを設定する。
onChange(minChangedSize, handler) 領域内の画像がminChangedSize以上変わったときに呼び出すhandlerを設定する。
observe(seconds) 領域内の画像監視をseconds秒行う。監視中、処理は停止する。
observeInBackground(seconds) 上記と同じだが、バックグラウンドで処理を行うため処理は停止しない。
stopObserver() 監視を停止する。
hasObserver() 監視を設定しているかどうか。
isObserver() 監視中かどうか。
hasEvents() 監視のイベントが発生したかどうか。
getEvents() イベントに関するObserveEventオブジェクトを取得する。
getEvent(name) イベントに関する引数に渡された情報を取得する。
setInactive(name) 監視を指定した名称で一時停止する。
setActive(name) 監視を再開する。

【関連記事】
Sikuli - 為替レートの変化を常時監視
Sikuli - イベント処理

Sikuli - 画像マッチングメソッド一覧

Sikuliでは画像マッチングで処理を行うのが基本となります。
そのため画像マッチングに関するメソッドを一通り把握しておくのはとても重要です。

画像マッチングのメソッド一覧は下記の通りです。
(PSはPatternオブジェクト、Stringオブジェクトを表します。)

画像マッチングのメソッド一覧

メソッド 説明
find(PS) 領域内から、最も類似度が高い部分をMatchオブジェクトとして返す。
findAll(PS) 領域内から、合致する全ての部分をMatchオブジェクトのリストとして返す。
wait(PS, seconds) PSが登場するまでseconds秒待つ。
watiVanish(PS, seconds) PSが消えるまでseconds秒待つ。
exists(PS, seconds) 画像が存在するかどうかを調べる。seconds秒待ち、見つからない場合は例外を発生する。
has(PS, seconds) existsと同じだが、見つからないときに例外を発生しない。
findBest(PS, PS, …) 複数の画像マッチ条件を引数に設定し、もっとも類似度が高いものを返す。
findBestList(ListPS) 上記と同じ動作をするが、引数をリストとして渡す。
findAny(PS, PS, …) 複数の画像マッチ条件を引数に設定し、条件を満たすものを全て返す。
findAny(ListPS) 上記と同じ動作をするが、引数をリストとして渡す。
setImageMissingHandler
(function_name)
画像が存在しなかった時に実行するコールバック関数を設定する。
setFindFailedResponse
(ABOART|SKIP|PROMPT|RETRY)
画像が見つからなかった時にどうするかを設定する。
 ABORT:処理を終了する。
 SKIP:処理をスキップする。
 RETRY:リトライする。
 PROMPT:ダイアログボックスを表示しユーザに選択させる。
setFindFailedHandler(function_name) 画像が見つからなかったときに実行するコールバック関数を設定する。
getFindFailedResponse setFindFailedResponseの現在の値を返す。
setThrowException(False|True) 画像が見つからなかった時に例外を発生するかどうかを設定する。

Sikuli - Appクラスのメソッド

SikuliのAppクラスを使うと、アプリケーションの起動やフォーカスの設定、ウィンドウを閉じるなどの操作を行うことができます。

Appクラスの静的メソッド(インスタンスを生成しないで使用できるメソッド)とインスタンスメソッド(インスタンスを作ってから使用できるメソッド)は下記の通りです。

(1) Appクラスの静的メソッド

メソッド 説明
open(appName)
open(appName, waitTime)
appNameで指定されたアプリを起動し、waitTime秒(デフォルトは1秒)待つ。
appNameがすでに起動中のときは、2重起動しないで前面に表示する。
返値として、そのアプリのAppインスタンスを返す。
close(appName) appNameのアプリを閉じる。
正常に閉じられた場合はTrue、失敗したときはFalseを返す。
focus(title)
focus(title, index)
指定したtitleを持つindex番目のアプリを前面に表示し、フォーカスを設定する。
返値として、そのアプリのAppインスタンスを返す。
focusedWindow() フォーカスされているウィンドウのRegionオブジェクトを返す。
openLink(url) urlを開く。
run(cmd) cmdで指定された実行形式ファイルを実行する。
getClipboard() クリップボードに設定されている文字列を取得する。
setClipboard(text) クリップボードにtextを設定する。

(2) Appクラスのインスタンスメソッド

メソッド 説明
open()
open(waitTime)
アプリを開く。
すでに開かれているときは、それを前面に表示しフォーカスを設定する。
close()
close(waitTime)
アプリを閉じる。閉じるまで最大waitTime秒(デフォルト10秒)待つ。
異常終了とされることがあるのでcloseByKeyメソッドを使う方がおすすめ。
closeByKey()
closeByKey(waitTime)
ウィンドウを閉じるためのキーを送信することで、アプリを閉じる。
閉じるまで最大waitTime秒(デフォルト10秒)待つ。
focus() 前面に表示し、フォーカスを設定する。
hasFocus() フォーカスが設定されているかどうかを返す。
window()
window(winNum)
winNum番目(省略したときは先頭)のウィンドウを示すRegionオブジェクトを返す。
isValid() アプリケーションが有効かどうかを返す。
isRunning() 実行中かどうかを返す。
hasWindow() ウィンドウを持っているかどうかを返す。
getWindow() ウィンドウタイトルを得る。
getPID() プロセスIDを得る。
getName() アプリ名を得る。

Sikuli - APPクラスを使って各ブラウザを起動して閉じる

SikuliのAppクラスからインスタンスを作るとフォーカスをあてたり、ウィンドウタイトルを取得できたり、プロセスIDを取得できたり意外と便利です。
ただインスタンスを作るときの引数[アプリケーション名]に何を指定すべきか迷ったのでまとめてみました。

まず起動するときに指定すべきアプリケーション名は「ファイル名を指定して実行」で起動できるものであればいいみたいでした。
各ブラウザーで例えると下記のようになります。

  • Microsoft Edgeの場合 ⇒ microsoft-edge:
  • インターネットエクスプローラの場合 ⇒ iexplore
  • Chromeブラウザの場合 ⇒ chrome
  • Firefoxブラウザの場合 ⇒ Firefox
  • Operaブラウザの場合 ⇒ opera

Appコンストラクタの返値としては、Appインスタンスが返ってきます。
そのインスタンスを使っていろいろ操作できるはずなんですが、Microsoft Edgeだけは操作することができず一旦’Edge’という引数でAppクラスのインスタンスを作り直せば操作できるようになります。

上記5つのブラウザをそれぞれ起動して閉じる操作を行っているソースと動画がありますのでご参照ください。

ソース



今回の検証でAppインスタンスの作り方として分かったことをまとめます。

  • 「ファイル名を指定して実行」で起動できるアプリケーションであればコンストラクタの引数としてOK。
    ただMicosoft Edgeのように起動はできるが、その後Appインスタンスとして操作ができないことがある。
  • 起動しているアプリケーションであれば「タイトルバー」に表示されている一部文字列をコンストラクタの引数として指定すると有効なAppインスタンスすることができる。
    (Microsoft Edgeはこのやり方で、起動後の操作をすることが可能。)
  • exeまでのフルパスを指定してAppインスタンスを作りアプリ起動することも可能だが、返ってきたAppインスタンスを使って操作することはできない。
    (タイトルバーにexeまでのフルパスが表示されていないことが原因のような気もする。)

明確に検証できたわけではありませんが、上記3点を踏まえるとSikuliのAppインスタンスを使った操作をすることがほとんど可能になるので、今回はこれでよしとしたいと思います。

Sikuli - データを変更して複数PDFを出力する

表形式のデータを変更してPDFを出力する処理を行います。

1つや2つのPDFを出力するのであれば、手動でも問題ありませんが出力するPDFがたくさんになるほど、とても退屈なルーチンワークとなります。

この作業をSikuliを使って自動化してみます。
(Excelがインストールされていないので表形式ソフトとしてLibreo Officeを使います。)

今回のSikuliの処理フローは下記の通りです。

 (1) Libreo上のデータを書き換えます。
 (2) メニューからPDF出力を選択します。
 (3) ファイル名を指定してPDF保存を行います。

 (1)から(3)の処理をデータ数分繰り返します。繰り返すデータはSikuliソース上にリスト型(の中に辞書データ)として定義しています。

ソース


下記の動画では、Sikuliで自動的にPDFファイルを3つ出力し、後半は手動で出力したPDFファイルを開いてデータが変わっていることを確認しています。


Sikuli - wordpressに自動投稿

Sikuliを使ってwordpressに自動投稿してみます。

処理はとても簡単で、まずブラウザを起動してwordpressの新規投稿ページに移動します。
(wordpressにはログイン状態になっている状態です。)

新規投稿ページではタイトルと記事を入力して、カテゴリーを選択し投稿(Publish)ボタンを押して投稿完了です。

ちゃんと投稿できているかどうか確認するために最後に投稿を表示しています。

ソース



ログイン処理をせずに単純に記事を投稿するだけだと、とても簡単に実装できました。

これまでにSikuliを使っていくつか実装しましたが、これらを組み合わせれば「FXで自動的に売買を行い、その内容をtwitterやwordpressに自動的に投稿する」といった作業がRPAだけで行えるようになります。

Sikuli - twitterに自動つぶやき

Sikuliを使ってtwitterに自動的でつぶやいてみます。

基本的なメソッドだけを使っていて、次のようなフローで処理しています。

 (1)ブラウザ起動
 (2)ログイン
 (3)つぶやく
 (4)ログアウト
 (5)ブラウザ落とす

下記ソースと動画を参考にして頂ければと思います。

ソース1


ソース2



twitterのAPIを使えば、GUI操作なしでも自動でつぶやくことはできると思いますが、APIキーを取得したりAPIの仕様を確認したりする必要がありますので、全体的な労力を考えるとGUIで操作を自動化する方が楽に実装できるかなと感じます。
APIを用意していないサービスでも自動化可能なので、汎用性も高いかと。。

Sikuli - 為替レートの変化を常時監視

SikuliのOCR機能と状態変化を検知する機能を使って、画面に表示されている為替レートの変化を常時監視してみます。

まずOCRに関しては、Regionクラスのtextメソッドで数字くらいなら簡単に認識してくれます。

画面変化を検知するのは少し難しいのですが、変化検知したときに動作する関数をRegionに設定しておく感じとなります。
今回はhandler1関数を定義し、OCRで取得した数字をエディタに貼り付けてみます。
Regionへのイベントハンドラ追加にはonChangeメソッドを使い、第1引数にはどれだけ変化があったらイベントハンドラを呼び出すかを指定します。今回は10を指定したので10ピクセル以上変化したらイベントハンドラがコールされます。

状態検知を有効にするためにはobserve関数を使うのですが、この関数を使うと処理が止まってしまうので通常はobserveInBackground関数を使いバックグラウンドで状態検知を有効にします。

また、処理を終了するときにはstopObserver関数を使い、状態検知を無効にします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# coding:utf-8
def handler1(event):
app.focus()
paste(r.text() + ' ')

# 変化値を貼り付けるエディタ
app = App('MKEditor')

# ユーザに監視するエリアを指定させる
r = selectRegion()

r.onChange(10, handler1)
r.observeInBackground(FOREVER)

wait(90)

r.stopObserver()
print('finished!')

この処理の動きは下記の動画で確認していますので、参考にして頂ければ幸いです。



OCRと状態変化検知を使うと、投資対象の為替レートを常時監視ができるようになり、例えば一定時間にある程度上昇したらその上昇に合わせて順張り投資するといったことが可能になります。

パラダイムシフトの時のような急激な一方方向へのトレンドがある場合は、順張り+建玉追加投資できるとかなりの利益を上げることができますが、そんなトレンドを人が張り付いて確認し続けるのは大変なので今回実装したようなRPAでの処理をうまく活用したいものです。

Sikuli - FX(デモ版)の注文を自動化

Sikuliを使ってFXの自動売買を行う処理を実装してみました。
ソースと実際の動きを動画にしましたのでよかったら参考にして下さい。
(ソース上のログインユーザ名やパスワードはさすがに隠してます。)

ソースの内容としては、waitやclick,paste,typeといった基本的なメソッドしか使っていませんがこのくらいのGUI操作なら十分自動化できます。
ただもっとエラー処理など気を付けて実装する必要があると思いますが。。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# Operaブラウザを起動
app = App(r'C:\xxxxx\xxxxx\Opera\launcher.exe')
app.open()

# Operaの起動を待って、ログインページに移動
wait("1580206648525.png")
paste('https://demotrade.fx.dmm.com/fxcmdipresen/webrich/direct/login')
wait(0.1)
type(Key.ENTER)

# ログインページのロードを待ってログイン
wait("1580206818170.png",20)
click(Pattern("1580206853211.png").targetOffset(-97,123))
wait(0.1)
paste('[ユーザ名]')
wait(0.1)
type(Key.TAB)
wait(0.1)
paste('[パスワード]')
wait(0.1)
type(Key.TAB)
wait(0.1)
type(Key.ENTER)

# DMMサイトのロードを待って自動注文
wait("1580207030297.png", 20)
click(Pattern("1580213297947.png").targetOffset(89,41))
click("1580207967756.png")
click("1580213354520.png")

# ログアウト
click("1580213395792.png")
click(Pattern("1580213422219.png").exact())

# Opera閉じる
click(Pattern("1580214355504.png").targetOffset(21,-18))

popup(u'終了しました。')

ソース内で参照している画像



最初の実装サンプルではこのくらいでもいいかと思いますが、レートが大きく動いているときに順張りするとか、AIで状況を判断して売買するなどいろいろ作りこんでいくと夢のあるシステムができると思います。

Sikuli - 起動しているInternet Exploreを全て終了する方法

起動しているIEを全て終了する必要があったので実装してみました。

まずAppクラスにIEのウィンドウタイトルを設定しAppインスタンスを作成します。
(ウィンドウタイトルは一部が合致していればAppインスタンスを作成してくれるようです。)

そして生成したAppインスタンスのisRunningメソッドをコールしてIEが起動しているかどうかをチェックします。

IEが起動している場合は、closeByKeyメソッドで順次IEを終了させる・・・・といった感じで簡単に実装できるはずでした。。。

1
2
3
4
5
6
7
# coding:utf-8
chkApp = App(u"Internet")
while chkApp.isRunning():
chkApp.focus()
#chkApp.closeByKey() # 終了しないことがある
#chkApp.close() # 次回のIE起動時にクラッシュしたと表示される
type('w', Key.CTRL) # 比較的平和に全て終了する

ここからいろいろ問題が発生します。

まずcloseByKeyメソッドだとIEが終了せず無限ループになることが分かりました。原因は分からなかったのですが、IEが複数ウィンドウ起動していると1つめのウィンドウが落ちてその次のウィンドウが落ちないという現象です。

仕方ないのでcloseメソッドを使うことにしました。この方法ですと問題なく全てのIEウィンドウが閉じるのですが、次回IEを起動したときに「前回のブラウズセッションは予期せずに終了しました」と表示されてしまいます。

最終的には[CTRL + w]というショートカットキーを使ってIEを終了することにしました。
この方法であればIEのウィンドウは問題なく全て閉じますし、気持ち悪いメッセージが表示されることもありません。めでたし、めでたし。