LoginSignup
6
1

【Python】`pywinauto`の"Simple Example"は日本語環境だと動かない

Posted at

はじめに

PythonのRPA用ライブラリ、pywinautoは非常に便利なライブラリであり、WindowsのGUI操作に強力な機能があります。

しかし、そのドキュメントは日本語で十分に充実しているとは言えず、GitHubのREADME.mdにある"Simple Example"は日本語環境では動きません。
これがなぜ動かないかをエラーメッセージやソースコードから見抜くのは非常に困難なので、技術選定の段階で挫折しているプロジェクトが多いのではと考えています。
この記事では、「とりあえず"Simple Example"と同等物を動かせるようにする」ことを目標に解説していきます。

"Simple Example"実行時のエラー

"Simple Example"のコードは、下記のようにシンプルです。

from pywinauto.application import Application
app = Application().start("notepad.exe")

app.UntitledNotepad.menu_select("Help->About Notepad")
app.AboutNotepad.OK.click()
app.UntitledNotepad.Edit.type_keys("pywinauto Works!", with_spaces = True)

仕様がわからなくても、クラス名や関数名、プロパティ名から、なんとなく「メモ帳を起動して、情報ウィンドウを開いて、OKを押下して閉じて、"pywinauto Works!"と入力するものだ」ということが把握できるかと思います。

しかし、これを実行すると、下記のようなエラーとなります。

Traceback (most recent call last):
  ...
  File "...\pywinauto\controls\hwndwrapper.py", line 1084, in menu_select
    self.menu_item(path, exact=exact).select()
  File "...\pywinauto\controls\hwndwrapper.py", line 1028, in menu_item
    return self.menu().get_menu_path(path, appdata = menu_appdata, exact=exact)[-1]
  File "...\pywinauto\controls\menuwrapper.py", line 110, in check
    return method(instance, *args, **kwargs)
  File "...\pywinauto\controls\menuwrapper.py", line 569, in get_menu_path
    best_item = findbestmatch.find_best_match(
  File "C:\Users\komoj\pywinauto\pywinauto\findbestmatch.py", line 133, in find_best_match
    raise MatchError(items = text_item_map.keys(), tofind = search_text)
pywinauto.findbestmatch.MatchError: Could not find 'Help' in 'dict_keys(['ファイル(&F)', '編集(&E)', '書式(&O)', '表示(&V)', 'ヘルプ(&H)'])'

メッセージから「どうやら操作対象画面要素をマッピングしている辞書のキーに"Help"がない」からエラーになっていることがわかりますが、ここからどうやってエラーを解決すべきかは、これから開発しようとしているプロジェクト/プロダクトにpywinautoを使うべきかという技術選定段階ではなかなか見つけられないでしょうし、事実、メソッドの実装はかなり複雑な呼び出し経路をたどっています。

日本語環境で動くコード

動作環境を考慮しつつ、"Simple Example"を日本語環境で動くコードにするとこうなります。

from pywinauto.application import Application
app = Application().start("notepad.exe")

app.UntitledNotepad.menu_select("ヘルプ->バージョン情報")
app.バージョン情報.OK.click()
app.UntitledNotepad.Edit.type_keys("pywinauto Works!", with_spaces=True)
  1. menu_select("Help->About Notepad") -> menu_select("ヘルプ->バージョン情報")
    これは比較的わかりやすいですが、表示されているメニュー画面の通りに指定する文字列を直しただけです。
    menu_selectは、"->"で渡された文字列を分割して、各文字列で指定されたメニューアイテムを押下し続けていくメソッドです。日本語で指定されたことにより日本語環境メモ帳の「バージョン情報」ウィンドウを開くことができます。
  2. app.AboutNotepad.OK.click() -> app.バージョン情報.OK.click()
    日本語で属性の指定を行っている、少し奇妙なコードとなります。これはApplicationには__getattr____getattribute__が実装されており、動的な属性アクセスを行うためです。
    Applicationは指定された属性と同名(.- など、Pythonの文法的に変数名やメソッド名に指定できない文字がリプレースされることが考慮されつつ)の画面要素を取得します。なので"Simple Example"にある英語環境と同じ属性参照が使えず、日本語の属性を参照する必要があります。

展望

現在、実行環境の言語に関する言及をREADMEに導入することを、discussionsで提案しています。

これが受け入れられれば、「しょっぱなサンプルコードが動かない!」で導入をあきらめるプロジェクトが減って、pywinautoコミュニティが活性化するのではと期待しています。

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1