在中文windows下使用pywinauto進行窗口操作


這兩天開始接觸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

里面的窗口類名與標題文本相關重要,以后的查找窗口基本上都要用的到

現在我們來點擊“幫助->關於記事本”操作

?
1
app.Notepad.MenuSelect( '幫助->關於記事本' .decode( 'gb2312' ))

這里的app是你剛才實例的對象,Notepad是類名,可以從spy++lite中看到,MenuSelect方法可以自動檢索Notepad上的菜單選項,

decode(‘gb2312’)方法是把中文強制轉換為unicode編碼,對於非英文的操作系統都是要轉換的,后面還有更簡單的方法

二、查找“關於記事本”的窗口

還是使用spy++lite來查看“關於記事本”的信息

2

窗口類名:#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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM