querylist采集微信公眾號文章( UI自動(dòng)化工具輕松實(shí)現微信消息的自動(dòng)收發(fā)和朋友圈爬取)
優(yōu)采云 發(fā)布時(shí)間: 2021-10-21 06:58querylist采集微信公眾號文章(
UI自動(dòng)化工具輕松實(shí)現微信消息的自動(dòng)收發(fā)和朋友圈爬取)
大家好,我是小明。昨天,我在《UI自動(dòng)化工具輕松實(shí)現微信消息自動(dòng)收發(fā)和好友動(dòng)態(tài)爬取》一文中演示了三個(gè)UIAutomation的使用實(shí)例。鏈接:
由于昨天對UIAutomation的API的理解不夠全面,個(gè)人代碼優(yōu)化還有很大的空間。今天我們的目標是實(shí)現微信PC版聯(lián)系人信息列表的抓取,這將分別使用PyWinAuto和uiautomation來(lái)實(shí)現。通過(guò)對比,大家就會(huì )有更深入的了解。
PyWinAuto 實(shí)現
PyWinAuto 官方文檔地址:
將 PyWinAuto 連接到桌面程序有兩種主要方式:
它們是進(jìn)程的 pid 和窗口句柄。下面我將演示如何獲取微信的進(jìn)程id和窗口句柄。
根據進(jìn)程名獲取進(jìn)程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
根據窗口標題和類(lèi)名查找窗口句柄:
import win32gui
%time hwnd = win32gui.FindWindow("WeChatMainWndForPC", "微信")
hwnd
Wall time: 0 ns
264610
耗時(shí)幾乎為零,比之前的方法快了100多倍。
于是我用窗口句柄連接微信窗口:
import win32gui
from pywinauto.application import Application
hwnd = win32gui.FindWindow("WeChatMainWndForPC", "微信")
app = Application(backend='uia').connect(handle=hwnd)
app
自動(dòng)打開(kāi)*敏*感*詞*:
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))
隨機點(diǎn)擊好友信息詳情后,通過(guò)inspect.exe查看節點(diǎn)信息。
然后編寫(xiě)如下代碼,根據分析結果運行:
可以看到各種信息提取的很流暢,但是最多需要3.54秒,不一定比手動(dòng)復制粘貼快。這也是pywinauto的一個(gè)缺點(diǎn),太慢了。
下面我們進(jìn)行批量爬取。原理大致是每次讀取信息面板時(shí),按向下箭頭鍵,發(fā)現當前讀取的數據與上一次一致。認為爬行已經(jīng)結束。
由于pywinauto的爬取速度太慢,我手動(dòng)將好友列表拖到最后,然后運行如下代碼:
import pandas as pd
win = app['微信']
contacts = win.child_window(title="聯(lián)系人", control_type="List")
# 點(diǎn)擊第二個(gè)可見(jiàn)元素
contacts.children()[1].click_input()
result = []
last = None
num = 0
while 1:
tag = win.Edit2
tmp = tag.parent().parent()
nickname = tag.get_value()
# 跳過(guò)兩個(gè)官方號
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() != "":
# 這種情況說(shuō)明是企業(yè)微信,跳過(guò)
contacts.type_keys("{DOWN}")
continue
items = tmp.parent().parent().children()[2].children()
row = {"昵稱(chēng)": nickname, "個(gè)性簽名": 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:
# 與上一條數據一致則說(shuō)明已經(jīng)爬取完畢
break
result.append(row)
num += 1
print("\r", num, row,
end=" ")
last = row
contacts.type_keys("{DOWN}")
df = pd.DataFrame(result)
df
最后結果:
可以看出,最后一頁(yè)11個(gè)微信賬號的數據抓取耗時(shí)45秒。
ui自動(dòng)化實(shí)現
接下來(lái),我們將使用 uiautomation 來(lái)實(shí)現這種爬取。
獲取微信窗口,點(diǎn)擊*敏*感*詞*按鈕:
import uiautomation as auto
wechatWindow = auto.WindowControl(searchDepth=1, Name="微信", ClassName='WeChatMainWndForPC')
wechatWindow.SetActive()
txl_btn = wechatWindow.ButtonControl(Name='*敏*感*詞*')
txl_btn.Click()
然后點(diǎn)擊云朵君的好友信息,測試好友信息抽?。?/p>
?。ㄟ@個(gè)數字,你可以隨意添加)
wechatWindow.EditControl(searchDepth=10, foundIndex=2) 表示在10層節點(diǎn)內搜索第二個(gè)EditControl類(lèi)型節點(diǎn)(第一個(gè)是搜索框,第二個(gè)是朋友的昵稱(chēng))。
GetParentControl() 和 GetNextSiblingControl() 是昨天沒(méi)有使用的 API。它們用于獲取父節點(diǎn)和下一個(gè)兄弟節點(diǎn)。使用這兩個(gè) API 來(lái)重寫(xiě)昨天的 文章 的代碼,將使程序代碼變得簡(jiǎn)單和高效。改進(jìn)。
然后使用與 PyWinAuto 相同的方式進(jìn)行批量提?。?/p>
還要先測試最后一頁(yè)的數據:
爬取只用了 11 秒,比 PyWinAuto 快 4 倍。
所以我們可以批量提取所有微信好友的數據。最后,我這邊的700多個(gè)朋友用了10分鐘。雖然速度較慢,但??與 PyWinAuto 相比完全可以接受。
代碼對比
對于兩者,我都試圖遵循完全相同的邏輯。
win.Edit2 也得到第二個(gè) EditControl 類(lèi)型節點(diǎn),
type_keys 是 PyWinAuto 用來(lái)模擬擊鍵的 API,{DOWN} 代表向下的方向鍵。
PyWinAuto獲取父子節點(diǎn)的api都是小寫(xiě)的,沒(méi)有g(shù)et,uiautomation獲取父子節點(diǎn)的api大寫(xiě),前綴為Get。
對于 PyWinAuto 中的這行代碼:
items = tmp.parent().parent().children()[2].children()
使用 uiautomation:
items = tmp.GetParentControl().GetNextSiblingControl().GetNextSiblingControl().GetChildren()
有一個(gè)很大的不同。
這是因為我沒(méi)有找到PyWinAuto獲取兄弟節點(diǎn)的API,所以采用了先獲取父節點(diǎn)再獲取子節點(diǎn)的方法。
另外,判斷是否是企業(yè)微信的邏輯不同。PyWinAuto也需要在個(gè)性簽名為空時(shí)處理異常,否則程序會(huì )報錯退出。具體點(diǎn)需要大家去測試和體驗。
其他地方的邏輯幾乎相同。
總結
本文還演示了 PyWinAuto 和 uiautomation 讀取微信好友列表信息。通過(guò)對比,我們可以更深入地了解兩者的API用法。作為作者,我在實(shí)踐中有著(zhù)深刻的理解。只是文章中的代碼并沒(méi)有體現這些細節,具體的事情需要讀者在分析對比的過(guò)程中得到答案。僅僅看本文的代碼或許可以解決當前的需求,但是很難將本文涉及的技術(shù)應用到其他需求上。
童鞋們,讓我們通過(guò)動(dòng)手實(shí)踐來(lái)學(xué)習吧??學(xué)完之后,你會(huì )看到任何實(shí)現Automation Provider的桌面程序,并且可以爬~