基于Python开发的用pywinauto爬取朋友圈互动信息
用于自动化测试的脚本模块,主要操作于Windows标准图形界面。它可以允许你很容易的发送鼠标、键盘动作给Windows的对话框和控件。
安装方式:
命令行安装:pip install pywinauto,简单,方便,直接。
手动安装:【解压缩后执行 python setup.py install】
pyWin32:python调用windows api的库。https://sourceforge.net/projects/pywin32/files/pywin32/Build%20220/
comtypes: COM接口的调度。https://github.com/enthought/comtypes/releases
six:用来兼容Python2和Python3的库。https://pypi.org/project/six/
Pillow:可选,用来做屏幕截图的。https://pypi.org/project/Pillow/2.7.0/
Pywinauto:PC端自动化工具。https://github.com/pywinauto/pywinauto/releases
检查安装成功:使用python解释器运行以下代码,启动windows自带的记事本,如果正常启动不报错,则安装成功。
#开始 测试能否打开记事本
import pywinauto
from pywinauto.application import Application
app = Application(backend="uia").start("notepad.exe")
#结束
backend选择
安装完成后,要先确定哪种==可访问性技术(backend)==可以用于我们的应用程序。在windows上受支持的有两种:
Win32 API (backend= "win32") ,默认的backend
MS UI Automation (backend="uia")
注:可以借助于GUI对象检查工具来确定程序到底适用于那种backend。eg:如果使用 inspect 的uia模式,可见的控件和属性更多的话,backend可选uia,反之,backend可选win32。
常用的检查工具:
1. Inspect(定位元素工具(uia))
2. Spy++ (定位元素工具(win32))
3. UI Spy (定位元素工具)
4. Swapy(可简单生成pywinauto代码)
元素定位工具 inspect
下载:https://github.com/blackrosezy/gui-inspect-tool,或 https://www.pconlife.com/download/otherfile/128053/5f2da0a792d68ff9e9bf33a60613fb57/,或
https://pan.baidu.com/s/1LHvbcP5NKqSHC7FLSpiTFQ,提取码:p4hm
控件的定位和可用方法:
层级查找控件的方法:定位控件
# 通过层级查找控件相关方法
window(**kwargs) # 用于窗口的查找
child_window(**kwargs) # 可以无视层级的找后代中某个符合条件的元素===>【最常用】
parent() # 返回此元素的父元素,没有参数
children(**kwargs) # 返回符合条件的子元素列表,支持索引,是BaseWrapper对象(或子类)
iter_children(**kwargs) # 返回子元素的迭代器,是BaseWrapper对象(或子类)
descendants(**kwargs) # 返回符合条件的所有后代元素列表,是BaseWrapper对象(或子类)
iter_children(**kwargs) # 符合条件后代元素迭代器,是BaseWrapper对象(或子类)---> 存疑,是iter_descendants?
kwargs筛选条件:
# 常用的
class_name=None, # 类名
class_name_re=None, # 正则匹配类名
title=None, # 控件的标题文字,对应inspect中Name字段
title_re=None, # 正则匹配文字
control_type=None, # 控件类型,inspect界面LocalizedControlType字段的英文名
best_match=None, # 模糊匹配类似的title
auto_id=None, # inspect界面AutomationId字段,但是很多控件没有这个属性
# 不常用
parent=None,
process=None,# 这个基本不用,每次启动进程都会变化
top_level_only=True,
visible_only=True,
enabled_only=False,
handle=None,
ctrl_index=None,
found_index=None,
predicate_func=None,
active_only=False,
control_id=None,
framework_id=None,
backend=None,
控件可用的方法属性:
# 以下几个只支持窗口模式的控件
dlg.close() # 关闭界面
dlg.minimize() # 最小化界面
dlg.maximize() # 最大化界面
dlg.restore() # 将窗口恢复为正常大小,比如最小化的让他正常显示在桌面
dlg.get_show_state() # 正常0,最大化1,最小化2
dlg.menu_select() # 菜单栏,eg:app.window.menu_select(Edit -> Replace)
dlg.exists(timeout=None, retry_interval=None) # 判断是否存在
#timeout:等待时间,一般默认5s
#retry_interval:timeout内重试时间
dlg.wait(wait_for, timeout=None, retry_interval=None) # 等待窗口处于特定状态
dlg.wait_not(wait_for_not, timeout=None, retry_interval=None) # 等待窗口不处于特定状态,即等待消失
# wait_for/wait_for_not:
# * 'exists' means that the window is a valid handle
# * 'visible' means that the window is not hidden
# * 'enabled' means that the window is not disabled
# * 'ready' means that the window is visible and enabled
# * 'active' means that the window is active
# timeout:等待多久
# retry_interval:timeout内重试时间
# eg: dlg.wait('ready')
# 鼠标键盘操作,只列举了常用形式,他们有很多默认参数但不常用,可以在源码中查看
ctrl.click_input() # 最常用的点击方法,一切点击操作的基本方法(底层调用只是参数不同),左键单击,使用时一般都使用默认不需要带参数
ctrl.right_click_input() # 鼠标右键单击
ctrl.type_keys(keys, pause = None, with_spaces = False,) # 键盘输入,底层还是调用keyboard.send_keys
# keys:要输入的文字内容
# pause:每输入一个字符后等待时间,默认0.01就行
# with_spaces:是否保留keys中的所有空格,默认去除0
ctrl.double_click_input(button ="left", coords = (None, None)) # 左键双击
ctrl.press_mouse_input(coords = (None, None)) # 指定坐标按下左键,不传坐标默认左上角
ctrl.release_mouse_input(coords = (None, None)) # 指定坐标释放左键,不传坐标默认左上角
ctrl.move_mouse_input(coords=(0, 0)) # 将鼠标移动到指定坐标,不传坐标默认左上角
ctrl.drag_mouse_input(dst=(0, 0)) # 将ctrl拖动到dst,是press-move-release操作集合
# 控件的常用属性
ctrl.children_texts() # 所有子控件的文字列表,对应inspect中Name字段
ctrl.window_text() # 控件的标题文字,对应inspect中Name字段
# ctrl.element_info.name
ctrl.class_name() # 控件的类名,对应inspect中ClassName字段,有些控件没有类名
# ctrl.element_info.class_name
ctrl.element_info.control_type # 控件类型,inspect界面LocalizedControlType字段的英文名
ctrl.is_child(parent) # ctrl是否是parent的子控件
ctrl.legacy_properties().get('Value') # 可以获取inspect界面LegacyIAccessible开头的一系列字段,在源码uiawraper.py中找到了这个方法,非常有用
# 控件常用操作
ctrl.draw_outline(colour='green') # 空间外围画框,便于查看,支持'red', 'green', 'blue'
ctrl.print_control_identifiers(depth=None, filename=None) # 以树形结构打印其包含的元素,详见打印元素
# depth:打印的深度,缺省时打印最大深度。
# filename:将返回的标识存成文件(生成的文件与当前运行的脚本在同一个路径下)
ctrl.scroll(direction, amount, count=1,) # 滚动
# direction :"up", "down", "left", "right"
# amount:"line" or "page"
# count:int 滚动次数
ctrl.capture_as_image() # 返回控件的 PIL image对象,可继续使用其方法如下:
# eg: ctrl.capture_as_image().save(img_path)
ret = ctrl.rectangle() # 控件上下左右坐标,(L430, T177, R1490, B941),可输出上下左右
# eg: ret.top=177
# ret.bottom=941
# ret.left=430
# ret.right=1490
# 微信主界面几种方式:
# 这个最好用
dlg1 = app.window(class_name='WeChatMainWndForPC') # 是WindowSpecification对象
# 下面几种方法速度慢,不指名道姓容易出错
dlg2 = app.Dialog # eg:dlg2 = app.微信
dlg3 = app['Dialog'] # eg: dlg3 = app['微信']
首先我们安装一个psutil,用来获取微信的进程号;然后再安装一个pywinauto,用来读取微信界面上的信息。
# -*- coding:utf-8 -*-
import psutil # 用于获取微信电脑版的进程信息;
import pywinauto # 用于自动化控制微信电脑版
from pywinauto.application import Application #启动
import sys
import pickle
#我们需要先找到微信的进程号,由此定位微信窗口。
#初始化默认进程
PID = 0
#我们把进程ID来提供给PyWinAuto ,以便于链接微信电脑版
for proc in psutil.process_iter(): #循环电脑上的进程,获取进程号和名称
try:
pinfo = proc.as_dict(attrs=['pid', 'name'])
except psutil.NoSuchProcess: #没有运行微信程序
pass
else:
if 'WeChat.exe' == pinfo['name']: #当进程名为WeChat.exe的时候,把进程号记下来
PID = pinfo['pid']
#PyWinAuto实例化并启动应用 #进程ID用来提供给 PyWinAuto.application 以连接微信电脑版,connect是要已经运行微信才行
app = Application(backend='uia').connect(process=PID)
#控制微信电脑版,把朋友圈打开
win = app['微信'] #获得微信窗口实例
#接下来是关键一步,由于微信新版窗口的布局有更改,因此下一步是关键,如果不会变通,就会失败,先调用下面语句,以树形方式打印窗口上所有控件
win.print_control_identifiers()#以树形方式打印窗口上所有控件--在正式使用时可以注释掉
#获取微信窗口上朋友圈按钮实例 Button_pyq = win['Pane6'].child_window(title="朋友圈", control_type="Button")
#然后打开朋友圈窗口
pyq_but = win.child_window(title = '朋友圈',control_type = "Button")
pyq_but.draw_outline() #为按钮描边标识
cords = pyq_but.rectangle() #获取按钮坐标
# 接着控制微信电脑版,模拟鼠标点击,把朋友圈窗口打开
pywinauto.mouse.click(button = 'left',coords = (cords.left + 10,cords.top + 10))
#运行到这里,朋友圈窗口就打开了,接下来获取朋友圈窗口实例,然后把当前窗口内容以树形显示出来
pyq_win = app['朋友圈'] #获取朋友圈窗口实例
pyq_win.draw_outline(colour = 'red',thickness = 2)# 在当前定位到的窗口围画出一条边界线,方便我们看出定位到了哪个控件
#获取朋友窗口里面各个控件结构
print(f'打印朋友圈控件结构:{pyq_win.dump_tree}')
然后,我们定位“朋友圈”这个页面(需要先手动把朋友圈打开,这里才能定位到):
pyq_win = app['朋友圈']
通过用
print(pyq_win.dump_tree())
进行观察,我们可以发现整个朋友圈页面呈现一种由child_window构成的树状结构。其中,
第四层包含若干ListItem类型的child_window,每一个代表一条朋友圈,包括作者、内容、时间。例:child_window(title="张三\n今天天气很好\n3小时前\n", control_type="ListItem")。
在每条朋友圈的子树中、总树的第十层,有一个Edit类型的child_window,代表点赞人名的列表。例:child_window(title="李四,王五", control_type="Edit")。
在每条朋友圈的子树中、总树的第十层,有一个List类型的child_window,代表评论列表。例:child_window(title="评论", control_type="List")。
在评论列表的子树中、总树的第十一层,有若干个ListItem类型的child_window,每一个代表一条评论,包括发布者与内容。例:child_window(title="张三 : 下雨了", control_type="ListItem")。
有这样的了解后,我们就可以通过简单的树上操作把当前显示出来的朋友圈信息爬下来了。
接着我们要做的,就是模拟鼠标滚轮向下滚动,然后继续重复上述过程:
cords = pyq_win.rectangle()
pywinauto.mouse.scroll(wheel_dist=-5, coords=(cords.left+10, cords.bottom-10))
需要注意的是,微信朋友圈页面必须显示在屏幕顶端,“向下滚动”才能正常完成。
向下刷到一定程度后,朋友圈就会被“刷到底”,没法继续往下翻了。经测试,这大概是在读到~1000条朋友圈之后。所以我就加了一个终止条件:如果连续读了20条朋友圈,都是以前读到过的旧内容,就终止程序。
在爬虫过程中,电脑是不能正常使用的(因为电脑需要把鼠标移动到朋友圈界面,然后向下滚动)。从头刷到底大概需要一个小时。
- 相关阅读
- optgroup 标签
- 程序员在网站设计时应注意的SEO细节
- 强制转载文章者加上你的文章出处
- jquery中动态生成的代码使用on hover事件时不出现效果
- jQuery设置提交表单disabled属性所有input、button、extarea、select、checkbox、radio都生效
- 14个CSS实用技巧精选推荐
- 微信公众号回复音乐消息或用客服接口推送音乐消息
- 点击密码框弹出小键盘
- 共有0条关于《基于Python开发的用pywinauto爬取朋友圈互动信息》的评论
- 发表评论
您发布的评论即表示同意遵守以下条款:
一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家、社会、集体和公民的合法权益;
二、不得发布国家法律、法规明令禁止的内容;互相尊重,对自己在本站的言论和行为负责;
三、本站对您所发布内容拥有处置权。
- 更多>>同类信息
- Android移动端自动化测试:使用UIAutomatorViewer与Selenium定位元素
- python通过代码修改pip下载源让下载库飞起
- python里面requests.post返回的res.text还有其它的吗
- windows7环境下安装配置jdk
- python对微信操作要用到这两个库wxpy与itchat
- 8种Python字符串拼接的方法,你知道几种
- 更多>>最新添加文章
- dw里面查找替换使用正则删除sqlserver里面的CONSTRAINT
- Android移动端自动化测试:使用UIAutomatorViewer与Selenium定位元素
- 抖音直播音挂载小雪花 懂车帝小程序
- javascript获取浏览器指纹可以用来做投票
- 火狐Mozilla Firefox出现:无法载入您的Firefox配置文件 它可能已经丢失 或是无法访问 问题解决集合处理办法
- 在Android、iOS、Windows、MacOS中微信小程序的文件存放路径
- python通过代码修改pip下载源让下载库飞起
- python里面requests.post返回的res.text还有其它的吗