掘金 人工智能 07月21日 14:02
从零开始:Python 自动化控制微信聊天实战教程
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文分享了使用Python和uiautomator2库实现微信自动回复的完整过程。文章详细介绍了环境搭建,包括安装Android SDK、UIAutomator2、配置手机环境以及安装weditor工具。随后,文章分析了程序逻辑,讲解了如何连接手机(USB与WiFi)、启动weditor、定位微信应用及联系人、打开对话框,并重点阐述了如何通过元素坐标和文本属性识别对方消息,以及如何获取消息内容和进行回复。最后,文章提供了完整的Python代码实现,并展示了实际运行效果,同时也提到了可能遇到的定位不准等问题。

📱 **环境准备与搭建**:文章详细指导了如何准备开发环境,包括选择IDE(PyCharm)、Python版本(3.7),以及一台Android手机。关键步骤包括下载并配置Android SDK,通过ADB命令验证安装;安装`uiautomator2`库;连接手机并开启USB调试,通过`python -m uiautomator2 init`命令在手机端安装`atx-agent`;安装`weditor`工具以便可视化元素定位。

📲 **手机连接与weditor使用**:介绍了通过USB和WiFi两种方式连接手机,并提供了相应的ADB命令。重点讲解了`weditor`工具的使用,它能像网页开发者工具一样,帮助用户直观地定位手机App中的UI元素,并自动生成对应的元素定位代码,极大地简化了自动化脚本的编写过程。

💬 **微信自动化核心逻辑**:文章深入剖析了实现微信自动回复的核心步骤:首先通过ADB命令获取微信应用的包名,然后使用`uiautomator2`启动微信,并通过`weditor`定位并点击进入目标聊天窗口。关键在于如何识别和提取对方的消息,作者通过分析元素属性和坐标,发现可以通过比较元素中心点与屏幕中心点的关系来判断消息的发送方,并通过双击放大镜图标来获取原本为空的文本内容。

⌨️ **消息收发与自动回复实现**:在成功提取消息内容后,文章详细描述了如何进行回复。这包括设置预设的输入法(如`adbkeyboard.apk`),使用`d.set_fastinput_ime(True)`切换输入法,通过`d.send_keys()`输入回复内容,最后通过点击发送按钮完成消息发送。代码中还包含了判断回复是否正确的逻辑,以及一个简单的死循环来持续监听和回复消息。

💡 **代码实现与优化建议**:文章提供了完整的Python自动化脚本,包含了打开微信、发送指定消息、获取最新消息内容、判断消息来源以及根据预设列表进行回复的完整逻辑。作者也坦诚地指出了`uiautomator2`可能存在的定位不准和点击过快等问题,并鼓励读者根据实际情况进行调试和优化,同时欢迎初学者交流学习心得。

刚学习Python,做点小玩意练练手( ̄▽ ̄)~*

文章目录

目录

一、准备工作

二、环境搭建

1. 安装安卓工具

2. UIAutomator2安装

3. 配置手机环境 

4. 安装weditor

三、程序分析

1. 连接手机

2. 启动weditor

3. 整理思路

四、代码实现

五、效果展示

总结


一、准备工作

        IDE:pycharm2019

        Python:3.7

        还有安卓手机一台(^_-)

        代码git:代码地址

二、环境搭建

1. 安装安卓工具

    首先进入谷歌官网,下载对应的SDK工具,这里我使用的是android-sdk_r24.4.1

编辑

 下载完之后解压,打开SDK Manager,安装对应的工具(PS:这里我就直接无脑下一步

编辑

 安装完之后,配置一下环境变量,在cmd界面输入“adb” 来判断安装是否成功

编辑

编辑

这样,SDK就装好了

2. UIAutomator2安装

      直接执行以下命令进行安装

pip3 install --pre -U uiautomator2

3. 配置手机环境 

    手机用USB连接电脑,手机端开启usb调试。cmd输入adb devices

编辑

 如果出现 device,则是授权成功。如果出现 unauthorized 则是未授权,需要手机授权 

 连接成功之后cmd输入命令,安装atx-agent至手机

python -m uiautomator2 init

出现下图则安装成功,手机端会出现一个ATX的app

编辑

由于自带的SDK工具无法输入中文,所以还需要一个插件adbkeyboard.apk进行支持

4. 安装weditor

     这个插件可以让我们像定位网页元素那样定位手机端元素,执行以下命令进行安装:

pip3  install --pre weditor

    安装成功之后,使用以下命令启动:

python -m weditor

    启动成功后,效果如下:

编辑

环境总算搭好了,接下来万事俱备,只欠东风了

三、程序分析

1. 连接手机

连接手机主要有两种方式,一种是通过USB进行连接,还有一种就是通过WiFi连接        

USB连接:

           这个比较简单,只要一个数据线,然后手机开启USB调试就行了

    WiFi连接:

           首先手机和电脑连接同一个WiFi,然后执行以下命令:

adb tcpip 5555

           再执行以下命令查看:

adb devices

          出现这样既成功了:

编辑

2. 启动weditor

    直接执行以下命令即可:

python -m weditor

    启动成功后如下:

        编辑

3. 整理思路

        开始写代码之前,先来理一下思路,主要分以下几步:

    打开微信寻找联系人打开对话框获取回复内容做出应答

    先来看下第一步,打开微信,这个比较简单,只要获取到微信的包名就行了,执行以下命令:

adb shell pm list package -f |findstr tencent

   结果如下:

编辑

   拿到包名就好办了,直接在weditor运行代码:

d.app_start("com.tencent.mm")

   效果如下:

编辑

 oh,忘了自己有应用分身了 ̄へ ̄,得多加一步了,如果没有分身的话,应该可以直接打开了。用weditor定位到要打开的微信,双击会自动生成代码:

编辑

编辑

第一步打开微信,完成后,接下来看如何打开对话框。其他跟上边的也差不多。如法炮制,这里就直接定位第一个联系人了,先定位元素:

编辑

 在双击:

编辑

 这样打开聊天框也完成了,接来下就是获取回复内容了,这个比较麻烦一点。主要有两个问题:一个是如何区分是对方的消息,还有一个就是如何获取回复的内容。我们先来看第一个问题

编辑

编辑

   对比了两个,发现只有中间的数字不一样,那这个数字代表什么呢,我们数一下当前屏幕上的聊天记录,正好是10条,所以索性猜测是聊天条数 。

   再看下两个节点的坐标,是否可以用坐标进行判断呢?还有个问题,如果遇到超长的怎么办?我们可以取元素的中心坐标,再和手机屏幕中心坐标比较,这样只要不撑满整个宽度,貌似就行了。来做一下实验验证一下:

编辑

 看下结果貌似可以哦

 获取对方回复元素后,就可以准备获取回复内容。我们惊奇的发现一件事,元素的text竟然是空的:

编辑

 额,这就难办了,获取不到内容咋回复。咦,双击了一下。发现可以放大诶

编辑

 山穷水复疑无路,柳暗花明又一村。赶紧试试能不能取得到值,如下:

编辑

哦耶!获取到内容后,只剩最后一步了,就是回复消息了

首先设置我们之前安装的输入法,如下:

编辑

  编写代码测试一下:

# 点击对话框d(resourceId="com.tencent.mm:id/iki").click()# 切换输入法d.set_fastinput_ime(True)time.sleep(1)# 输入内容d.send_keys("我打算的")# d.set_fastinput_ime(False)# 发送消息d(resourceId="com.tencent.mm:id/ay5").click()

 效果如下:

编辑

 好了,终于解决了所有问题,接下来就是实现了( ̄▽ ̄)~*

四、代码实现

    这里只是简单的重复一句话,直到获取正确的回答(PS:本来想接入图灵机器人的,结果发现要钱的,就放弃了(╥╯^╰╥) )。完整的代码如下:

import timeimport uiautomator2 as u2answer_right_list = ["是", "帅", "帅哥", "对", "yes", "很帅", "宇宙第一帅"];# USB连接device = u2.connect();# WiFi连接# device = u2.connect_adb_wifi("192.168.1.9");"""    发送消息"""def auto_answer(message="我帅不帅"):    # 点击对话框    device(resourceId="com.tencent.mm:id/iki").click()    # 切换输入法    device.set_fastinput_ime(True)    time.sleep(1)    # 输入内容    device.send_keys(message)    # d.set_fastinput_ime(False)    # 发送消息    device(resourceId="com.tencent.mm:id/ay5").click()"""    打开微信"""def open_chat_window():    # 根据包名启动微信    device.app_start("com.tencent.mm")    # 由于手机存在应用分身,所以多出一步    device.xpath(        '//*[@resource-id="vivo:id/resolver_slide"]/android.widget.LinearLayout[2]/android.widget.ImageView[1]').click()    time.sleep(3)    # d(resourceId="com.tencent.mm:id/dub", text="通讯录").click()    # 打开置顶的聊天框    device.xpath(        '//*[@resource-id="com.tencent.mm:id/f67"]/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]').click()def is_right_answer(context):    if context in answer_right_list:        return True;    return False;"""获取最新内容"""def get_newest_answer():    # 统计所有的聊天框    count = len(device.xpath('//*[@resource-id="com.tencent.mm:id/awv"]/android.widget.RelativeLayout').all());    # 获取最底下的聊天信息    ele = device.xpath('//*[@resource-id="com.tencent.mm:id/awv"]/android.widget.RelativeLayout[' + str(        count) + ']/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]');    x, y = ele.center();    window_x, window_y = device.window_size();    if x == window_x / 2:  # 相等则是表情包        ele = device.xpath('//*[@resource-id="com.tencent.mm:id/awv"]/android.widget.RelativeLayout[' + str(            count) + "]/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]/android.widget.LinearLayout[1]/android.widget.FrameLayout[1]");        if ele.exists:            x, y = ele.center();    return x, y;"""    获取恢复内容"""def get_answer_content():    x, y = get_newest_answer();    #这里由于会有偏差,所有再取28像素的中心点    cent_x = (x + (x - 28)) / 2;    cent_y = (y + (y - 28)) / 2;    device.click(cent_x, cent_y);    time.sleep(0.1)    device.click(cent_x, cent_y);    ele = device(resourceId="com.tencent.mm:id/dc3");    text = "";    if ele.exists:        text = str(device(resourceId="com.tencent.mm:id/dc3").get_text()).strip();        # 关闭放大框        device(resourceId="com.tencent.mm:id/dc3").click();    else:        # 是不是表情包        ele = device(resourceId="com.tencent.mm:id/ei");        if ele.exists:            device(resourceId="com.tencent.mm:id/ei").click();            text = "这" \                   "是一个表情包"        else:            # 图片            device.click(x, y);            text = "这是一张图片"    return text;"""    判断是否是回复"""def is_answer():    x, y = get_newest_answer();    window_x, window_y = device.window_size();    # 如果在屏幕的左侧则是回复    if x < window_x / 2:        return True;    return False;def start():    open_chat_window();    auto_answer();if __name__ == '__main__':    start();    while True:        if is_answer():            text = get_answer_content();            print(text)            if is_right_answer(text):                break            else:                auto_answer();        #过5秒检测一下        time.sleep(5)    auto_answer("这就对了")    device.set_fastinput_ime(False)

五、效果展示

编辑

编辑


总结

        这里uiautomator2可能存在定位不准和点击过快的问题,这里就要大家自己去试了。

        刚开始学Python,写的不对的地方欢迎指正(✪ω✪)

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Python uiautomator2 微信自动化 App自动化 代码实践
相关文章