1.pywinautoの紹介
pywinautoの公式ドキュメントリンクは次のとおりです。
https://pywinauto.readthedocs.io/en/latest/
https://www.kancloud.cn/gnefnuy/pywinauto_doc
- ダイアログ は、ボタン、編集ボックスなど、他のいくつかのGUI要素/コントロールを含むウィンドウです。ダイアログは必ずしもメインウィンドウではありません。メインフォームの上部にあるメッセージボックスもダイアログボックスです。メインウィンドウは、pywinautoではダイアログボックスと見なされます。
- コントロールは、階層の任意のレベルにあるGUI要素です。定義には、ウィンドウ、ボタン、編集ボックス、テーブル、テーブルセル、ツールバーなどが含まれます。
- Win32 APIテクノロジー(pywinautoの「win32」バックエンド)は、各コントロールの識別子を提供します。これは、handleと呼ばれる一意の整数です。
- UI Automation API(pywinautoの「uia」バックエンド)は、すべてのGUI要素にウィンドウハンドルを提供するとは限りません。「win32」バックエンドにはそのような要素はありません。ただし、
Inspect.exe
属性NativeWindowHandle
が使用可能な場合は表示できます。
2.アクセステクノロジーの選択
アプリケーションを操作するには、pywinautoが最初にアプリケーションにアクセスする必要があります。2つの主要なアクセステクノロジーがあります。WIN32アクセステクノロジーは、MFC、VB6、VCL、および単純なWinFormsコントロールによって開発されたアプリケーションをサポートします。MSUIAutomationアクセステクノロジーは、WinForms、WPS、QT5、WPF、ストアアプリ、ブラウザーなどによって開発されたアプリケーションをサポートします。
アプリケーションソフトウェアが使用できるアクセステクノロジを分析するために、次の一般的なツールがあります。
1. WIN32APIに使用されるSPY ++。SPY ++がすべてのコントロールを表示できる場合、アクセステクノロジは「win32」を選択する必要があります
2. Inspect.exe:Inspect.exeのモードがUIAモードに設定されている場合、SPY ++よりも多くのコントロールを表示できるため、アクセステクノロジは「uia」を選択する必要があります。
3. py_inspect:win32とuiaの2つのアクセス技術をサポートし、SWAPYの代替手段です。
https://github.com/pywinauto/py_inspect
4. UISPY:uiaアクセステクノロジーをサポートします
5. SWAPY:win32アクセステクノロジーのみをサポートします。https://github.com/pywinauto/SWAPY
次の図は、py_inspectで表示されたsecureCRTコントロールです。uia形式を選択すると、より多くのコントロールが表示されるため、アクセステクノロジは「uia」を選択する必要があります。
その他の一般的に使用される
三、アクセス申請方法
アプリケーションを開くか、既存のアプリケーションインスタンスに接続できます。すべてはApplicationオブジェクトを介して行われます。これはsubprocess.Popenのクローンではなく、アプリケーション自動化のためのアクセスポイントです。これは主に、自動制御プロセスの範囲を制限するためのものです。プログラムに複数のインスタンスがある場合、1つのインスタンスが自動的に制御され、他のインスタンス(プロセス)は影響を受けません。この種のエントリポイントApplication()とDesktop()を確立できるオブジェクトには主に2つのタイプがあります。アプリケーションの範囲は、一般的なデスクトップアプリケーションなどのプロセスです。デスクトップの範囲はプロセスにまたがることができます。これは主に、win10の計算機のような複数のプロセスを含むプログラムに使用されます。これは現在比較的まれです。
1.アプリケーションオブジェクト
1.1、アプリケーションを開く
connect(self, **kwargs) # instance method:
タイムアウトパラメータはオプションであり、アプリケーションの起動に時間がかかる場合にのみ使用する必要があります。
from pywinauto.application import Application
app = Application(backend="uia").start('notepad.exe')
# describe the window inside Notepad.exe process
dlg_spec = app.UntitledNotepad
# wait till the window is really open
actionable_dlg = dlg_spec.wait('visible')
1.2、アプリケーションを接続します
connect(self, **kwargs) # instance method:
connect()
自動化されたアプリケーションを開始するときに使用されます。すでに実行されているアプリケーションを指定するには、次のいずれかを指定する必要があります。
プロセス:アプリケーションのプロセスID、たとえば、app = Application()。connect(process = 2341)
ハンドル:アプリケーションウィンドウのウィンドウハンドル、たとえば、app = Application()。connect(handle = 0x010f0c)
パス:プロセスの実行可能ファイルのパス(GetModuleFileNameExは、各プロセスのパスを見つけて、渡された値と比較するために使用されます)。例:app = Application()。connect(path = r "c:\ windows \ system32 \ notepad.exe")
または、指定されたウィンドウのパラメーターの任意の組み合わせで、これらはすべてpywinauto.findwindows.find_elements()
関数に渡されます。例えば
app = Application()。connect(title_re = "。* Notepad"、class_name = "Notepad")
2.デスクトップオブジェクト
from subprocess import Popen
from pywinauto import Desktop
Popen('calc.exe', shell=True)
dlg = Desktop(backend="uia").Calculator
dlg.wait('visible')
4、アクセスウィンドウ方式
これは、高度なpywinautoAPIのコアコンセプトです。ウィンドウまたはコントロールは、まだ存在していないか閉じられている場合でも、おおよそまたはより詳細に説明できます。ウィンドウ仕様には、実際のウィンドウまたはコントロールを取得するために使用されるマッチング/検索アルゴリズムに関する情報も保持されます。
詳細なウィンドウ仕様は次のとおりです。
>>> dlg_spec = app.window(title='Untitled - Notepad')
>>> dlg_spec
<pywinauto.application.WindowSpecification object at 0x0568B790>
>>> dlg_spec.wrapper_object()
<pywinauto.controls.win32_controls.DialogWrapper object at 0x05639B70>
実際のウィンドウ検索は、このwrapper_object()
メソッドによって実行されます。実際の既存のウィンドウ/コントロールのラッパーまたはトリガーを返しますElementNotFoundError
。このラッパーは、アクションを送信したりデータを取得したりすることで、ウィンドウ/コントロールを処理できます。
ただし、Pythonはこのwrapper_object()
呼び出しを非表示にできるため、プログラムにさらにコンパクトなコードを含めることができます。以下の説明はまったく同じです。
dlg_spec.wrapper_object().minimize() # while debugging
dlg_spec.minimize() # in production
ウィンドウ仕様を作成するための多くの可能な標準があります。以下はほんの一例です。pywinauto.findwindows.find_elements()
可能な基準のリストは、関数にあります。
# 可以是多层次的
app.window(title_re='.* - Notepad$').window(class_name='Edit')
# 可以结合标准
dlg = Desktop(backend="uia").Calculator
dlg.window(auto_id='num8Button', control_type='Button')
1.通过窗体名确定窗体
dlg = app.Notepad
dlg = app ['Notepad']
2、top_window()
これにより、アプリケーションの最上位ウィンドウのZ次数が最も高いウィンドウが返されます。
3.(a)のようにマルチレベルの説明でウィンドウを指定するか、(b)のようにパラメーターの組み合わせを使用してウィンドウを指定すると、次の2つのステートメントで同じウィンドウが決定されます。
dlg = app.window(title_re="Page Setup").window(class_name="#32770")
dlg = app.window(title_re="Page Setup", class_name="#32770")
4.findwindowsを介して
pywinauto.findwindows.find_windows()
pywinauto.findwindows.find_elements()は、実行中のすべてのプログラムのwin32_element_info.HwndElementInfoを返します。
5、dialogs = app.windows()
これにより、アプリケーションの表示され、有効になっているすべてのトップレベルウィンドウのリストが返されます。次に、handleprops
モジュール内のいくつかのメソッドを使用して、目的のダイアログボックスを選択できます。必要なハンドルを取得したら、次を使用できます
app.window(handle=win)
注:ダイアログのタイトルが非常に長い場合、入力された属性アクセスが非常に長くなる可能性があります。その場合、通常は使いやすくなります。
app.window(title_re=".*Part of Title.*")
5、アクセス制御
1.属性分析の魔法
Pythonは、オブジェクト属性を動的に解析することにより、ウィンドウ作成の仕様を簡素化します。ただし、属性名には、他の変数名と同じ制限があります。スペース、コンマ、またはその他の特別な記号は使用できません。しかし幸いなことに、pywinautoは「ベストマッチ」アルゴリズムを使用してスペルミスや小さな変更を見つけます。
app.UntitledNotepad # 相当于 app.window(best_match='UntitledNotepad')
辞書のようなアイテムからアクセスするには、Unicode文字と特殊記号を使用できます。
app['Untitled - Notepad'] # 是相同的 app.window(best_match='Untitled - Notepad')
2.魔法の属性の名前を知る方法
「ベストマッチ」をコントロールにアタッチする方法には、いくつかの原則があります。ウィンドウの指定がいずれかの名前に近い場合、名前の一致は成功します。
- タイトル別(ウィンドウテキスト、名前):
app.Properties.OK.click()
- タイトルとコントロールタイプ別:
app.Properties.OKButton.click()
- コントロールタイプと番号によって:
app.Properties.Button3.click()
(注:Button0とボタン1が同じボタンに一致する、ボタン2は、次のもの、等です) - 左上隅のラベルとコントロールタイプを押します。
app.OpenDialog.FileNameEdit.set_text("")
- コントロールタイプとアイテムテキスト別:
app.Properties.TabControlSharing.select("General")
通常、これらの一致する名前のすべてを同時に使用できるわけではありません。指定されたダイアログボックスのこれらの名前をチェックするには、print_control_identifiers()
メソッドを使用できます。可能な「best_match」名は、ツリー内の各コントロールのPythonリストとして表示されます。メソッド出力から、より詳細なウィンドウ仕様をコピーすることもできます。たとえば app.Properties.child_window(title="Contains:", auto_id="13087", control_type="Edit")
。
3.ダイアログボックスでコントロールを指定する方法
コントロールを指定する方法はたくさんありますが、最も簡単な方法は
app.dlg.control app['dlg']['control']
2つ目は、英語以外のオペレーティングシステムに適しています。たとえば、ユニコード文字列を渡す必要があります。 app [u'对话框标题'] [u'控件标题']
このコードは、以下に基づいて、コントロールごとに複数の識別子を作成します。
- 題名
- フレンドリーなクラス
- タイトル+フレンドリークラス
コントロールのタイトルテキストが空の場合(char以外の文字を削除した後)、このテキストは使用されません。代わりに、コントロールの右上にある最も近いタイトルテキストを探します。そして、フレンドリーなクラスを追加します。したがって、リストは次のようになります
- フレンドリーなクラス
- 最も近いテキスト+フレンドリーなクラス
ダイアログ内のすべてのコントロールに対して一連の識別子が作成されたら、それらを明確にします。
WindowSpecification.print_control_identifiers()メソッドを使用します
この方法で印刷された識別子は、識別子を一意にするプロセスを経ていることに注意してください。したがって、編集ボックスが2つある場合は、それらの識別子に「編集」が表示されます。実際には、最初のものは「編集」、「編集0」、「編集1」と呼ぶことができ、2番目のものは「編集2」と呼ぶ必要があります
6、操作制御
https://pywinauto.readthedocs.io/en/latest/code/code.html#controls-reference
具体的な操作方法は、公式紹介を参考に、2点注意してください。
1.同じコントロールの場合、win32で検出されたアクセスパスは、uiaでクエリされたアクセスパスとは異なります。
2.同じコントロールの場合、win32アクセスに使用できる方法は、uiaアクセスに使用できる方法とは異なります。
セブン、その他
1.英語以外のアプリケーション言語でpywinautoを使用する方法
Pythonはコード内のユニコード識別子をサポートしていないため、属性アクセスを使用してコントロールを参照することはできません。したがって、アイテムアクセスを使用するかwindow()
、明示的に呼び出す必要があります。
だから書いてはいけない
app.dialog_ident.control_ident.click()
あなたは書く必要があります
app ['dialog_ident'] ['control_ident']。click()
または明示的に使用するwindow()
app.window(title_re="非Ascii字符").window(title="非Ascii字符").click()
2.期待どおりに応答しないコントロール(OwnerDrawコントロールなど)の処理方法
一部のコントロール(特にOwnerdrawnコントロール)は、期待どおりにイベントに応答しません。たとえば、HLPファイルを表示して[インデックス]タブに移動すると([検索]ボタンをクリック)、リストボックスが表示されます。ここでSpyまたはWinspectorを実行すると、それが実際にリストボックスであることが示されますが、ownerdrawnです。これは、開発者がWindowsに、プロジェクトの表示方法を上書きして自分で行うことを指示することを意味します。この場合、文字列を取得できなくなりました:-(。
どうしたの?
app.HelpTopics.ListBox.texts() # 1 app.HelpTopics.ListBox.select("ItemInList") # 2
- 文字列の空のリストを返します。これはすべて、pywinautoがリストボックス内の文字列を取得できないことを意味します。
- ListBoxのselect(string)メソッドはテキスト内のアイテムを検索して、選択する必要のあるアイテムのインデックスを認識しているため、これはIndexErrorで失敗します。
次の解決策がこのコントロールに適用されます
app.HelpTopics.ListBox.select(1)
これは文字列検索ではないため、リストボックスの2番目の項目を選択します。これは正常に機能します。
残念ながら、これでも役に立ちません。開発者は、コントロールをSelectなどの標準イベントに応答しないようにすることができます。この場合、リストボックスで項目を選択できる唯一の方法は、TypeKeys()のキーボードエミュレーションを使用することです。
これにより、任意のキーストロークをコントロールに送信できます。だからあなたが使いたい3番目のアイテムを選んでください
app.Helptopics.ListBox1.type_keys("{HOME}{DOWN 2}{ENTER}")
{HOME}
最初の項目が強調表示されていることを確認します。{DOWN 2}
次に、2つの項目が強調表示されます{ENTER}
ハイライトされたアイテムが選択されます
アプリケーションが同様のコントロールタイプを広範囲に使用している場合は、特定のアプリケーションに関する追加の知識を使用できるListBoxから新しいクラスを派生させることで、より簡単に使用できます。たとえば、WinHelpの例では、リストビューでアイテムが強調表示されるたびに、そのテキストがリストの上のEditコントロールに挿入され、そこからアイテムのテキストを取得できます。次に例を示します。
# 打印列表框中当前所选项目的文本 # (只要你没有输入编辑控件!) print app.HelpTopics.Edit.texts()[1]