1. 説明
pywinauto は、Windows システム ソフトウェア (GUI) に適した自動化用の Python モジュールです。Pywinauto を介してウィンドウ (ダイアログ ボックス) とウィンドウ内のコントロールを移動でき、マウスとキーボードの入力も制御できるため、これまで以上のことができます。 pysimplegui の前に導入されましたさらに表示
2.インストール
通常、インストールには pip を使用します
pip install pywinauto
公式 Web サイトのドキュメント: https://pywinauto.readthedocs.io/en/latest/
3.申請
ソフトウェアを制御したい最初のことは、Windows ソフトウェアを起動することです。各ソフトウェア (プロセス) は Application オブジェクトです。
Application オブジェクトをインスタンス化するときに、バックエンド パラメーターを渡すことができます。オプションの値は ですwin32(默认)和 uia
。
win32 用のフレームワーク: MFC、VB6、VCL、シンプルな WinForms コントロール、およびほとんどの古いレガシー アプリケーション
uia 用のフレームワーク: WinForms、WPF、ストア アプリ、Qt5、ブラウザー フレームワークには 2 種類あり、使用するものと表示する
ものがあります。どちらかを選択できます。 1 つはより包括的なものです。Inspect と Spy++ は自分でインストールする必要がありますInspect(对应uia)
Spy++(对应win32)
Application オブジェクトの主なメソッドは次のとおりです。
方法 | 共通パラメータ | 説明する |
---|---|---|
始める() | cmd_line、timeout、retry_interval | cmdコマンドでソフトウェア(プロセス)を起動する |
接続する() | プロセス、ハンドル、パス、タイムアウト | プロセスに接続するには、通常、プロセス番号を使用します (タスク マネージャーで確認できます)。 |
ウインドウ上部() | / | アプリケーションのトップレベルウィンドウを取得する |
窓() | title、title_re、class_name、best_match | 単一のウィンドウを取得する (WindowSpecific) |
ウィンドウズ() | タイトル、タイトルレ、クラス名 | 複数のウィンドウを取得する (UIAWrapper) |
は64ビット() | / | 64ビットアプリケーションかどうか |
CPU使用率 | 間隔 | CPU使用率 |
wait_cpu_usage_ lower() | しきい値、タイムアウト | CPU 使用率が特定のしきい値を下回るのを待機します |
アクティブ()() | / | 検索するとアクティブなウィンドウが返されます |
殺す() | 柔らかい | 最終過程 |
wait_for_process_exit() | タイムアウト、再試行間隔 | プロセスが終了するまで待ちます |
たとえば、WeChat アプリケーションを起動し、プロセス番号を介して接続します。プロセス番号はタスク マネージャーに详细信息
表示される PIDです。
from pywinauto import Application
app = Application(backend="uia")
# app.start(r"D:\Program Files (x86)\Tencent\WeChat\WeChat.exe")
app.connect(process=6556)
print("is64bit:", app.is64bit())
print("cpu_usage:", app.cpu_usage())
app.wait_cpu_usage_lower()
# app.active() # 如果指定时间内不激活则报错
print("kill:", app.kill())
print("wait_for_process_exit:", app.wait_for_process_exit())
4.窓の仕様
ウィンドウを取得したいと考えています。ウィンドウは、WindowSpecification
Application オブジェクトの window() メソッドを通じて取得できるオブジェクトです。パラメータには、title、classname、または best_match などを指定できます。これらは、inspect.exe で確認できます。ただし、表示される名前は実際には window() の title パラメータに対応していることに注意することが重要です。
WindowSpecific オブジェクトの一般的に使用されるメソッドは次のとおりです。
方法 | 共通パラメータ | 説明する |
---|---|---|
最大化() | / | ウィンドウを最大化する |
最小化() | / | ウィンドウを最小化する |
復元する() | / | 回復期間 |
近い() | / | 窓を閉めて |
get_show_state() | / | ウィンドウのステータスを取得します。0 通常、1 最大化、2 最小化 |
was_maximized() | / | 現在最大化されていますか |
描画アウトライン() | 色、厚さ | 位置決めのためにウィンドウの周囲に枠を描画します |
print_control_identifiers() | / | すべての子ウィンドウと子要素を出力します (対応する control_type が出力されます)。 |
子ウィンドウ() | タイトル、コントロールタイプ | 子ウィンドウを取得する |
存在します() | タイムアウト | 窓は存在しますか |
待って() | wait_for、タイムアウト | ウィンドウが特定の状態 (存在、表示、有効、準備完了、アクティブ) になるまで待ちます。 |
wait_not() | 待機しない、タイムアウト | ウィンドウが特定の状態 (存在、表示、有効、準備完了、アクティブ) にならないまで待ちます。 |
栗をあげる
dlg = app.window(class_name="WeChatMainWndForPC")
# dlg = app.window(title="微信")
print("get_show_state:", dlg.get_show_state())
print("was_maximized:", dlg.was_maximized())
dlg.print_control_identifiers()
dlg.draw_outline()
dlg.maximize()
dlg.restore()
dlg.minimize()
dlg.close()
5. 要素コントロール
一般にウィンドウ内には、ボタン(Button)、編集バー(Edit)、ツリービュー(Tree View)、チェックボックス(CheckBox)、ダイアログボックス(Dialog)、ツールバー(Toolbar)、ステータスバー(StatusBar)などのさまざまな要素があります。 )、リスト ボックス (ListBox)、ペイン (Pane)、メニュー (Menu)、メニュー バー (MenuItem)、静的コンテンツ (Static)、ツール ヒント (ToolTips)、リスト コントロール (ListView)、RadioButton、ComboBox、TabControl、GroupBox、ポップアップメニュー、ヘッダーなど
コントロールの種類が多すぎて 1 つずつ学習することはできませんが、それらはすべて、アクセス後にelement_info
継承されたオブジェクト (UIAElementInfo または HwndElementInfo) を返すプロパティを持っていますElementInfo
。より重要なプロパティまたはメソッドは次のとおりです。
メソッドまたはプロパティ | 共通パラメータ | 説明する |
---|---|---|
名前 | / | 要素の実際の名前 (通常はタイトル) |
見える | / | 要素が表示されるかどうか |
リッチテキスト | / | 要素の完全な名前 |
矩形 | / | 要素の位置、幅、高さを返します。 |
クラス名 | / | クラス名 |
有効 | / | 要素が利用可能かどうか |
親 | / | 親要素を返す |
子供たち() | title、title_re、class_name、best_match | 要件を満たす子要素(リスト)を返します。 |
iter_children() | title、title_re、class_name、best_match | 適格な子要素を反復処理する (ジェネレーター) |
一部の要素の主な情報を取得するだけでなくelement_info
、これらの要素も Wrapper にパッケージ化されているため、BaseWrapper
共通のメソッドと属性を学ぶこともできます。実際BaseWrapper
、これらのメソッドは基本的にElementInfo
さらにパッケージ化するためのものであり、次の表に示すように、いくつかのメソッドのみをリストします。
メソッドまたはプロパティ | 共通パラメータ | 説明する |
---|---|---|
要素情報 | / | 返回当前元素的ElementInfo对象 |
from_point() | x、y | 通过坐标查找ElementInfo |
class_name() | / | 类名,实际是调用element_info.class_name |
friendly_class_name() | / | 友好的类名,同上 |
window_text() | / | 元素的文本,实际是调用element_info.rich_text |
is_visible() | / | 元素是否可见,实际是调用element_info.visible |
is_enabled() | / | 元素是否可用,实际是调用element_info.enabled |
rectangle() | / | 元素的位置和宽高,实际是调用element_info.rectangle |
process_id() | / | 进程号,实际是调用element_info.process_id |
draw_outline() | colour、thickness | 给当前元素画个框 |
click_input() | button、coords、double | 鼠标操作,实际是调用mouse模块的_perform_click_input() |
type_keys() | / | 键盘操作,实际是调用keyboard模块的send_keys() |
dlg = app.window(class_name="WeChatMainWndForPC")
list_data = dlg.child_window(title="会话", control_type="List")
for item in list_data:
print(type(item))
element_info = item.element_info
print(type(element_info))
print("window_text:", )
print("rich_text:", element_info.rich_text)
print("name:", element_info.name)
print("visible:", element_info.visible)
print("rectangle:", element_info.rectangle)
print("class_name:", element_info.class_name)
print("enabled:", element_info.enabled)
print("parent:", element_info.parent)
print("children:", element_info.children())
print("iter_children:", element_info.iter_children())
if item.window_text() == "文件传输助手":
item.click_input()
item.type_keys("冰冷的希望")
item.type_keys("{VK_RETURN}")
print()
说明一下,每个控件元素都有对应的Wrapper,所以上面的方法也不一定都用,需要根据实际情况进行测试区分。另外,比较有用的click_input()
和type_keys()
这两个方法分别用于操作鼠标和键盘(输入),下面我会单独拿出来说一下
6.鼠标操作
鼠标点击肯定离不开点击的位置,桌面就是一个坐标,左上角为坐标原点,往右是X轴正向,往下是Y轴正向。pywinauto提供了一个mouse模块用于鼠标操作,最核心的方法是_perform_click_input()
,不过它是一个私有方法,我们调用的是基于它的封装方法,如下表
方法 | 参数 | |
---|---|---|
click() | button、coords | 单击鼠标某个键 |
double_click() | button、coords | 双击鼠标某个键 |
right_click() | coords | 单击鼠标右键 |
move() | coords | 移动鼠标 |
press() | button、coords | 按下鼠标 |
release() | button、coords | 放开鼠标 |
scroll() | coords、wheel_dist | 滚动鼠标滚轮 |
wheel_click() | coords | 单击鼠标滚轮 |
参数说明:
参数button
的默认值都是“left”,即鼠标左键,可选值有left、right、middle、move、wheel、x
参数coords
的默认值都是元组(0, 0),元组里的两个整数分别是X、Y轴的值
参数wheel_dist
表示滚动的距离,大于0是向上滚动,小于0是向下滑动
举个栗子
from pywinauto import Application, mouse
app = Application(backend="uia")
app.connect(process=4352)
dlg = app.window(class_name="WeChatMainWndForPC")
list_data = dlg.child_window(title="会话", control_type="List")
for item in list_data:
if item.window_text() == "文件传输助手":
# item.click_input()
rectangle = item.element_info.rectangle
x = int((rectangle.left + rectangle.right) / 2)
y = int((rectangle.top + rectangle.bottom) / 2)
mouse.click(button='left', coords=(x, y))
time.sleep(1)
mouse.click("right", (x, y))
time.sleep(1)
mouse.move((x - 50, y)) # 往左边移动50个像素
time.sleep(1)
mouse.click(coords=(x, y))
break
7.键盘操作
键盘操作主要是按下键盘上的按键,相关方法在keyboard模块,最最主要的是send_keys()
方法,第一个参数keys
就是我们需要按下的按键,其他参数比如说with_spaces、with_tabs、with_newlines、turn_off_numlock、set_foreground、vk_packet,一看就知道作用,而且都是布尔值,此处不进行举例
pywinauto支持的完整的按键可以在官方文档查看,https://pywinauto.readthedocs.io/en/latest/code/pywinauto.keyboard.html
下面我列举出的是一些比较常用的按键
按键 | 符号 | 说明 |
---|---|---|
Shift | VK_SHIFT | 上档键 |
Ctrl | VK_CONTROL、VK_LCONTROL、VK_RCONTROL | Ctrl键、左右Ctrl键 |
Alt | VK_MENU | Alt键 |
Windows | VK_LWIN、VK_RWIN | 左右win键 |
Space | VK_SPACE | 空格键 |
backspace | BACKSPACE | 退格键 |
enter | ENTER | 回车键 |
esc | ESC | 退出键 |
table | VK_TAB | 制表键 |
left、right、up、down | VK_LEFT、VK_RIGHT、VK_UP、VK_DOWN | 上下左右方向键 |
f1~f24 | VK_F1、VK_F2…VK_F24 | f1~f24 |
キャップスロック | キャップスロック | 大文字キー |
手順:
1. ボタンを使用する場合は中かっこが必要です。たとえば、Enter キーを押すと '{ENTER}' (是字符串)
2. Windows プラットフォームでは、デフォルトで仮想ボタンが送信され、VK_
で始まるボタンはすべて仮想ボタンです。VK_
プレフィックスを削除してvk_packet
パラメータを変更してください。 send_keys() のFalse
宛先
単一のボタンを押したり離したりするだけでは十分ではありません。多くの場合、キーの組み合わせが必要です。このとき、修飾子が必要です。中かっこで使用して、ボタンを押したり離したりするタイミングを制御できます。数字を追加するdown
とup
、その後に、押された回数が表示されます。
list_data = dlg.child_window(title="会话", control_type="List")
for item in list_data:
if item.window_text() == "文件传输助手":
item.click_input()
# item.type_keys("冰冷的希望")
send_keys(" ") # 随便输入字符串
send_keys("{VK_CONTROL down} a {VK_CONTROL up}") # 快捷键Ctrl+a(先按下Ctrl,再按下a,最后放开Ctrl)
send_keys("{BACKSPACE}") # 按下退格键删除文本
send_keys("{. 6}") # 按6次小数点
send_keys("冰冷的希望{ENTER}") # 输入文本,按下回车键
もちろん、多くの場合、使用down
と変更は十分に簡潔ではないため、 pywinauto は、「代わりに使用」 、「代わりに使用」 、「代わりに使用」up
という簡略化された書き方も提供します。+
{VK_SHIFT}
^
{VK_CONTROL}
%
{VK_MENU}
send_keys('^a^c') # 按下Ctrl+a之后再按下Ctrl+c,即全选复制
send_keys('+{INS}') # 按下Shift+Ins键
send_keys('%{F4}') # 按下Alt+F4键
ボタンを押さずに単純な文字列を入力したい場合は、エスケープを解除する必要があります。修飾子とボタンの書き方が異なることに注意してください。
send_keys('{^}a{^}c{%}') # 输入字符串"^a^c%"而不是当成快捷键
send_keys('{
{}ENTER{}}') # 输入字符串"{ENTER}"而不是按下回车键