python基於pywinauto實現PC端自動化 python操作微信自動化


一、 pywinauto安裝和啟動

安裝:

pip install pywinauto

啟動(實例化程序):以微信示例

from pywinauto.application import Application
# 常用方式一:連接已有微信進程(進程號在 任務管理器-詳細信息 可以查看)
app = Application(backend='uia').connect(process=8948)
# 常用方式二:啟動微信進程 (注意路徑中特殊字符的轉義,/和\,不注意有時會出錯)
app = Application(backend="uia").start(r'C:\Program Files (x86)\Tencent\WeChat\WeChat.exe') 

結束:

# 結束進程
app.kill()

二、backend選擇 和 控件查看工具inspect

1.backend選擇和inspect介紹

我們安裝好Pywinauto之后,首先要確定哪種可訪問性技術(backend)可以用於我們的應用程序,在windows上受支持的有兩種:

  • Win32 API (backend= "win32") 默認的backend

  • MS UI Automation (backend="uia")

如果不能確定程序到底適用於那種backend,可以借助於GUI對象檢查工具來做,常用的檢查工具有Inspect.exSpy++ ,下載地址:https://github.com/blackrosezy/gui-inspect-tool

將inspect左上角的下拉列表中切換到“UI Automation”,然后鼠標點一下你需要測試的程序窗體,inspect就會顯示相關信息,如下圖所示。說明backend為uia

 

 程序里面的任意一個部位其實都是控件,在inspect的控件樹中都可以找到,是一層一層分級別的,可以一個個點開所有控件

2.打印元素

我們拿到控件后,是可以將該控件下的所有子控件及其屬性以樹形結構打印出來的:

# 拿到微信主窗口
win_main_Dialog = app.window(class_name='WeChatMainWndForPC')

# 判斷是否為dialog,一個微信是一個dialog,就是窗口
print(win_main_Dialog.is_dialog)

# 給控件畫個紅色框便於看出是哪個
win_main_Dialog.draw_outline(colour = 'red')

# 打印當前窗口的所有controller(控件和屬性)
win_main_Dialog. print_control_identifiers(depth=None, filename=None)
# 源碼內部函數名鏈式賦值了,都能用,一樣的
# print_ctrl_ids = dump_tree = print_control_identifiers

depth:打印的深度,缺省時打印最大深度。
filename:將返回的標識存成文件(生成的文件與當前運行的腳本在同一個路徑下)
eg:dlg. print_control_identifiers(filename =’a.txt’)

打印出來的文檔樹就是inspect中的控件樹完全展開的樣子,都是有層級的,和微信程序中的各個元素是一一對應的:

 三、控件定位

3.1常規查找

# 直接找窗口
win_main_Dialog = app.window(class_name='WeChatMainWndForPC')

# 主窗口下的某個窗口,不管層級的找
chat_list = win_main_Dialog.child_window(control_type='List', title='會話')
first = chat_list.items()[0] # 第一個聊天項  列表支持items(),支持循環,支持索引
chat_list.scroll(direction='down', amount='page') # 向下滾動一頁

# 詳情頁修改備注操作  parent()和children()都是只往上或往下查找一個層級,所有滿足的放進列表
details_page = win_main_Dialog.child_window(class_name='ContactProfileWnd') # 窗口下的某個窗口
we_id = details_page.child_window(title="微信號:", control_type="Text").parent().children()[1].window_text() # 窗口的爸爸的第二個兒子的文字
alia = details_page.child_window(title="微信號:", control_type="Text").parent().parent().children()[0].children()[0].window_text()
edit_btn = details_page.child_window(title="備   注", control_type="Text").parent().children()[1]
edit_btn.click_input()
btn_modify_name_edit = edit_btn
# 先ctrl+a選中所有然后再type_keys替換
btn_modify_name_edit.type_keys('^a').type_keys('備注名字', with_spaces=True)

# descendants查找所有后代中滿足的,不管層級,所有滿足的放進列表
btn_return = win_main_Dialog.child_window(control_type='ToolBar').parent().descendants(control_type='Button')
btn_return[0].click_input()

 

title="微信團隊" # 對應inspect界面的Name,打印出來也會顯示

class_name='WeChatLoginWndForPC' # 對應ClassName

control_type="Window" # 對應LocalizedControlType的英文版,打印出來后也會顯示
control_type="Text"
control_type="Button"
control_type="List"
control_type="ListItem"
control_type='MenuItem'
control_type='ToolBar'

auto_id='FileTypeControlHost'
控件常見特征

3.2 快速定位

當你還在一層一層定位的時候,就純的不行了,頁面一定要打印出來,然后基於頁面快速定位

 

 

    def we_name(self):
        # todo+++++++++++++++++++++++++++++++++++++
        try:
            self._popup = wechat.win_main.child_window(class_name='ContactProfileWnd')
            self._popup.wait('visible')
            self._popup.print_control_identifiers(depth=None, filename=None)

            print(self._popup.Edit.window_text()) # www.pu🤗
            print(self._popup.Edit0.window_text()) # www.pu🤗
            print(self._popup.Edit1.window_text()) # www.pu🤗

            print(self._popup.Edit2.window_text()) # qwer1315458571
            print(self._popup.child_window(best_match='微信號:Edit').window_text()) # qwer1315458571
            print(self._popup.child_window(best_match='Edit2').window_text()) # qwer1315458571

            return self._popup.Edit.window_text()
            # return self._popup.child_window(title="微信號:", control_type="Text").parent().parent().children()[0].children()[0].window_text()
        except:
            return None
快速定位 偽代碼

四、控件自帶的的方法

1. 點擊和輸入

# 左點擊,可以點進源碼,還有double_click_input,right_click_input等
edit_btn.click_input() # 先ctrl+a選中所有然后再type_keys替換,和我們選中然后修改一樣的
edit_btn.type_keys('^a').type_keys('備注名字', with_spaces=True)
SHIFT                            +      
CTRL                             ^      
ALT                               %
空格鍵                            {SPACE}

BACKSPACE                        {BACKSPACE}、{BS}   or   {BKSP}      
BREAK                            {BREAK}      
CAPS   LOCK                      {CAPSLOCK}      
DEL   or   DELETE                {DELETE}   or   {DEL}      
DOWN   ARROW                     {DOWN}      
END                              {END}      
ENTER                            {ENTER}   or   ~      
ESC                              {ESC}      
HELP                             {HELP}      
HOME                             {HOME}      
INS   or   INSERT                {INSERT}   or   {INS}      
LEFT   ARROW                     {LEFT}      
NUM   LOCK                       {NUMLOCK}      
PAGE   DOWN                      {PGDN}      
PAGE   UP                        {PGUP}      
PRINT   SCREEN                   {PRTSC}      
RIGHT   ARROW                    {RIGHT}      
SCROLL   LOCK                    {SCROLLLOCK}      
TAB                              {TAB}      
UP   ARROW                       {UP}     
+                                {ADD}      
-                                {SUBTRACT}      
*                                {MULTIPLY}      
/                                {DIVIDE}
常用快捷鍵

2.對控件截圖並保存

ctrl_qrcode = self.win_login.child_window(title='二維碼', control_type='Image')
if ctrl_qrcode.exists(): 
    ctrl_qrcode.capture_as_image().save(img_path)

3.窗口的等待

窗口加載需要時間,我們又不能一直sleep就需要等待,等待窗口出現或者等待窗口關閉:

save_dialog.wait('ready',timeout=2)
save_dialog.close()
save_dialog.wait_not('visible')

# 'exists':窗口是有效的句柄
# 'visible':窗口未隱藏,常用
# 'enabled':未禁用窗口
# 'ready':窗口可見並啟用,常用
# 'active':窗口處於活動狀態

4.窗口存在和關閉

self.chatwnd = wechat.app.window(class_name='ChatWnd')
if self.chatwnd.exists():
    self.chatwnd.close()

5.其他

# 頂層窗口
dlg = app.top_window()
# 點方法取值
print(dlg.class_name()) #'WeChatMainWndForPC'
# 滾動
chat_list.scroll(direction='up', amount='page')

五、鼠標操作

導入:

from pywinauto import mouse

常見操作:

# 移動鼠標
mouse.move(coords=(x, y))

# 指定位置,鼠標左擊
mouse.click(button='left', coords=(40, 40))

# 鼠標雙擊
mouse.double_click(button='left', coords=(140, 40))

# 將屬性移動到(140,40)坐標處按下
mouse.press(button='left', coords=(140, 40))

# 將鼠標移動到(300,40)坐標處釋放,
mouse.release(button='left', coords=(300, 40))

# 右鍵單擊指定坐標
mouse.right_click(coords=(400, 400))

# 鼠標中鍵單擊指定坐標(很少用的到)
mouse.wheel_click(coords=(400, 400))

# 滾動鼠標 wheel_dist指定鼠標滾輪滑動,正數往上,負數往下。
mouse.scroll(coords=(1200,300),wheel_dist=-3)

示例:

# 以控件中心為起點,滾動
def mouse_scroll(control, distance):
    rect = control.rectangle()
    cx = int((rect.left+rect.right)/2)
    cy = int((rect.top + rect.bottom)/2)
    mouse.scroll(coords=(cx, cy), wheel_dist=distance)
mouse_scroll(control=win_main_Dialog.child_window(control_type='List', title='聯系人'), distance=-5)

六、鍵盤操作

和控件自己的type_keys方法效果一樣,但是更快,那個是從前到后啪啪啪的輸入,這個是一下就出來了那種

在發送文件和圖片的時候可以使用鍵盤模塊,復制粘貼,比啪啪啪輸入路徑再發送速度快多了

import keyboard
import io

for line in io.StringIO(msg):
    keyboard.write(line.strip()) #
    keyboard.send('ctrl+enter')   
keyboard.write(chat_name)
keyboard.send('enter')
keyboard.send('ctrl+v')

 


免責聲明!

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



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