大头哈利 發表於 2020-10-28 18:35:00

python基于pywinauto实现PC端自动化 python操作微信自动化

<h2>一、 pywinauto安装和启动</h2>
<h3>1.安装:</h3>
<div class="cnblogs_code">
<pre>pip install pywinauto</pre>
</div>
<h3 class="md-end-block md-p"><span class="md-plain">2.backend选择 和 控件查看工具inspect介绍</span></h3>
<p class="md-end-block md-p"><span class="md-plain">我们安装好Pywinauto之后,首先要确定哪种可访问性技术(backend)可以用于我们的应用程序,在windows上受支持的有两种:</span></p>
<ul class="ul-list" data-mark="-">
<li class="md-list-item">
<p class="md-end-block md-p"><strong>Win32 API</strong><span class="md-plain">&nbsp;(<code>backend= "win32"</code><span class="md-plain">) 默认的backend</span></span></p>
</li>
<li class="md-list-item">
<p class="md-end-block md-p"><strong>MS UI Automation</strong><span class="md-plain">&nbsp;(<code>backend="uia"</code><span class="md-plain">)</span></span></p>
</li>
</ul>
<p class="md-end-block md-p"><span class="md-plain">如果不能确定程序到底适用于那种backend,可以借助于GUI对象检查工具来做,常用的检查工具有<strong>Inspect.ex</strong><span class="md-plain">,<strong>Spy++</strong><span class="md-plain">&nbsp;,下载地址:https://github.com/blackrosezy/gui-inspect-tool</span></span></span></p>
<p class="md-end-block md-p"><span class="md-plain"><span class="md-plain"><span class="md-plain">giithub的项目中的inspect好像不行了,可以用下面这个:</span></span></span></p>
<p>链接:https://pan.baidu.com/s/1LHvbcP5NKqSHC7FLSpiTFQ <br>提取码:p4hm</p>
<p>将inspect左上角的下拉列表中切换到“UI Automation”,然后鼠标点一下你需要测试的程序窗体,inspect就会显示相关信息,如下图所示。说明backend为uia</p>
<p>&nbsp;程序里面的任意一个部位其实都是控件,在inspect的控件树中都可以找到,是一层一层分级别的,可以一个个点开所有控件</p>
<p><img src="https://img2020.cnblogs.com/blog/1652510/202010/1652510-20201028163031333-180559694.png" alt="" loading="lazy"></p>
<h3>2.启动(实例化程序):以微信示例</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">from</span> pywinauto.application <span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> Application
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 常用方式一:连接已有微信进程(进程号在 任务管理器-详细信息 可以查看,项目中一般根据进程名称自动获取)</span>
app = Application(backend=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">uia</span><span style="color: rgba(128, 0, 0, 1)">'</span>).connect(process=8948<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 常用方式二:启动微信进程 (注意路径中特殊字符的转义,/和\,不注意有时会出错)</span>
app = Application(backend=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">uia</span><span style="color: rgba(128, 0, 0, 1)">"</span>).start(r<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">C:\Program Files (x86)\Tencent\WeChat\WeChat.exe</span><span style="color: rgba(128, 0, 0, 1)">'</span>) </pre>
</div>
<h3>3.Application对象app的常用方法</h3>
<p>通过查看pywinauto的源码中application.py文件,可以看到app的所有属性方法,下面列举常用方法:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">app.top_window()
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 返回应用程序当前顶部窗口,是<span style="color: rgba(255, 0, 255, 1)">WindowSpecification</span>对象,可以继续使用对象的方法往下继续查找控件</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> eg:如:app.top_window().child_window(title='地址和搜索栏', control_type='Edit')</span>
<span style="color: rgba(0, 0, 0, 1)">
app.window(</span>**<span style="color: rgba(0, 0, 0, 1)">kwargs)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 根据筛选条件,返回一个窗口, 是<span style="color: rgba(255, 0, 255, 1)">WindowSpecification</span>对象,可以继续适用对象的方法往下继续查找控件</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> eg: 微信主界面 app.window(class_name='WeChatMainWndForPC')</span>
<span style="color: rgba(0, 0, 0, 1)">
app.windows(</span>**<span style="color: rgba(0, 0, 0, 1)">kwargs)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 根据筛选条件返回一个窗口列表,无条件默认全部,列表项为<span style="color: rgba(255, 0, 255, 1)">wrapped</span>对象,可以使用wrapped对象的方法,注意不是WindowSpecification对象</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> eg:[&lt;uiawrapper.UIAWrapper - '李渝的早报 - Google Chrome', Pane, -2064264099699444098&gt;]</span>
<span style="color: rgba(0, 0, 0, 1)">
app.kill(soft</span>=False) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 强制关闭</span>
app.cpu_usage() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 返回指定秒数期间的CPU使用率百分比</span>
app.wait_cpu_usage_lower(threshold=2.5, timeout=None, usage_interval=None) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 等待进程CPU使用率百分比小于指定的阈值threshold</span>
app.is64bit() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 如果操作的进程是64-bit,返回True</span></pre>
</div>
<h2>二、控件定位方法和控件可用方法</h2>
<p>操作控件需要以下几个步骤:&nbsp;</p>
<p>第一步 实例化要操作的进程:得到的app是<span style="color: rgba(255, 0, 255, 1)">Application</span>对象</p>
<p>第二步 选择窗口 :app.window('一个或多个筛选条件') 得到的窗口是<span style="color: rgba(255, 0, 255, 1)">WindowSpecification</span>对象</p>
<p>第三步:基于<span style="color: rgba(255, 0, 255, 1)">WindowSpecification</span>对象使用其方法再往下查找,定位到具体的控件</p>
<p>第四步:使用控件的方法属性执行我们需要的操作</p>
<p>WindowSpecification源码中有一些自带的方法可以直接使用,也有注释说到:</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_a3309d5e-1abc-42b5-bfd5-99656758ad9c" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_a3309d5e-1abc-42b5-bfd5-99656758ad9c" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_a3309d5e-1abc-42b5-bfd5-99656758ad9c" class="cnblogs_code_hide">
<pre>    <span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">
    A specification for finding a window or control

    Windows are resolved when used.
    You can also wait for existance or non existance of a window

    .. implicitly document some private functions
    .. automethod:: __getattribute__
    .. automethod:: __getitem__
    </span><span style="color: rgba(128, 0, 0, 1)">"""</span></pre>
</div>
<span class="cnblogs_code_collapse">WindowSpecification 说明</span></div>
<p>就是说这是一个查找空间或者窗口的规范,可以使用等待机制。</p>
<p>并且该对象中__getattribute__和__getitem__两个魔术方法,隐式地记录一些私有方法</p>
<p>我的理解是我们可以继续往下一层一层的查找,下面一层一层的控件其实是各种各样的wrapper对象,wrapper有很多种是一系列对象,对象源码都在pywinauto源码的controls目录中</p>
<p>以下总结了常用方法,基本可以满足所有场景的操作,如下:</p>
<h3>2.1 层级查找控件的方法</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 通过层级查找控件相关方法+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++</span>
window(**kwargs) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 用于窗口的查找</span>
child_window(**kwargs) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 可以不管层级的找后代中某个符合条件的元素,最常用</span>
parent() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 返回此元素的父元素,没有参数</span>
children(**kwargs) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 返回符合条件的子元素列表,支持索引,是BaseWrapper对象(或子类)</span>
iter_children(**kwargs) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 返回子元素的迭代器,是BaseWrapper对象(或子类)</span>
descendants(**kwargs) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 返回符合条件的所有后代元素列表,是BaseWrapper对象(或子类)</span>
iter_children(**kwargs) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 符合条件后代元素迭代器,是BaseWrapper对象(或子类)</span></pre>
</div>
<h3>2.2 kwargs筛选条件</h3>
<p>常用的一些筛选条件:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 这些是常用的</span>
class_name=None, <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 类名</span>
class_name_re=None, <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 正则匹配类名</span>
title=None, <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 控件的标题文字,对应inspect中Name字段</span>
title_re=None, <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 正则匹配文字</span>
control_type=None, <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 控件类型,inspect界面LocalizedControlType字段的英文名</span>
best_match=None, <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 这个有坑,我不喜欢用,下文有讲解</span>
auto_id=None, <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 这个也是固定的可以用,inspect界面AutomationId字段,但是很多控件没有这个属性</span></pre>
</div>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_dbfced88-b683-4626-8973-8ef687bffaa0" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_dbfced88-b683-4626-8973-8ef687bffaa0" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_dbfced88-b683-4626-8973-8ef687bffaa0" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 下面这些不常用,基本用不到</span>
parent=<span style="color: rgba(0, 0, 0, 1)">None,
process</span>=None,<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 这个基本不用,每次启动进程都会变化</span>
top_level_only=<span style="color: rgba(0, 0, 0, 1)">True,
visible_only</span>=<span style="color: rgba(0, 0, 0, 1)">True,
enabled_only</span>=<span style="color: rgba(0, 0, 0, 1)">False,
handle</span>=<span style="color: rgba(0, 0, 0, 1)">None,
ctrl_index</span>=<span style="color: rgba(0, 0, 0, 1)">None,
found_index</span>=<span style="color: rgba(0, 0, 0, 1)">None,
predicate_func</span>=<span style="color: rgba(0, 0, 0, 1)">None,
active_only</span>=<span style="color: rgba(0, 0, 0, 1)">False,
control_id</span>=<span style="color: rgba(0, 0, 0, 1)">None,
framework_id</span>=<span style="color: rgba(0, 0, 0, 1)">None,
backend</span>=None,</pre>
</div>
<span class="cnblogs_code_collapse">源码中有我没用过的条件</span></div>
<h3>2.3 控件可用的方法属性</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 以下几个只支持窗口模式的控件=======================================================================</span>
dlg.close() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 关闭界面</span>
dlg.minimize() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 最小化界面</span>
dlg.maximize() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 最大化界面</span>
dlg.restore() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 将窗口恢复为正常大小,比如最小化的让他正常显示在桌面</span>
dlg.get_show_state() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 正常0,最大化1,最小化2</span>
<span style="color: rgba(0, 0, 0, 1)">
dlg.exists(timeout</span>=None, retry_interval=None) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 判断是否存在</span>
    <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">timeout:等待时间,一般默认5s</span>
    <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">retry_interval:timeout内重试时间</span>
dlg.wait(wait_for, timeout=None, retry_interval=None) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 等待窗口处于特定状态</span>
dlg.wait_not(wait_for_not, timeout=None, retry_interval=None) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 等待窗口不处于特定状态,即等待消失</span>
<span style="color: rgba(136, 136, 136, 1)">    # 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')</span>

<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 鼠标键盘操作 =====================================================================================</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 我只列举常用形式,他们有很多默认参数但不常用,可以在源码中查看</span>
ctrl.click_input() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 最常用的点击方法,一切点击操作的基本方法(底层调用只是参数不同),左键单击,使用时一般都使用默认不需要带参数</span>
ctrl.right_click_input() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 鼠标右键单击</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 键盘输入,底层还是调用keyboard.send_keys</span>
ctrl.type_keys(keys, pause = None, with_spaces =<span style="color: rgba(0, 0, 0, 1)"> False,)
    </span><span style="color: rgba(136, 136, 136, 1)"># keys:要输入的文字内容
    # pause:每输入一个字符后等待时间,默认0.01就行
    # with_spaces:是否保留keys中的所有空格,默认去除0</span>
ctrl.double_click_input(button =<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">left</span><span style="color: rgba(128, 0, 0, 1)">"</span>, coords = (None, None)) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 左键双击</span>
ctrl.press_mouse_input(coords = (None, None)) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 指定坐标按下左键,不传坐标默认左上角</span>
ctrl.release_mouse_input(coords = (None, None)) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 指定坐标释放左键,不传坐标默认左上角</span>
ctrl.move_mouse_input(coords=(0, 0)) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 将鼠标移动到指定坐标,不传坐标默认左上角</span>
ctrl.drag_mouse_input(dst=(0, 0)) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 将ctrl拖动到dst,是press-move-release操作集合</span>

<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 控件的常用属性===================================================================================</span>
ctrl.children_texts() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 所有子控件的文字列表,对应inspect中Name字段</span>
ctrl.window_text() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 控件的标题文字,对应inspect中Name字段</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> ctrl.element_info.name</span>
ctrl.class_name() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 控件的类名,对应inspect中ClassName字段,有些控件没有类名</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> ctrl.element_info.class_name</span>
ctrl.element_info.control_type <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 控件类型,inspect界面LocalizedControlType字段的英文名</span>
ctrl.is_child(parent) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> ctrl是否是parent的子控件<br><span style="color: rgba(255, 0, 0, 1)">ctrl.legacy_properties().get('Value')</span> # 可以获取inspect界面LegacyIAccessible开头的一系列字段,在源码uiawraper.py中找到了这个方法,非常有用<br>#如某些按钮显示值是我们想要的,但是window_text获取到的是固定文字‘修改群昵称’,这个值才是我们修改后的新名字<br></span>


<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 控件常用操作========================================================================================</span>
ctrl.draw_outline(colour=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">green</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 空间外围画框,便于查看,支持'red', 'green', 'blue'</span>
ctrl.print_control_identifiers(depth=None, filename=None) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 打印其包含的元素,详见打印元素</span>
ctrl.scroll(direction, amount, count=1,) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 滚动</span>
<span style="color: rgba(136, 136, 136, 1)">    # direction :"up", "down", "left", "right"
    # amount:"line" or "page"
    # count:int 滚动次数</span>
ctrl.capture_as_image() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 返回控件的 PIL image对象,可继续使用其方法如下:</span>
<span style="color: rgba(0, 0, 0, 1)">    eg:
      ctrl.capture_as_image().save(img_path)
ret </span>= ctrl.rectangle() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 控件上下左右坐标,(L430, T177, R1490, B941),可.输出上下左右</span>
<span style="color: rgba(136, 136, 136, 1)">    eg:
      ret.top=177
      ret.bottom=941
      ret.left=430
      ret.right=1490</span></pre>
</div>
<h2>三、具体使用举例</h2>
<p>第二节中列举了能用到的方法属性,本节列举实际操作中的具体用法</p>
<h3>1.对话框dialog选择</h3>
<p>根据pywinauto的源码中application.py文件介绍,窗口选择有三种方式:</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_1f2c76f2-44fc-4246-9813-3158228c2ad2" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_1f2c76f2-44fc-4246-9813-3158228c2ad2" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_1f2c76f2-44fc-4246-9813-3158228c2ad2" class="cnblogs_code_hide">
<pre>Once you have an Application instance you can access dialogs <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> that
application either by using one of the methods below. ::

   dlg </span>=<span style="color: rgba(0, 0, 0, 1)"> app.YourDialogTitle
   dlg </span>= app.child_window(title=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">your title</span><span style="color: rgba(128, 0, 0, 1)">"</span>, classname=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">your class</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, ...)
   dlg </span>= app[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Your Dialog Title</span><span style="color: rgba(128, 0, 0, 1)">'</span>]</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>以微信主界面窗口为例:</p>
<p><img src="https://img2020.cnblogs.com/blog/1652510/202112/1652510-20211220172338024-1822341783.png" alt="" width="497" height="187" loading="lazy"></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 微信主界面几种方式:</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 这个最好用,下面几种不指名道姓容易出错且速度很慢</span>
dlg1 = app.window(class_name=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">WeChatMainWndForPC</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 是WindowSpecification对象</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 下面几种方法速度慢,我是不喜欢用</span>
# dlg2_1 =<span style="color: rgba(0, 0, 0, 1)"> app.Dialog
# dlg2_2 </span>=<span style="color: rgba(0, 0, 0, 1)"> app.微信
# dlg3_1 </span>= app[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Dialog</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">]
# dlg3_2 </span>= app[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">微信</span><span style="color: rgba(128, 0, 0, 1)">'</span>]</pre>
</div>
<h3>2.打印元素</h3>
<p>我们拿到控件后,是可以将该控件下的所有子控件及其属性以树形结构打印出来的:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 拿到微信主窗口</span>
win_main_Dialog = app.window(class_name=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">WeChatMainWndForPC</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 判断是否为dialog,一个微信是一个dialog,就是窗口</span>
<span style="color: rgba(0, 0, 255, 1)">print</span><span style="color: rgba(0, 0, 0, 1)">(win_main_Dialog<span style="background-color: rgba(0, 255, 255, 1)">.is_dialog</span>)

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 给控件画个红色框便于看出是哪个</span>
win_main_Dialog.<span style="background-color: rgba(0, 255, 255, 1)">draw_outline</span>(colour = <span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">red</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 打印当前窗口的所有controller(控件和属性)</span>
win_main_Dialog.<span style="background-color: rgba(0, 255, 255, 1)"> print_control_identifiers</span>(depth=None, filename=<span style="color: rgba(0, 0, 0, 1)">None)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 源码内部函数名链式赋值了,都能用,一样的</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> print_ctrl_ids = dump_tree = print_control_identifiers</span></pre>
</div>
<p>depth:打印的深度,缺省时打印最大深度。<br>filename:将返回的标识存成文件(生成的文件与当前运行的脚本在同一个路径下)<br>eg:dlg. print_control_identifiers(filename =’a.txt’)</p>
<p>打印出来的文档树就是inspect中的控件树完全展开的样子,都是有层级的,和微信程序中的各个元素是一一对应的:</p>
<p><img src="https://img2020.cnblogs.com/blog/1652510/202010/1652510-20201028163759501-795181620.png" alt="" width="1105" height="648" loading="lazy"></p>
<h3>3 常用查找方法</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 拿到微信主窗口</span>
win_main_Dialog = app.window(class_name=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">WeChatMainWndForPC</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 主窗口下的某个窗口,不管层级的找</span>
chat_list = win_main_Dialog.child_window(control_type=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">List</span><span style="color: rgba(128, 0, 0, 1)">'</span>, title=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">会话</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
first </span>= chat_list.items() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 第一个聊天项列表支持items(),支持循环,支持索引</span>

<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 详情页修改备注操作parent()和children()都是只往上或往下查找一个层级,所有满足的放进列表</span>
details_page = win_main_Dialog.child_window(class_name=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">ContactProfileWnd</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 窗口下的某个窗口</span>
we_id = details_page.child_window(title=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">微信号:</span><span style="color: rgba(128, 0, 0, 1)">"</span>, control_type=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Text</span><span style="color: rgba(128, 0, 0, 1)">"</span>).parent().children().window_text() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 窗口的爸爸的第二个儿子的文字</span>
alia = details_page.child_window(title=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">微信号:</span><span style="color: rgba(128, 0, 0, 1)">"</span>, control_type=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Text</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">).parent().parent().children().children().window_text()
edit_btn </span>= details_page.child_window(title=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">备   注</span><span style="color: rgba(128, 0, 0, 1)">"</span>, control_type=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Text</span><span style="color: rgba(128, 0, 0, 1)">"</span>).parent().children()
edit_btn.click_input()
btn_modify_name_edit </span>=<span style="color: rgba(0, 0, 0, 1)"> edit_btn
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 先ctrl+a选中所有然后再type_keys替换</span>
btn_modify_name_edit.type_keys(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">^a</span><span style="color: rgba(128, 0, 0, 1)">'</span>).type_keys(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">备注名字</span><span style="color: rgba(128, 0, 0, 1)">'</span>, with_spaces=<span style="color: rgba(0, 0, 0, 1)">True)

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> descendants查找所有后代中满足的,不管层级,所有满足的放进列表</span>
btns_list = win_main_Dialog.child_window(control_type=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">ToolBar</span><span style="color: rgba(128, 0, 0, 1)">'</span>).parent().descendants(control_type=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Button</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
btns_list.click_input()

dialog.child_window(title</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">文件名(N):</span><span style="color: rgba(128, 0, 0, 1)">"</span>, auto_id=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">1148</span><span style="color: rgba(128, 0, 0, 1)">"</span>, control_type=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Edit</span><span style="color: rgba(128, 0, 0, 1)">"</span>)</pre>
</div>
<h3>4 快速定位</h3>
<p>定位一个元素我们可以一层一层定位,但是这样真就有点笨蛋了,不仅效率低下还不容易适应结构变化,可以先定位某个页面,打印出页面结构,然后基于页面快速定位</p>
<p>&nbsp;</p>
<p><img src="https://img2020.cnblogs.com/blog/1652510/202012/1652510-20201211164733791-692453759.png" alt="" width="1496" height="1149" loading="lazy"></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_7c095ffa-918c-4dfa-aa5a-df944a56efe5" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_7c095ffa-918c-4dfa-aa5a-df944a56efe5" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_7c095ffa-918c-4dfa-aa5a-df944a56efe5" class="cnblogs_code_hide">
<pre>    <span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> we_name(self):
      </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> todo+++++++++++++++++++++++++++++++++++++</span>
      <span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">:
            self._popup </span>= wechat.win_main.child_window(class_name=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">ContactProfileWnd</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
            self._popup.wait(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">visible</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
            self._popup.print_control_identifiers(depth</span>=None, filename=<span style="color: rgba(0, 0, 0, 1)">None)

            </span><span style="color: rgba(0, 0, 255, 1)">print</span>(self._popup.Edit.window_text()) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> www.pu🤗</span>
            <span style="color: rgba(0, 0, 255, 1)">print</span>(self._popup.Edit0.window_text()) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> www.pu🤗</span>
            <span style="color: rgba(0, 0, 255, 1)">print</span>(self._popup.Edit1.window_text()) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> www.pu🤗</span>

            <span style="color: rgba(0, 0, 255, 1)">print</span>(self._popup.Edit2.window_text()) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> qwer1315458571</span>
            <span style="color: rgba(0, 0, 255, 1)">print</span>(self._popup.child_window(best_match=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">微信号:Edit</span><span style="color: rgba(128, 0, 0, 1)">'</span>).window_text()) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> qwer1315458571</span>
            <span style="color: rgba(0, 0, 255, 1)">print</span>(self._popup.child_window(best_match=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Edit2</span><span style="color: rgba(128, 0, 0, 1)">'</span>).window_text()) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> qwer1315458571</span>

            <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> self._popup.Edit.window_text()
            </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> return self._popup.child_window(title="微信号:", control_type="Text").parent().parent().children().children().window_text()</span>
      <span style="color: rgba(0, 0, 255, 1)">except</span><span style="color: rgba(0, 0, 0, 1)">:
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> None</pre>
</div>
<span class="cnblogs_code_collapse">快速定位 伪代码</span></div>
<h2>四、控件自带的的方法</h2>
<h3>1. 点击和输入</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 左点击,可以点进源码,还有double_click_input,right_click_input等</span>
<span style="color: rgba(0, 0, 0, 1)">edit_btn<span style="background-color: rgba(0, 255, 255, 1)">.click_input()

</span></span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 先ctrl+a选中所有然后再type_keys替换,和我们选中然后修改一样的</span>
edit_btn.type_keys(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">^a</span><span style="color: rgba(128, 0, 0, 1)">'</span>)<span style="background-color: rgba(0, 255, 255, 1)">.type_keys</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">备注名字</span><span style="color: rgba(128, 0, 0, 1)">'</span>, with_spaces=True)</pre>
</div>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" id="code_img_closed_0283f803-b325-4248-978f-e12998f25f46" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" id="code_img_opened_0283f803-b325-4248-978f-e12998f25f46" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_0283f803-b325-4248-978f-e12998f25f46" class="cnblogs_code_hide">
<pre>SHIFT                            +<span style="color: rgba(0, 0, 0, 1)">      
CTRL                           </span>^<span style="color: rgba(0, 0, 0, 1)">      
ALT                               </span>%<span style="color: rgba(0, 0, 0, 1)">
空格键                            {SPACE}

BACKSPACE                        {BACKSPACE}、{BS}   </span><span style="color: rgba(0, 0, 255, 1)">or</span><span style="color: rgba(0, 0, 0, 1)">   {BKSP}      
BREAK                            {BREAK}      
CAPS   LOCK                      {CAPSLOCK}      
DEL   </span><span style="color: rgba(0, 0, 255, 1)">or</span>   DELETE                {DELETE}   <span style="color: rgba(0, 0, 255, 1)">or</span><span style="color: rgba(0, 0, 0, 1)">   {DEL}      
DOWN   ARROW                     {DOWN}      
END                              {END}      
ENTER                            {ENTER}   </span><span style="color: rgba(0, 0, 255, 1)">or</span>   ~<span style="color: rgba(0, 0, 0, 1)">      
ESC                              {ESC}      
HELP                           {HELP}      
HOME                           {HOME}      
INS   </span><span style="color: rgba(0, 0, 255, 1)">or</span>   INSERT                {INSERT}   <span style="color: rgba(0, 0, 255, 1)">or</span><span style="color: rgba(0, 0, 0, 1)">   {INS}      
LEFT   ARROW                     {LEFT}      
NUM   LOCK                     {NUMLOCK}      
PAGE   DOWN                      {PGDN}      
PAGE   UP                        {PGUP}      
PRINT   SCREEN                   {PRTSC}      
RIGHT   ARROW                  {RIGHT}      
SCROLL   LOCK                  {SCROLLLOCK}      
TAB                              {TAB}      
UP   ARROW                     {UP}   
</span>+<span style="color: rgba(0, 0, 0, 1)">                              {ADD}      
</span>-<span style="color: rgba(0, 0, 0, 1)">                              {SUBTRACT}      
</span>*<span style="color: rgba(0, 0, 0, 1)">                              {MULTIPLY}      
</span>/                              {DIVIDE}</pre>
</div>
<span class="cnblogs_code_collapse">常用快捷键</span></div>
<p>常规使用很方便,但是有些字符,比如微信中的用户昵称什么的带有表情等特殊符号,用自带的输入方法就会不适用,可以使用keyboard模块(见下)</p>
<h3>2.对控件截图并保存</h3>
<div class="cnblogs_code">
<pre>ctrl_qrcode = self.win_login.child_window(title=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">二维码</span><span style="color: rgba(128, 0, 0, 1)">'</span>, control_type=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Image</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> ctrl_qrcode<span style="background-color: rgba(0, 255, 255, 1)">.exists()</span>:
    ctrl_qrcode<span style="background-color: rgba(0, 255, 255, 1)">.capture_as_image</span>()<span style="background-color: rgba(0, 255, 255, 1)">.save</span>(img_path)</span></pre>
</div>
<p>capture_as_image() 方法 返回控件的其实是 PIL image对象,所以可用该方法的属性方法,比如save</p>
<h3>3.窗口的等待</h3>
<p>窗口加载需要时间,我们又不能一直sleep就需要等待,等待窗口出现或者等待窗口关闭:</p>
<div class="cnblogs_code">
<pre>save_dialog.<span style="background-color: rgba(0, 255, 255, 1)">wait</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">ready</span><span style="color: rgba(128, 0, 0, 1)">'</span>,timeout=2<span style="color: rgba(0, 0, 0, 1)">)
save_dialog.<span style="background-color: rgba(0, 255, 255, 1)">close</span>()
save_dialog.<span style="background-color: rgba(0, 255, 255, 1)">wait_not</span>(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">visible</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 'exists':窗口是有效的句柄</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 'visible':窗口未隐藏,常用</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 'enabled':未禁用窗口</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 'ready':窗口可见并启用,常用</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 'active':窗口处于活动状态</span></pre>
</div>
<h3>4.窗口存在和关闭</h3>
<div class="cnblogs_code">
<pre>self.chatwnd = wechat.app.window(class_name=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">ChatWnd</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> self.chatwnd.exists():
    self.chatwnd.close()</span></pre>
</div>
<h3>5.其他</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 顶层窗口</span>
dlg =<span style="color: rgba(0, 0, 0, 1)"> app.<span style="background-color: rgba(0, 255, 255, 1)">top_window</span>()
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 点方法取值</span>
<span style="color: rgba(0, 0, 255, 1)">print</span>(dlg<span style="background-color: rgba(0, 255, 255, 1)">.</span>class_name()) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">'WeChatMainWndForPC'</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 滚动 常用于页面的滚动,比如好友列表、聊天列表、消息界面</span>
chat_list.<span style="background-color: rgba(0, 255, 255, 1)">scroll</span>(direction=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">up</span><span style="color: rgba(128, 0, 0, 1)">'</span>, amount=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">page</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>
</div>
<h2>五、鼠标操作</h2>
<p>pywinauto自带的鼠标操作有些时候并不能完全满足要求,可以调用mouse的方法</p>
<p>导入:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">from</span> pywinauto <span style="color: rgba(0, 0, 255, 1)">import</span> mouse</pre>
</div>
<p>常见操作:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 移动鼠标</span>
mouse.move(coords=<span style="color: rgba(0, 0, 0, 1)">(x, y))

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 指定位置,鼠标左击</span>
mouse.click(button=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">left</span><span style="color: rgba(128, 0, 0, 1)">'</span>, coords=(40, 40<span style="color: rgba(0, 0, 0, 1)">))

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 鼠标双击</span>
mouse.double_click(button=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">left</span><span style="color: rgba(128, 0, 0, 1)">'</span>, coords=(140, 40<span style="color: rgba(0, 0, 0, 1)">))

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 将属性移动到(140,40)坐标处按下</span>
mouse.press(button=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">left</span><span style="color: rgba(128, 0, 0, 1)">'</span>, coords=(140, 40<span style="color: rgba(0, 0, 0, 1)">))

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 将鼠标移动到(300,40)坐标处释放,</span>
mouse.release(button=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">left</span><span style="color: rgba(128, 0, 0, 1)">'</span>, coords=(300, 40<span style="color: rgba(0, 0, 0, 1)">))

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 右键单击指定坐标</span>
mouse.right_click(coords=(400, 400<span style="color: rgba(0, 0, 0, 1)">))

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 鼠标中键单击指定坐标(很少用的到)</span>
mouse.wheel_click(coords=(400, 400<span style="color: rgba(0, 0, 0, 1)">))

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 滚动鼠标 wheel_dist指定鼠标滚轮滑动,正数往上,负数往下。</span>
mouse.scroll(coords=(1200,300),wheel_dist=-3)</pre>
</div>
<p>示例:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 以控件中心为起点,滚动</span>
<span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> mouse_scroll(control, distance):
    rect </span>=<span style="color: rgba(0, 0, 0, 1)"> control.rectangle()
    cx </span>= int((rect.left+rect.right)/2<span style="color: rgba(0, 0, 0, 1)">)
    cy </span>= int((rect.top + rect.bottom)/2<span style="color: rgba(0, 0, 0, 1)">)
    mouse.scroll(coords</span>=(cx, cy), wheel_dist=<span style="color: rgba(0, 0, 0, 1)">distance)
mouse_scroll(control</span>=win_main_Dialog.child_window(control_type=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">List</span><span style="color: rgba(128, 0, 0, 1)">'</span>, title=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">联系人</span><span style="color: rgba(128, 0, 0, 1)">'</span>), distance=-5)</pre>
</div>
<h2>六、键盘操作</h2>
<p>和控件自己的type_keys方法效果一样,但是更快,那个是从前到后啪啪啪的输入,这个是一下就出来了那种</p>
<p>在发送文件和图片的时候可以使用键盘模块,复制粘贴,比啪啪啪输入路径再发送速度快多了</p>
<p>并且该模块可以适配很多表情等特殊符号</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> keyboard
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> io

</span><span style="color: rgba(0, 0, 255, 1)">for</span> line <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> io.StringIO(msg):
    keyboard.<span style="background-color: rgba(0, 255, 255, 1)">write</span>(line.strip()) </span><span style="color: rgba(0, 128, 0, 1)">#
</span>    keyboard.<span style="background-color: rgba(0, 255, 255, 1)">send</span>(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">ctrl+enter</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)   
keyboard.write(chat_name)
keyboard.send(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">enter</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
keyboard.send(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">ctrl+v</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>
</div>
<p>&nbsp;</p>
<p><span style="color: rgba(255, 153, 0, 1); font-size: 18pt; background-color: rgba(240, 248, 255, 1)"><strong><span style="font-family: 仿宋">纯干货,可以说是全网最详细最全面讲解,如果确实帮助到了你,右侧打赏一分或者点个推荐吧~</span></strong></span></p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/xp1315458571/p/13892205.html
頁: [1]
查看完整版本: python基于pywinauto实现PC端自动化 python操作微信自动化