在学uiautomation(以微信进入青年大学习为例)
目录
一、前言
二、前期准备
三、开干
3.1打开微信客户端
3.2判断微信是否登录
3.3微信页面操作
3.4具体页面操作
3.5对产生的新窗格进行操作
3.6页面关闭
3.7全部代码展示
四、总结
一、前言
之前笔者写过关于uiautomation的一篇入门级文章初识UI自动化(inspect.exe + uiautomation)https://blog.csdn.net/knighthood2001/article/details/124297008?spm=1001.2014.3001.5502不过没有给出相应的学习例子,因此本篇文章主要以微信的青年大学习为例。教你如何使用uiautomation进入微信青年大学习。
二、前期准备
2.1模块准备
import subprocessimport uiautomation as autoimport time
①subprocess模块用来启动微信客户端
②uiautomation模块用来UI自动化
2.2软件准备
inspect.exe(或者其他用于获取窗口或控制句柄的软件,如UISpy.exe)
三、开干
如上图,首先我们需要知道,青年大学习的很多页面是只能在微信客户端中才能打开。因此我们采取uiautomation模块进行模仿人进行手动操作。
3.1打开微信客户端
# 可执行文件的具体地址信息subprocess.Popen('E:\微信\WeChat\WeChat.exe')
使用subprocess.Popen('微信具体地址')打开微信客户端
3.2判断微信是否登录
“微信”窗格页面
“进入微信”按钮页面
代码如下:
# 判断微信是否已经登录wechat_login = auto.PaneControl(Name='微信')enter_wechat_btn = wechat_login.ButtonControl(Name='进入微信')if enter_wechat_btn.Exists(): enter_wechat_btn.Click()
上图可以看出,“进入微信”按钮是“微信”窗格的子控件。因此我们可以先定位“微信”窗格,然后再定位“进入微信”按钮。定位方式可以通过具体控件的类型、名字等来定位。
然后通过Exists()函数来判断控件是否存在,存在则进行点击事件。
注意:“微信”窗格页面中的控件类型为PaneControl,并给出了ClassName,不过auto.PaneControl()中没有ClassName这一参数。
3.3微信页面操作
登录微信后,“微信”窗口页面的相关句柄如下。
# 进入微信后wechatWindow = auto.WindowControl(searchDepth=1, className='WeChatMainWndForPC', Name='微信')
1
2
# 点击聊天button = wechatWindow.ButtonControl(Name='聊天')button.Click()# 搜索search = wechatWindow.EditControl(Name='搜索')search.Click()
接下来在搜索框中搜索青春浙江,然后在结果中遍历,判断名字是否为青春浙江,如果是则点击。
# 输入查找内容search.GetParentControl().GetChildren()[1].SendKeys('青春浙江')searResult = wechatWindow.ListControl(Name='搜索结果').GetChildren()for sear in searResult: # print(sear.Name) if sear.Name == '青春浙江': sear.Click() break
不过还有一种方法,即输入青春浙江,然后回车。
# 通过回车search.GetParentControl().GetChildren()[1].SendKeys('青春浙江')time.sleep(2)wechatWindow.SendKeys('{Enter}')
注意:
①输入青春浙江后,需要一点时间然后再回车,不然结果不正确。笔者认为是只要运行了第一行代码,即使内容还没输完,就运行了回车的代码。
②SendKeys('文本或者按键')不仅仅支持文本的输入,也支持按键的使用,包括组合键的使用。
例:{Enter}表示回车、{Delete}表示Delete、{Ctrl}v表示Ctrl+v。
3.4具体页面操作
接下来点击更多,然后点击发消息,最后点击大学习。
session = wechatWindow.PaneControl(Name='会话列表')more = session.ButtonControl(Name='更多')more.Click()send_message = auto.MenuItemControl(Name='发消息')send_message.Click()dxx_btn = session.ButtonControl(Name='大学习')dxx_btn.Click()
3.5对产生的新窗格进行操作
注意:“微信”窗口控件的ClassName与之前的已经发生了更改,因此需要重新定义一个。
wechatWindow_2 = auto.WindowControl(searchDepth=1, className='CefWebViewWnd', Name='微信')
由于每隔一段时间(如每隔一天)会出现授权信息,需要同意,因此同样需要判断该控件是否存在。
# 这个判断会花费较长时间# 每隔一段时间后会出现授权信息agree_btn = wechatWindow_2.ButtonControl(Name="同意")if agree_btn.Exists(): agree_btn.Click()
接下来就是点击“立即学习”按钮。不过首先得判断一下页面是否为最大化,如果页面处于最大化,会找不到“立即学习”按钮,因此需要点击向下还原。
max = wechatWindow_2.ButtonControl(Name='向下还原')# 判断页面是否最大化if max.Exists(): max.Click()study_icon = wechatWindow_2.ImageControl(Name='立即学习')study_icon.Click()
由于“立即参与”(如上图)是一张没有Name的图片,因此我们可以通过其所在树的位置进行查找。
同理,之后出现的“去学习”也是一张没有Name的图片,也可以通过其所在树的位置进行查找。
# 到达立即参与界面participate_in_btn = wechatWindow_2.DocumentControl(Name="青春浙江“青年大学习”").GetChildren()[0].GetChildren()[4].GetChildren()[0]participate_in_btn.Click()# # 到达去学习界面study_page = wechatWindow_2.DocumentControl(Name="青春浙江“青年大学习”").GetChildren()[0].GetChildren()[3].GetChildren()[0]time.sleep(5)study_btn = study_page.GetChildren()[9]study_btn.Click()
点击立即参与后,就来到了具体需要学习的页面,为了显示完全,然后获取相应的网址。因此首先进行了最大化页面的操作,然后使用CaptureToImane("图片名字",x,y,长,宽)截取二维码图片并保存,便于后续操作。
'''1'''# 最大化# 最大化界面有漏洞,最大化后,右上角的图标仍为最大化,而不是向下还原wechatWindow_2.Maximize()time.sleep(2)# 截取二维码图片wechatWindow_2.CaptureToImage('url.jpg', 1218, 257, 190, 185)wechatWindow_2.DoubleClick(960, 10)
注意:经过笔者测试,发现Maximize()函数有漏洞,即使用该方法最大化后,右上角的图标仍显示最大化而不是向下还原,因此笔者最终选择双击窗口最上方进行向下还原操作。
不过,随着对inspect.exe的逐渐熟悉,找到了最大化、向下还原按钮所在树中的位置。因此对以上代码做出了相应的调整,弃用了Maximize()
'''2'''# 最大化# max_page = wechatWindow_2.ButtonControl(Name='最大化')# max_page.Click()# time.sleep(2)# # 截图二维码# wechatWindow_2.CaptureToImage('url.jpg', 1218, 257, 190, 185)# # 向下还原# restore_page = wechatWindow_2.ButtonControl(Name='向下还原')# restore_page.Click()
再深入研究后,发现了更好的获取网址的方法。
首先也是最大化页面,然后用inspect.exe找到网址所在树的位置。
由于网址所在的是编辑控件,查看网址所在区域,虽然没有Name,但是我们发现LegacyIAccessible.Value: "https://h5.cyol.com/special/daxuexi/cod4a2tb5v/index.html"
中的是网址,所以我们可以通过一些办法找到该网址。
'''3'''max_page = wechatWindow_2.ButtonControl(Name='最大化')max_page.Click()time.sleep(2)edit = wechatWindow_2.EditControl(searchDepth=5).GetValuePattern().Valueprint(edit)# 向下还原restore_page = wechatWindow_2.ButtonControl(Name='向下还原')restore_page.Click()
3.6页面关闭
最后就将页面关闭和微信关闭即可。
注意:两个控件的ClassName不同,在定义时分开定义了。
# 关闭具体页面wechatWindow_2.ButtonControl(Name='关闭').Click()# 关闭微信界面wechatWindow.ButtonControl(Name='关闭').Click()
3.7全部代码展示
import subprocessimport uiautomation as autoimport time'''searchFromControl: `Control` or its subclass, if it is None, search from root control(Desktop).searchDepth: int, max search depth from searchFromControl.Depth: int, only search controls in relative depth from searchFromControl, ignore controls in depth(0~Depth-1), if set, searchDepth will be set to Depth too.'''# 可执行文件的具体地址信息subprocess.Popen('E:\微信\WeChat\WeChat.exe')# 判断微信是否已经登录wechat_login = auto.PaneControl(Name='微信')enter_wechat_btn = wechat_login.ButtonControl(Name='进入微信')if enter_wechat_btn.Exists(): enter_wechat_btn.Click()# 进入微信后wechatWindow = auto.WindowControl(searchDepth=1, className='WeChatMainWndForPC', Name='微信')# 点击聊天button = wechatWindow.ButtonControl(Name='聊天')button.Click()# 搜索search = wechatWindow.EditControl(Name='搜索')search.Click()# 通过回车search.GetParentControl().GetChildren()[1].SendKeys('青春浙江')time.sleep(2)wechatWindow.SendKeys('{Enter}')session = wechatWindow.PaneControl(Name='会话列表')more = session.ButtonControl(Name='更多')more.Click()send_message = auto.MenuItemControl(Name='发消息')send_message.Click()dxx_btn = session.ButtonControl(Name='大学习')dxx_btn.Click()# ---------------------------------------------wechatWindow_2 = auto.WindowControl(searchDepth=1, className='CefWebViewWnd', Name='微信')# 这个判断会花费较长时间# 每隔一段时间后会出现授权信息agree_btn = wechatWindow_2.ButtonControl(Name="同意")if agree_btn.Exists(): agree_btn.Click()max = wechatWindow_2.ButtonControl(Name='向下还原')# 判断页面是否最大化if max.Exists(): max.Click()study_icon = wechatWindow_2.ImageControl(Name='立即学习')study_icon.Click()# 到达立即参与界面participate_in_btn = wechatWindow_2.DocumentControl(Name="青春浙江“青年大学习”").GetChildren()[0].GetChildren()[4].GetChildren()[0]participate_in_btn.Click()# # 到达去学习界面study_page = wechatWindow_2.DocumentControl(Name="青春浙江“青年大学习”").GetChildren()[0].GetChildren()[3].GetChildren()[0]time.sleep(5)study_btn = study_page.GetChildren()[9]study_btn.Click()'''3'''# 最大化max_page = wechatWindow_2.ButtonControl(Name='最大化')max_page.Click()time.sleep(2)# 获取网址edit = wechatWindow_2.EditControl(searchDepth=5).GetValuePattern().Valueprint(edit)# 向下还原restore_page = wechatWindow_2.ButtonControl(Name='向下还原')restore_page.Click()# 关闭具体页面wechatWindow_2.ButtonControl(Name='关闭').Click()# 关闭微信界面wechatWindow.ButtonControl(Name='关闭').Click()
四、总结
①微信进入青年大学习的方式有很多,上述讲的只是其中一种方法,之后笔者也会更新其他的方法。
②代码总是在不断的改善,只要你多思考。由于笔者知识有限,上述过程中存在许多地方可以改善。例如,判断某个控件是否存在,如果该控件不存在,将会花费很长的时间去寻找判断,这是一处地方可以进行改善。又如,笔者不太懂SearchDepth和Depth的具体用法,虽然之前也有讲过。
③上述内容如有错误,请指正!!