querylist采集微信公众号文章( UI自动化工具轻松实现微信消息的自动收发和朋友圈爬取)
优采云 发布时间: 2021-10-21 06:58querylist采集微信公众号文章(
UI自动化工具轻松实现微信消息的自动收发和朋友圈爬取)
大家好,我是小明。昨天,我在《UI自动化工具轻松实现微信消息自动收发和好友动态爬取》一文中演示了三个UIAutomation的使用实例。链接:
由于昨天对UIAutomation的API的理解不够全面,个人代码优化还有很大的空间。今天我们的目标是实现微信PC版联系人信息列表的抓取,这将分别使用PyWinAuto和uiautomation来实现。通过对比,大家就会有更深入的了解。
PyWinAuto 实现
PyWinAuto 官方文档地址:
将 PyWinAuto 连接到桌面程序有两种主要方式:
它们是进程的 pid 和窗口句柄。下面我将演示如何获取微信的进程id和窗口句柄。
根据进程名获取进程ID:
import psutil
def get_pid(proc_name):
for proc in psutil.process_iter(attrs=['pid', 'name']):
if proc.name() == proc_name:
return proc.pid
%time get_pid("WeChat.exe")
Wall time: 224 ms
7268
根据窗口标题和类名查找窗口句柄:
import win32gui
%time hwnd = win32gui.FindWindow("WeChatMainWndForPC", "微信")
hwnd
Wall time: 0 ns
264610
耗时几乎为零,比之前的方法快了100多倍。
于是我用窗口句柄连接微信窗口:
import win32gui
from pywinauto.application import Application
hwnd = win32gui.FindWindow("WeChatMainWndForPC", "微信")
app = Application(backend='uia').connect(handle=hwnd)
app
自动打开*敏*感*词*:
import pywinauto
win = app['微信']
txl_btn = win.child_window(title="*敏*感*词*", control_type="Button")
txl_btn.draw_outline()
cords = txl_btn.rectangle()
pywinauto.mouse.click(button='left', coords=(
(cords.right+cords.left)//2, (cords.top+cords.bottom)//2))
随机点击好友信息详情后,通过inspect.exe查看节点信息。
然后编写如下代码,根据分析结果运行:
可以看到各种信息提取的很流畅,但是最多需要3.54秒,不一定比手动复制粘贴快。这也是pywinauto的一个缺点,太慢了。
下面我们进行批量爬取。原理大致是每次读取信息面板时,按向下箭头键,发现当前读取的数据与上一次一致。认为爬行已经结束。
由于pywinauto的爬取速度太慢,我手动将好友列表拖到最后,然后运行如下代码:
import pandas as pd
win = app['微信']
contacts = win.child_window(title="联系人", control_type="List")
# 点击第二个可见元素
contacts.children()[1].click_input()
result = []
last = None
num = 0
while 1:
tag = win.Edit2
tmp = tag.parent().parent()
nickname = tag.get_value()
# 跳过两个官方号
if nickname in ["微信团队", "文件传输助手"]:
contacts.type_keys("{DOWN}")
continue
detail = tmp.children()[-1]
whats_up = ""
if hasattr(detail, 'get_value'):
whats_up = detail.get_value()
elif hasattr(detail, 'window_text') and detail.window_text() != "":
# 这种情况说明是企业微信,跳过
contacts.type_keys("{DOWN}")
continue
items = tmp.parent().parent().children()[2].children()
row = {"昵称": nickname, "个性签名": whats_up}
for item in items:
lines = item.children()
k = lines[0].window_text()
v = lines[1].window_text()
row[k.replace(" ", "")] = v
if row == last:
# 与上一条数据一致则说明已经爬取完毕
break
result.append(row)
num += 1
print("\r", num, row,
end=" ")
last = row
contacts.type_keys("{DOWN}")
df = pd.DataFrame(result)
df
最后结果:
可以看出,最后一页11个微信账号的数据抓取耗时45秒。
ui自动化实现
接下来,我们将使用 uiautomation 来实现这种爬取。
获取微信窗口,点击*敏*感*词*按钮:
import uiautomation as auto
wechatWindow = auto.WindowControl(searchDepth=1, Name="微信", ClassName='WeChatMainWndForPC')
wechatWindow.SetActive()
txl_btn = wechatWindow.ButtonControl(Name='*敏*感*词*')
txl_btn.Click()
然后点击云朵君的好友信息,测试好友信息抽取:
(这个数字,你可以随意添加)
wechatWindow.EditControl(searchDepth=10, foundIndex=2) 表示在10层节点内搜索第二个EditControl类型节点(第一个是搜索框,第二个是朋友的昵称)。
GetParentControl() 和 GetNextSiblingControl() 是昨天没有使用的 API。它们用于获取父节点和下一个兄弟节点。使用这两个 API 来重写昨天的 文章 的代码,将使程序代码变得简单和高效。改进。
然后使用与 PyWinAuto 相同的方式进行批量提取:
还要先测试最后一页的数据:
爬取只用了 11 秒,比 PyWinAuto 快 4 倍。
所以我们可以批量提取所有微信好友的数据。最后,我这边的700多个朋友用了10分钟。虽然速度较慢,但与 PyWinAuto 相比完全可以接受。
代码对比
对于两者,我都试图遵循完全相同的逻辑。
win.Edit2 也得到第二个 EditControl 类型节点,
type_keys 是 PyWinAuto 用来模拟击键的 API,{DOWN} 代表向下的方向键。
PyWinAuto获取父子节点的api都是小写的,没有get,uiautomation获取父子节点的api大写,前缀为Get。
对于 PyWinAuto 中的这行代码:
items = tmp.parent().parent().children()[2].children()
使用 uiautomation:
items = tmp.GetParentControl().GetNextSiblingControl().GetNextSiblingControl().GetChildren()
有一个很大的不同。
这是因为我没有找到PyWinAuto获取兄弟节点的API,所以采用了先获取父节点再获取子节点的方法。
另外,判断是否是企业微信的逻辑不同。PyWinAuto也需要在个性签名为空时处理异常,否则程序会报错退出。具体点需要大家去测试和体验。
其他地方的逻辑几乎相同。
总结
本文还演示了 PyWinAuto 和 uiautomation 读取微信好友列表信息。通过对比,我们可以更深入地了解两者的API用法。作为作者,我在实践中有着深刻的理解。只是文章中的代码并没有体现这些细节,具体的事情需要读者在分析对比的过程中得到答案。仅仅看本文的代码或许可以解决当前的需求,但是很难将本文涉及的技术应用到其他需求上。
童鞋们,让我们通过动手实践来学习吧⁉️学完之后,你会看到任何实现Automation Provider的桌面程序,并且可以爬~