這兩天開始接觸pywinauto,聽說百度的自動化QA也用這個模塊,於是來了興趣,但網上的教程很少,而且基本上都是拿官方的notepad來說,首先中文菜單的支持是問題,其次各種操作也沒有寫清楚,閱讀官方的文檔,發現這個東西使用起來還真是非常方便,下面我也以notepad為例來說明一下它的簡單操作。
安裝
1. pywinauto https://sourceforge.net/project/showfiles.php?group_id=157379
2. Sendkeys http://www.rutherfurd.net/python/sendkeys/index.html
3.ctypes (如果你是python2.3或者2.4)
檢測你是否安裝正確
>>> from pywinauto import application >>> app = application.Application.start("notepad.exe") >>> app.notepad.TypeKeys("%FX")
都安裝好了以后,我們來正式進入pywinauto的世界
一、啟動程序
1
2
|
from
pywinauto
import
application
app
=
application.Application.start(
'notepad.exe'
)
|
start() 函數里也可以接路徑+程序名
使用spy++lite查看notepad的信息
里面的窗口類名與標題文本相關重要,以后的查找窗口基本上都要用的到
現在我們來點擊“幫助->關於記事本”操作
1
|
app.Notepad.MenuSelect(
'幫助->關於記事本'
.decode(
'gb2312'
))
|
這里的app是你剛才實例的對象,Notepad是類名,可以從spy++lite中看到,MenuSelect方法可以自動檢索Notepad上的菜單選項,
decode(‘gb2312’)方法是把中文強制轉換為unicode編碼,對於非英文的操作系統都是要轉換的,后面還有更簡單的方法
二、查找“關於記事本”的窗口
還是使用spy++lite來查看“關於記事本”的信息
窗口類名:#32770
標題文字:關於“記事本”
官方法文檔中有以下兩個方法
1. 通過top_dlg = app.top_window_() 來獲得最上面的window,但是官方並不推薦這種方式,目前來說這個“關於記事本”是最上面,但是也不能保證在測試的進程當中有什么意外的進程跑到了上面,一旦有新的進程,那么得到的就是一個錯誤的對象
2.通過find_dlg = app.window_(title_re = ‘’, class_name = ‘’) 方法獲得,這也是為什么我上面說標題文本與窗口類名非常重要的原因,title_re和 class_name這兩個可以單獨使用也可以一塊使用,因為有時沒有標題文本,也有時一個窗口類名有多個對象,比如“Edit”有時當一個對話框中有多個輸入框時會有多個Edit類名,對於“關於記事本”我們可以通過以下代碼獲得
1
|
about_dlg
=
app.window_(title_re
=
u
"關於"
, class_name
=
"#32770"
)
|
中文要進行unicode編碼,這里也可以通過decode(‘gb2312’)方法實現,但是不如輸入一個U省事~ 呵呵
我們print一下得到的about_dlg
<pywinauto.application.WindowSpecification object at 0x01F0A530>
說明我們得到的是一個application.WindowSpecification對象
三、在”關於記事本”窗口上找到“確定”按鈕(button)
在pywinauto中,對話框下面的是controller,button,checkbox,textbox等都是controller
我們可以使用print_control_identifiers() 方法來打印出該窗口中所有的controller
1
|
about_dlg.print_control_identifiers()
|
會得到以下的輸出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
Control Identifiers:
Static
-
'' (L312, T265, R738, B267)
'
' '
0
' '
1
' '
Static
' '
Static0
' '
Static1'
Static
-
'' (L308, T280, R340, B313)
'2'
'Static2'
Static
-
'Microsoft Windows'
(L350, T280, R695, B295)
'Microsoft Windows'
'Microsoft WindowsStatic'
'Static3'
Static
-
'\u7248\u672c 6.1 (\u5185\u90e8\u7248\u672c 7601: Service Pack 1)'
(L350, T295, R748, B310)
'Static4'
'\u7248\u672c 6.1 (\u5185\u90e8\u7248\u672c 7601: Service Pack 1)'
'\u7248\u672c 6.1 (\u5185\u90e8\u7248\u672c 7601: Service Pack 1)Static'
Static
-
'\u7248\u6743\u6240\u6709 \xa9 2009 Microsoft Corporation\u3002\u4fdd\u7559\u6240\u6709\u6743\u5229\u3002'
(L350, T310, R710, B325)
'Static5'
'\u7248\u6743\u6240\u6709 \xa9 2009 Microsoft Corporation\u3002\u4fdd\u7559\u6240\u6709\u6743\u5229\u3002'
'\u7248\u6743\u6240\u6709 \xa9 2009 Microsoft Corporation\u3002\u4fdd\u7559\u6240\u6709\u6743\u5229\u3002Static'
Static
-
'Windows 7 \u65d7\u8230\u7248 \u64cd\u4f5c\u7cfb\u7edf\u53ca\u5176\u7528\u6237\u754c\u9762\u53d7\u7f8e\u56fd\u548c\u5176\u4ed6\u56fd\u5bb6/\u5730\u533a\u7684\u5546\u6807\u6cd5\u548c\u5176\u4ed6\u5f85\u9881\u5e03\u6216\u5df2\u9881\u5e03\u7684\u77e5\u8bc6\u4ea7\u6743\u6cd5\u4fdd\u62a4\u3002'
(L350, T325, R710, B385)
'Static6'
'Windows 7 \u65d7\u8230\u7248 \u64cd\u4f5c\u7cfb\u7edf\u53ca\u5176\u7528\u6237\u754c\u9762\u53d7\u7f8e\u56fd\u548c\u5176\u4ed6\u56fd\u5bb6/\u5730\u533a\u7684\u5546\u6807\u6cd5\u548c\u5176\u4ed6\u5f85\u9881\u5e03\u6216\u5df2\u9881\u5e03\u7684\u77e5\u8bc6\u4ea7\u6743\u6cd5\u4fdd\u62a4\u3002'
'Windows 7 \u65d7\u8230\u7248 \u64cd\u4f5c\u7cfb\u7edf\u53ca\u5176\u7528\u6237\u754c\u9762\u53d7\u7f8e\u56fd\u548c\u5176\u4ed6\u56fd\u5bb6/\u5730\u533a\u7684\u5546\u6807\u6cd5\u548c\u5176\u4ed6\u5f85\u9881\u5e03\u6216\u5df2\u9881\u5e03\u7684\u77e5\u8bc6\u4ea7\u6743\u6cd5\u4fdd\u62a4\u3002Static'
'Windows 7 \u65d7\u8230\u7248 \u64cd\u4f5c\u7cfb\u7edf\u53ca\u5176\u7528\u6237\u754c\u9762\u53d7\u7f8e\u56fd\u548c\u5176\u4ed6\u56fd\u5bb6/\u5730\u533a\u7684\u5546\u6807\u6cd5\u548c\u5176\u4ed6\u5f85\u9881\u5e03\u6216\u5df2\u9881\u5e03\u7684\u77e5\u8bc6\u4ea7\u6743\u6cd5\u4fdd\u62a4\u3002Static0'
'Windows 7 \u65d7\u8230\u7248 \u64cd\u4f5c\u7cfb\u7edf\u53ca\u5176\u7528\u6237\u754c\u9762\u53d7\u7f8e\u56fd\u548c\u5176\u4ed6\u56fd\u5bb6/\u5730\u533a\u7684\u5546\u6807\u6cd5\u548c\u5176\u4ed6\u5f85\u9881\u5e03\u6216\u5df2\u9881\u5e03\u7684\u77e5\u8bc6\u4ea7\u6743\u6cd5\u4fdd\u62a4\u3002Static1'
Static
-
'' (L350, T385, R665, B415)
'Static7'
'Windows 7 \u65d7\u8230\u7248 \u64cd\u4f5c\u7cfb\u7edf\u53ca\u5176\u7528\u6237\u754c\u9762\u53d7\u7f8e\u56fd\u548c\u5176\u4ed6\u56fd\u5bb6/\u5730\u533a\u7684\u5546\u6807\u6cd5\u548c\u5176\u4ed6\u5f85\u9881\u5e03\u6216\u5df2\u9881\u5e03\u7684\u77e5\u8bc6\u4ea7\u6743\u6cd5\u4fdd\u62a4\u3002Static2'
SysLink
-
'\u6839\u636e <A>Microsoft \u8f6f\u4ef6\u8bb8\u53ef\u6761\u6b3e</A>\uff0c\u672c\u4ea7\u54c1\u4f7f\u7528\u6743\u5c5e\u4e8e:'
(L350, T415, R665, B445)
'SysLink'
'\u6839\u636e <A>Microsoft \u8f6f\u4ef6\u8bb8\u53ef\u6761\u6b3e</A>\uff0c\u672c\u4ea7\u54c1\u4f7f\u7528\u6743\u5c5e\u4e8e:'
'\u6839\u636e <A>Microsoft \u8f6f\u4ef6\u8bb8\u53ef\u6761\u6b3e</A>\uff0c\u672c\u4ea7\u54c1\u4f7f\u7528\u6743\u5c5e\u4e8e:SysLink'
Static
-
'kevin'
(L365, T445, R680, B460)
'Static8'
'kevin'
'kevinStatic'
'kevinStatic0'
'kevinStatic1'
Static
-
'' (L365, T460, R680, B475)
'Static9'
'kevinStatic2'
Button
-
'\u786e\u5b9a'
(L672, T503, R747, B524)
'Button'
'\u786e\u5b9a'
'\u786e\u5b9aButton'
|
static,SysLink,button等是它類型,后面接的是title,都是unicode的,這里面就有沒有title的controller,再后面的(L,T,R,B)是這個控件的位置,分別對應着左上右下
在”關於記事本”窗口上找到“確定”按鈕,可以通過app.window_()方法,傳入的參數可以是title,也可以是class_name,所以我說這兩個值相當重要,一直在用,這里的title支持正則表達式,非常方便
在app上先找到about_dlg,然后再about_dlg上找確定button
app.window_(title_re = u'關於“記事本”').window_(title_re = u'確定'),然后通過Click()方法來單擊這個button
另外一種方法也是官方推薦的在非英文系統下的方法
1
2
|
OK
=
u
'確定'
about_dlg[OK].Click()
|
這個的意思就是在about_dlg下找到u’確定’,看起來比上面要簡練好理解,理解了這種方式,接下來還有更簡單的,都不用找about_dlg
直接 app[u'關於“記事本”'][u'確定'].Click()
四、在記事本里寫點東西
這個其實在校驗pywinauto的時候已經做過了全用TypeKeys函數,但是這里如果要輸入中文還是要u一下
1
|
app.notepad.TypeKeys(u
"楊彥星"
)
|
五、一個比較惡心的問題
在MenuSelect函數中不支持正則,完全是全文匹配,如我輸入
dig = app.Notepad.MenuSelect("編輯->替換".decode('gb2312')) 是找不到對象的
必須要
dig = app.Notepad.MenuSelect("編輯(E)->替換(R)".decode('gb2312')) 這樣才行,得把(R) (E)寫上才行,但是奇怪的是上面的“幫助->關於記事本”就不用輸入,所以說是一個挺惡心的問題,我也不知道這是為什么……
最后把上面的函數合並一下,跑下來應該會很快
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
|
#! /usr/bin/env python
#coding=gbk
import
time
from
pywinauto
import
application
app
=
application.Application.start(
'notepad.exe'
)
app.Notepad.MenuSelect(
'幫助->關於記事本'
.decode(
'gb2312'
))
time.sleep(.
5
)
#這里有兩種方法可以進行定位“關於記事本”的對話框
#top_dlg = app.top_window_() 不推薦這種方式,因為可能得到的並不是你想要的
about_dlg
=
app.window_(title_re
=
u
"關於"
, class_name
=
"#32770"
)#這里可以進行正則匹配title
#about_dlg.print_control_identifiers()
app.window_(title_re
=
u
'關於“記事本”'
).window_(title_re
=
u
'確定'
).Click()
app.Notepad.MenuSelect(
'幫助->關於記事本'
.decode(
'gb2312'
))
time.sleep(.
5
)
#停0.5s 否則你都看不出來它是否彈出來了!
ABOUT
=
u
'關於“記事本”'
OK
=
u
'確定'
#about_dlg[OK].Click()
#app[ABOUT][OK].Click()
app[u
'關於“記事本”'
][u
'確定'
].Click()
app.Notepad.TypeKeys(u
"楊彥星"
)
dig
=
app.Notepad.MenuSelect(
"編輯(E)->替換(R)"
.decode(
'gb2312'
))
Replace
=
u
'替換'
Cancle
=
u
'取消'
time.sleep(.
5
)
app[Replace][Cancle].Click()
dialogs
=
app.windows_()
|
轉自:
http://my.oschina.net/yangyanxing/blog/167042