python安卓自动化pyaibote实践------学习通自动刷课

news2024/12/23 23:45:50

前言

欢迎来到我的博客

个人主页:北岭敲键盘的荒漠猫-CSDN博客

本文是一个完成一个自动播放课程,避免人为频繁点击脚本的构思与源码。

加油!为实现全部电脑自动化办公而奋斗!

为实现摆烂躺平的人生而奋斗!!!

 环境描述

aibote,雷电模拟器,学习通,python3.12,pyaibote框架。

环境不会搭建可以看我这篇博客:pyaibote--安卓自动化环境配置与基础的使用方法_aibote链接手机-CSDN博客

成品代码

from PyAibote import AndroidBotMain
import time

# 2. 自定义一个脚本类,继承 AndroidBotMain
class CustomAndroidScript(AndroidBotMain):
    #初始化配置
    Log_Level = "DEBUG"
    Log_Storage = True
    def start_xuexitong(self):
        #打开学习通,进入看课区域
        result = self.start_app("学习通", 5, 0.5)
        print("app运行状态:{}".format(result))
        place=self.get_element_rect("com.chaoxing.mobile/com.chaoxing.mobile:id=tabButton[3]", 15, 0.5)
        self.click((place))
        print("点击任务状态:{}".format(place))
        place=self.get_element_rect("com.chaoxing.mobile/com.chaoxing.mobile:id=myCourse", 15, 0.5)
        self.click((place))
        print("点击任务状态:{}".format(place))

    def select_class(self):
        #选择目标课程,并且判断是否有课程
        self.my_class=input("输入想要刷课的名称:")
        result = self.init_ocr_server("127.0.0.1", False, False, False)
        print("初始化状态:{}".format(result))
        result = self.get_text()
        print(result)
        if self.my_class in result:
            print("发现目标课程")
            result = self.find_text(self.my_class)
            print(result)
            self.click(result)
            time.sleep(1)

    def look_class(self):
        #观看课程
        self.current_class=float(input("(示例:2.3)\n输入你当前刷课进度:")) #当前的课程
        self.show_first_class()
        while True:
            self.cut_class()
            print("start look class")
            time.sleep(2)
            result = self.find_text("视频")
            print(result)
            self.click(result)
            time.sleep(3)
            self.ago_now()

    def ago_now(self):
        #判断课程是否看过
        result=self.find_text("任务点已完成")
        if result==():
            result = self.get_element_rect("com.chaoxing.mobile/android.widget.Button@text=播放", 5, 0.5)
            self.click(result)
            time.sleep(3)
            #判断是否看完
            i=1
            while i==1:
                time.sleep(5)
                outline=self.element_exists("com.chaoxing.mobile/android.widget.Button@text=重试", 2, 0.5)
                if outline: #判断是否断网
                    self.click_element("com.chaoxing.mobile/android.widget.Button@text=重试", 2, 0.5)
                result = self.get_element_rect("com.chaoxing.mobile/com.chaoxing.mobile:id=start", 2, 0.5)
                if result!=(): #判断是否看完
                    self.click_element("com.chaoxing.mobile/com.chaoxing.mobile:id=back", 5, 0.5)
                time.sleep(2)
                result=self.find_text("任务点已完成")
                if result!=():
                    break
        self.back()

    def cut_class(self):
        #看完课程更替视频
        self.infor_dispose()
        while True:
            #匹配课程
            print(self.current_class)
            result = self.element_exists("com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
            print("当前课程的状态:{}".format(result))
            if result==True: #如果存在课程,就点击进入课程
                result=self.click_element("com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
                self.current_class += 0.1  # 转换到下一门课
                break
            else: #如果不存在,下滑一下屏幕再匹配。
                print("屏幕未找到对应元素,正在执行下滑操作")
                self.swipe((306, 1116), (306, 750), 1)
                result = self.element_exists(
                    "com.chaoxing.mobile/android.widget.TextView@text={:.1f}".format(self.current_class), 5, 0.5)
                print("下滑后匹配元素状态:{}".format(result))
                if result: #如果匹配到了进入
                    self.click_element(
                        "com.chaoxing.mobile/android.widget.TextView@text={:.1f}".format(self.current_class), 5, 0.5)
                    self.current_class += 0.1  # 转换到下一门课
                    break
                else: #匹配不到可能是转换章节
                    self.current_class+=1
                    self.current_class-=(self.current_class%1)
                    self.current_class+=0.1
                    result = self.element_exists(
                        "com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
                    if result: #转换章节后匹配到
                        self.click_element(
                            "com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5,
                            0.5)
                        self.current_class += 0.1  # 转换到下一门课
                        break
                    else: #匹配不到的话
                        print("该课程已经刷完,或者程序出错。")
                        break

    def show_first_class(self):
        #防止第一个课程不在屏幕内
        result = self.element_exists(
            "com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
        if result:
            print("初始化目标课程在屏幕内")
        else:
            for i in range(15):
                self.swipe((402, 1404), (402, 564), 2)
                result = self.element_exists(
                    "com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 3, 0.5)
                if result:
                    break

    def infor_dispose(self):
        #解决python浮点不精准问题
        self.current_class=round(self.current_class,2)
        self.current_class_1=self.current_class%0.1
        if self.current_class_1==0:
            self.current_class=round(self.current_class,1)

    def script_main(self):
        #执行函数
        self.start_xuexitong()
        self.select_class()
        self.look_class()


if __name__ == '__main__':
    CustomAndroidScript.execute("0.0.0.0", 16678)

效果演示

因为我已经刷完了,所以他点进去后,发现任务已完成就退出来进行下一节了。

他支持选择课程,定义开始课程节数,自动处理网络重连问题。

安卓自动化演示

需求操作分析

我们先来分析一下学习通刷课的操作流程。

开启APP

点击我,点击课程,然后从里面选取要刷的课。

选好课程后,我们需要选择我们要从哪节开始刷。

点进去后要点击视频切换到视频的页面

之后我们要判断这节有没有刷,刷完返回下一节,没刷就进去看。

如果看的话,还要判断好是否结束了。还要应对中途可能发生的网络异常情况。

识别到看完后,我们就要返回进入下一节以此类推

代码解刨

基本框架

首先是pyaibote的基本运行框架。

我们把要执行的代码放到script_main中。

  # 1. 导入 AndroidBotMain 类
  from PyAibote import AndroidBotMain
  import time
  
  
  
  # 2. 自定义一个脚本类,继承 AndroidBotMain
  class CustomAndroidScript(AndroidBotMain):
  
      # 2.1. 设置是否终端打印输出 DEBUG:输出, INFO:不输出, 默认打印输出
      Log_Level = "DEBUG" 
  
      # 2.2. 终端打印信息是否存储LOG文件 True: 储存, False:不存储
      Log_Storage = True  
  
  
      # 2.3. 注意:script_main 此方法是脚本执行入口必须存在此方法
      def script_main(self):
          # 显示手机最近任务列表
          result = self.recent_tasks()
          print(result)
  
  
  
  
  
  
  
  
  if __name__ == '__main__':
      # 3. 注意:此处监听的端口号,必须和手机端的脚本端口号一致
      # 3.1 监听 16678 号端口
      CustomAndroidScript.execute("0.0.0.0", 16678)

定义进入APP的方法

我们需要通过找元素,点击进入这个区域。

    def start_xuexitong(self):
        #打开学习通,进入看课区域
        result = self.start_app("学习通", 5, 0.5)
        print("app运行状态:{}".format(result))
        place=self.get_element_rect("com.chaoxing.mobile/com.chaoxing.mobile:id=tabButton[3]", 15, 0.5)
        self.click((place))
        print("点击任务状态:{}".format(place))
        place=self.get_element_rect("com.chaoxing.mobile/com.chaoxing.mobile:id=myCourse", 15, 0.5)
        self.click((place))
        print("点击任务状态:{}".format(place))

通过这个方法来点进这个课程页面。

定义选课方法

我们需要找到我们想要的课程,于是我们定义这个方法来找课程。

    def select_class(self):
        #选择目标课程,并且判断是否有课程
        self.my_class=input("输入想要刷课的名称:")
        #初始化文字识别服务
        result = self.init_ocr_server("127.0.0.1", False, False, False)
        print("初始化状态:{}".format(result))
        #查找文本
        result = self.get_text()
        print(result)
        if self.my_class in result:#如果目标课程在里面就点击进入
            print("发现目标课程")
            result = self.find_text(self.my_class)
            print(result)
            self.click(result)
            time.sleep(1)

定义看课方法

选好课程后我们总要开始刷课吧。

这个方法是用来看课相关的操作的。

    def look_class(self):
        #观看课程
        self.current_class=float(input("(示例:2.3)\n输入你当前刷课进度:")) #当前的课程
        self.show_first_class() #自定义的滑动函数(防止开始刷课的节数不在屏幕中)
        while True: #循环执行
            self.cut_class() #自定义切换方法,用来判断当前应该看哪节课,并点进去
            print("start look class")
            time.sleep(2) #防止未加载出页面就文字识别导致错误
            result = self.find_text("视频")#识别文字
            print(result)
            self.click(result) #点击视频进去视频页面
            time.sleep(3)
            self.ago_now() #自定义函数,判断这节课是否刷完

定义滑动方法

因为我们有可以自定义开始刷课节数的功能,那么我们可能会遇到这个节数不在屏幕中会下滑的情况,这个方法就是判断并且识别这种情况的。

    def show_first_class(self):
        #防止第一个课程不在屏幕内
        result = self.element_exists(
            "com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
        if result: #判断屏幕中是否有这个课程的元素
            print("初始化目标课程在屏幕内")
        else: #如果没有
            for i in range(15): #下拉寻找
                self.swipe((402, 1404), (402, 564), 2)
                result = self.element_exists(
                    "com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 3, 0.5)
                if result: #如果该目标进入了屏幕就退出循环
                    break

定义切换,判断当前课程是否刷完的方法

第一我们要点进去这节课,

第二我们还要根据他的元素text1.1这类的章节数,来找下一节课,

最后我们计算机会有浮点计算偏差,但是课程就是1.1,2.2。最后的结果不能出现偏差,所以我们要把结果转化为正确无偏差的。

    def cut_class(self):
        #看完课程更替视频
        self.infor_dispose() #自定义方法解决计算机浮点计算偏差问题
        while True:
            #匹配课程
            print(self.current_class)
            result = self.element_exists("com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
            print("当前课程的状态:{}".format(result))
            if result==True: #如果存在课程,就点击进入课程
                result=self.click_element("com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
                self.current_class += 0.1  # 转换到下一门课
                break
            else: #如果不存在,下滑一下屏幕再匹配。
                print("屏幕未找到对应元素,正在执行下滑操作")
                self.swipe((306, 1116), (306, 750), 1)
                result = self.element_exists(
                    "com.chaoxing.mobile/android.widget.TextView@text={:.1f}".format(self.current_class), 5, 0.5)
                print("下滑后匹配元素状态:{}".format(result))
                if result: #如果匹配到了进入
                    self.click_element(
                        "com.chaoxing.mobile/android.widget.TextView@text={:.1f}".format(self.current_class), 5, 0.5)
                    self.current_class += 0.1  # 转换到下一门课
                    break
                else: #匹配不到可能是转换章节
                    self.current_class+=1
                    self.current_class-=(self.current_class%1)
                    self.current_class+=0.1
                    result = self.element_exists(
                        "com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
                    if result: #转换章节后匹配到
                        self.click_element(
                            "com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5,
                            0.5)
                        self.current_class += 0.1  # 转换到下一门课
                        break
                    else: #匹配不到的话
                        print("该课程已经刷完,或者程序出错。")
                        break

定义去除偏差方法

python浮点数加减其实会有一个很小偏差。

比如1.1+0.1=1.2000000002。

但是我们下一节就是1.2这样会出错。

于是我们用下面方法来四舍五入到我们规定的格式。

保留两位小数,如果利用取余判断小数第二位是否为0。

为0保留一位,不为0保留两位。

    def infor_dispose(self):
        #解决python浮点不精准问题
        self.current_class=round(self.current_class,2)
        self.current_class_1=self.current_class%0.1
        if self.current_class_1==0:
            self.current_class=round(self.current_class,1)

定义判断这节该不该刷,以及刷完退出的方法

我们肯定不能刷刷过的课浪费大量时间,这就需要我们加一个判定。

循环前是进行判断,有没有那个任务点已完成。

后面是刷课结束以及判断是否断网。

    def ago_now(self):
        #判断课程是否看过
        result=self.find_text("任务点已完成")
        if result==():
            result = self.get_element_rect("com.chaoxing.mobile/android.widget.Button@text=播放", 5, 0.5)
            self.click(result)
            time.sleep(3)
            #判断是否看完
            i=1
            while i==1:
                time.sleep(5)
                outline=self.element_exists("com.chaoxing.mobile/android.widget.Button@text=重试", 2, 0.5)
                if outline: #判断是否断网
                    self.click_element("com.chaoxing.mobile/android.widget.Button@text=重试", 2, 0.5)
                result = self.get_element_rect("com.chaoxing.mobile/com.chaoxing.mobile:id=start", 2, 0.5)
                if result!=(): #判断是否看完
                    self.click_element("com.chaoxing.mobile/com.chaoxing.mobile:id=back", 5, 0.5)
                time.sleep(2)
                result=self.find_text("任务点已完成")
                if result!=():
                    break
        self.back()

最后组装方法

在执行方法中拼凑方法。

主要的方法是三大步骤。

进入,选课,以及刷课

    def script_main(self):
        #执行函数
        self.start_xuexitong()
        self.select_class()
        self.look_class()

总结

以上就是整个刷课脚本的实现流程与代码,可以为我点一个赞吗。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1636754.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【吊打面试官系列】Java高并发篇 - 为什么 wait 和 notify 方法要在同步块中调用?

大家好,我是锋哥。今天分享关于 【为什么 wait 和 notify 方法要在同步块中调用?】面试题,希望对大家有帮助; 为什么 wait 和 notify 方法要在同步块中调用? Java API 强制要求这样做,如果你不这么做&#…

论文精读-基于FPGA的卷积神经网络和视觉Transformer通用加速器

论文精读-基于FPGA的卷积神经网络和视觉Transformer通用加速器 优势: 1.针对CNN和Transformer提出了通用的计算映射(共用计算单元,通过不同的映射指令,指导数据通路和并行计算) 2.非线性与归一化加速单元&#xff0…

windows和mac 电脑 部署Ollama

官网地址:https://ollama.com/ github地址:https://github.com/ollama/ollama 一、windows下 https://github.com/ollama/ollama 安装大模型 ollama run llama3 下载的大模型地址: C:\Users\dengg\.ollama 4.34G

数据结构––队列

1.队列的定义 2.队列的分类 2.1循环队 2.2链式队 3.队列的实现 3.1循环队 3.1.1声明 typedef int QDataType; #define MAXSIZE 50 //定义元素的最大个数 /*循环队列的顺序存储结构*/ typedef struct {QDataType *data;int front; //头指针int rear; //尾指针 }Queue;…

YOLOv5入门(二)处理自己数据集(标签统计、数据集划分、数据增强)

上一节中我们讲到如何使用Labelimg工具标注自己的数据集,链接:YOLOv5利用Labelimg标注自己数据集,完成1658张数据集的预处理,接下来将进一步处理这批数据,通常是先划分再做数据增强。 目录 一、统计txt文件各标签类型…

第49期|GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区,集成了生成预训练Transformer(GPT)、人工智能生成内容(AIGC)以及大语言模型(LLM)等安全领域应用的知识。在这里,您可以找…

【华为 ICT HCIA eNSP 习题汇总】——题目集19

1、(多选)以下选项中,FTP 常用文件传输类型有()。 A、ASCII 码类型 B、二进制类型 C、EBCDIC 类型 D、本地类型 考点:应用层 解析:(AB) 文件传输协议(FTP&…

Redis源码学习记录:列表 (ziplist)

ziplist redis 源码版本&#xff1a;6.0.9。ziplist 的代码均在 ziplist.c / ziplist.h 文件中。 定义 ziplist总体布局如下&#xff1a; <zlbytes> <zltail> <zllen> <entry> <entry> ... <entry> <zlend> zlbytes&#xff1a;uin…

Linux 的静态库和动态库

本文目录 一、静态库1. 创建静态库2. 静态库的使用 二、动态库1. 为什么要引入动态库呢&#xff1f;2. 创建动态库3. 动态库的使用4. 查看可执行文件依赖的动态库 一、静态库 在编译程序的链接阶段&#xff0c;会将源码汇编生成的目标文件.o与引用到的库&#xff08;包括静态库…

2024小米SU7首批锁单用户调研报告

来源&#xff1a;电动汽车用户联盟 80%的锁单用户认为自己是米粉&#xff0c;64%的用户拥有10个以上米家生态产品&#xff0c; 使用小米手机的比例为67%&#xff0c;使用苹果手机的比例为47% 2. 81%的用户为90后&#xff0c;均龄31岁&#xff0c;未婚者和已婚无孩者占比63%&am…

接口测试 - postman

文章目录 一、接口1.接口的类型2. 接口测试3. 接口测试流程4. 接口测试用例1. 测试用例单接口测试用例-登录案例 二、HTTP协议1. HTTP请求2. HTTP响应 三、postman1. 界面导航说明导入 导出用例集 Get请求和Post请求的区别:2.postman环境变量和全局变量3. postman 请求前置脚本…

Java微服务分布式分库分表ShardingSphere - ShardingSphere-JDBC

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 往期热门专栏回顾 专栏…

【算法刷题 | 贪心算法05】4.27(K次取反后最大化的数组和、加油站)

文章目录 8.K次取反后最大化的数组和8.1题目8.2解法&#xff1a;贪心8.2.1贪心思路8.2.2代码实现 9.加油站9.1题目9.2解法&#xff1a;贪心9.2.1贪心思路9.2.2代码实现 8.K次取反后最大化的数组和 8.1题目 给你一个整数数组 nums 和一个整数 k &#xff0c;按以下方法修改该数…

基于EBAZ4205矿板的图像处理:03使用VIO调试输出HDMI视频图像

基于EBAZ4205矿板的图像处理&#xff1a;03使用VIO调试输出HDMI视频图像 在zynq调试时VIO是真的方便&#xff0c;特此写一篇博客记录一下 先看效果 项目简介 下面是我的BD设计&#xff0c;vtc用于生成时序&#xff0c;注意&#xff0c;2021.2的vivado的vtcIP是v6.2版本&…

【算法】【贪心算法】【leetcode】870. 优势洗牌

题目地址&#xff1a;https://leetcode.cn/problems/advantage-shuffle/description/ 题目描述&#xff1a; 给定两个长度相等的数组 nums1 和 nums2&#xff0c;nums1 相对于 nums2 的优势可以用满足 nums1[i] > nums2[i] 的索引 i 的数目来描述。 返回 nums1 的任意排列&…

C++入门基础(二)

目录 缺省参数缺省参数概念缺省参数分类全缺省参数半缺省参数声明与定义分离 缺省参数的应用 函数重载函数重载概念例子1 参数类型不同例子2 参数的个数不同例子3 参数的顺序不同 C支持函数重载的原理--名字修饰(name Mangling) 感谢各位大佬对我的支持,如果我的文章对你有用,欢…

nginx+Tomcat动静分离

本⽂的动静分离主要是通过nginxtomcat来实现&#xff0c;其中nginx处理图⽚、html等静态的⽂ 件&#xff0c;tomcat处理jsp、do等动态⽂件. 实验环境 192.168.200.133 nginx反向代理 192.168.200.129 static 192.168.200.130 dynamic 步骤 修改三台主机名 [rootadmin ~]#…

《Redis使用手册之列表》

《Redis使用手册之列表》 目录 **《Redis使用手册之列表》****LPUSH&#xff1a;将元素推入列表左端****LPUSHX、RPUSHX&#xff1a;只对已存在的列表执行推入操作****LPOP&#xff1a;弹出列表最左端的元素****RPOP&#xff1a;弹出列表最右端的元素****RPOPLPUSH&#xff1a;…

【C语言刷题系列】删除公共元素

目录 一、问题描述 二、解题思路 三、源代码实现 解决方案一&#xff1a;拷贝到临时数组 解决方案二&#xff1a;直接打印 个人主页&#xff1a; 倔强的石头的博客 系列专栏 &#xff1a;C语言指南 C语言刷题系列 一、问题描述 二、解题思路 第一种方法&…

线上告警炸锅!FastJson 又立功了。。

前段时间新增一个特别简单的功能&#xff0c;晚上上线前review代码时想到公司拼搏进取的价值观临时加一行log日志&#xff0c;觉得就一行简单的日志基本上没啥问题&#xff0c;结果刚上完线后一堆报警&#xff0c;赶紧回滚了代码&#xff0c;找到问题删除了添加日志的代码&…