大家好,我是😎

今天我要给大家分享的是UI自动化测试工具UIAutomation实现对桌面程序的自动化控制和数据采集。前段时间有见过号主分享PyWinAutoWinAppDriver实现对桌面程序的自动化控制和数据采集。

我个人只推荐使用UIAutomation。为什么但呢?因为PyWinAuto 解析效率的速度非常慢,后面会通过《对比PyWinAuto和uiautomation实现微信联系人自动采集》这篇文章进行演示。

WinAppDriver服务框架需要Windows10 或 Windows Server 2016 以上系统开发者模式才能使用,它支持 Appium,但Appium 环境配置较为麻烦。对于已经能够达到同样自动化控制效果的UIAutomation显得比较重量级。不过有兴趣的童鞋,可以根据本文的系列,尝试用WinAppDriver实现同样的需求。

使用UIAutomation的前提是需要被自动化操作的桌面程序是用微软提供的标准控件实现的,实现了UI Automation Provider,详见:https://docs.microsoft.com/zh-cn/windows/win32/winauto/uiauto-providersoverview

基于vue的Electron桌面应用,虽然默认不支持UIAutomation,但在启动时开启参数–force-renderer-accessibility也能能支持UIAutomation。

那么如何通过python去调用这个微软UIAutomation API呢,可以查看:https://github.com/yinkaisheng/Python-UIAutomation-for-Windows/blob/master/readme_cn.md

这是某个大佬在业余时间开发的python模块,要感谢这位大佬的无私奉献,给了我们直接安装使用的机会,减少了学习成本,不用深入研究更底层的API。

同时我也要感谢微信昵称叫 那个百分十先生 的大佬,我第一次听说uiautomation
模块就是从这位做RPA的大佬听说的。只是只看到这位大佬用这个模块做web爬虫,却没有看到自动操作桌面应用的示例。所以我通过这个模块研究对桌面应用程序的自动化,补充这方面的中文资料的空缺。

大佬的相关文章:一种基于uiautomation和Python的网站加密字体数据获取
微信公众号:Python知识学堂

我们直接pip安装就可以使用这个库了:

pip install uiautomation

image-20210824212143061

今天我将以微信PC端为例子,演示UIAutomation 库的使用。

首先我们的目标是实现微信当前聊天窗口的聊天文本提取:

💻当前微信聊天窗口聊天记录提取💻

首先我们打开inspect.exe工具,并对微信窗口进行定位:

image-20210824202856100

inspect.exe是windows系统自带工具,可以通过everything搜索到文件位置。我的电脑上搜索到的位置是:C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\inspect.exe

可以查询的到的Name和,对微信启动自动化控制:

import uiautomation as auto

wechatWindow = auto.WindowControl(searchDepth=1, Name="微信", ClassName='WeChatMainWndForPC')

下面就以黄博的群为例子,演示一下提取当前聊天窗口的数据,首先我们需要分析一下ui节点的结构:

image-20210824203852277

可以看到消息列表节点的Name为"消息",ControlType为UA_ListControlTypeId (0xC358),而每条消息都是消息列表节点的子节点的名称,基于此我们编码:

messages = wechatWindow.ListControl(Name='消息')
for message in messages.GetChildren():
    content = message.Name
    print(content)

打印的后面一部分结果:

2021年8月21日 20:26
👇👇8.25-26邀您观看百度BML线上课程,一起聊聊工业AI质检~
-单瑕疵、多瑕疵等复杂场景识别率如何提升
-采集样本质量保证,小样本数据量如何增强
-数据回流让模型持续优化,降低产品漏检率
-快速搭建AI质检模型进行效果验证
-高精度模型调参与算法优化技巧

[红包][红包]看直播抽取小度真无线耳机、小度智能音箱、飞桨定制鼠标垫……新用户参与2021万有引力计划即刻获🉐️100元京东卡奖励!
报名链接:https://paddle.wjx.cn/vm/exDHIgz.aspx?udsid=340852
[图片]
2021年8月21日 22:16
[链接]
7个实用技巧总结[强]
昨天 11:53
【直播消息】8月25日我们特别邀请到凡泰极客创始人&CTO 杨涛先生进行线上直播分享,和大家聊聊移动应用如何利用小程序容器技术做转型升级,欢迎阅读文章了解详情~
[链接]
18:50
"xman" 撤回了一条消息

这个提取过于简单粗暴,如果还可以知道发送人和链接内容就更好了,那么我们继续深入分析节点:

image-20210824204913060

嵌套的层数挺多的,继续这样不断的分析各种情况下的节点结构和类型,多次测试,最终编写出如下代码:

import pandas as pd

wechatWindow.SetFocus()
messages = wechatWindow.ListControl(Name='消息')
result = []
time = pd.NA
for message in messages.GetChildren():
    content = message.Name
    if content in ["查看更多消息", "以下为新消息"]:
        continue
    details = message.GetChildren()[0].GetChildren()
    if len(details) == 0:
        time = content
        continue
    nickname, detail, me = details
    name = nickname.Name
    if me.Name:
        name = me.Name

    link_all = pd.NA
    if not (content == "[图片]" or content.startswith("[语音]")):
        details = detail.GetChildren()
        if len(details) == 0:
            continue
        detail = details[-1].GetChildren()[0].GetChildren()[0].GetChildren()[0]
        details = detail.GetChildren()

        if len(details) != 0:
            link_title = details[0].Name
            link_content = details[1].Name
            content += f"{link_title}\n{link_content}"
#     print(time, name, content)
    result.append((time, name, content.strip()))
df = pd.DataFrame(result, columns=["时间", "昵称", "内容"])
df

结果:

image-20210824205949656

目前我经过2小时的测试也只能提取到这个程度,有兴趣的小伙伴还可以继续研究,提取出文件的文件名。

发现一个有意思的群,必须要测试一下(不能辜负你们的队形):

image-20210824210613270

还挺有意思的,下面我们实现一下微信群聊轰炸机:

💥自动发送微信消息💥

分别查看输入框和发送按钮的Name和类型:

image-20210824212004346

然后编写如下代码进行测试:

edit = wechatWindow.EditControl(Name='输入')
edit.SendKeys('test')
sendButton = wechatWindow.ButtonControl(Name='发送(S)')
sendButton.Click()

运行后,我这里已经顺利给自己发送了test:

image-20210824212516391

批量表情包轰炸开始:

import random

emoji_faces = [
    "[微笑]", "[撇嘴]", "[色]", "[发呆]", "[得意]", "[流泪]", "[害羞]", "[闭嘴]", "[睡]", "[大哭]", "[尴尬]",
    "[发怒]", "[调皮]", "[呲牙]", "[惊讶]", "[难过]", "[囧]", "[抓狂]", "[吐]", "[偷笑]", "[愉快]", "[白眼]",
    "[傲慢]", "[困]", "[惊恐]", "[憨笑]", "[悠闲]", "[咒骂]", "[疑问]", "[嘘]", "[晕]", "[衰]", "[骷髅]", "[猪头]",
    "[敲打]", "[再见]", "[擦汗]", "[抠鼻]", "[鼓掌]", "[坏笑]", "[右哼哼]", "[鄙视]", "[委屈]", "[快哭了]",
    "[阴险]", "[亲亲]", "[可怜]", "[笑脸]", "[生病]", "[脸红]", "[破涕为笑]", "[恐惧]", "[失望]", "[无语]",
    "[嘿哈]", "[捂脸]", "[奸笑]", "[机智]", "[皱眉]", "[耶]", "[吃瓜]", "[加油]", "[汗]", "[天啊]", "[Emm]",
    "[社会社会]", "[旺柴]", "[好的]", "[打脸]", "[哇]", "[翻白眼]", "[666]", "[让我看看]", "[叹气]", "[苦涩]",
    "[裂开]", "[嘴唇]", "[爱心]", "[心碎]", "[拥抱]", "[强]", "[弱]", "[握手]", "[胜利]", "[抱拳]", "[勾引]",
    "[拳头]", "[OK]", "[合十]", "[啤酒]", "[咖啡]", "[蛋糕]", "[玫瑰]", "[凋谢]", "[菜刀]", "[便便]", "[月亮]",
    "[太阳]", "[礼物]", "[红包]", "[發]", "[福]", "[跳跳]", "[发抖]", "[转圈]", "[炸弹]", "[庆祝]", "[烟花]"
]
wechatWindow.SetFocus()
for _ in range(5):
    emoji_face = random.choice(emoji_faces)
    edit.SendKeys(emoji_face)
    sendButton.Click()

先随机发5个表情吧:

录制_2021_08_24_21_27_22_478

嘿嘿,测试成功。可以自动发消息了,不过不要乱在群聊里发,被T出群聊后,本文作者不负任何责任噢🐶~

🌀朋友圈爬取🌀

最后我们进行最后一个例子,这次怎么去查找节点元素就不演示了,大家直接看代码。👉

首先我们获取朋友圈按钮并打开朋友圈:

button = wechatWindow.ButtonControl(Name='朋友圈')
button.Click()

获取当前朋友圈窗口的数据:

friendWindow = auto.WindowControl(
    searchDepth=1, Name="朋友圈", ClassName='SnsWnd')
friendWindow.SetFocus()
listControls = friendWindow.ListControl(Name='朋友圈')
for item in listControls.GetChildren():
    if item.ControlTypeName != "ListItemControl":
        continue
    print(item.Name)
    panes = item.GetChildren()[0].GetChildren()[
        0].GetChildren()[1].GetChildren()
    if len(panes) >= 5:
        print("评论:")
        comments = panes[4].ListControl(Name='评论')
        for comment in comments.GetChildren():
            print(comment.Name)
    print("------------------")

可以看到朋友圈当前窗口的数据也完全获取到:

image-20210824213905814

这时,我们只需要加个自动滑动朋友圈窗口的代码,即可批量爬取朋友圈。

如何批量爬取朋友圈呢?这就当是留给各位童鞋们的作业了,期待各位童鞋们大显身手,拿出良好的解决方案。😎

后期我自己也会给出参考答案,尽请期待~


本文转载:CSDN博客