当前位置:   article > 正文

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

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

前言

欢迎来到我的博客

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

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

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

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

 环境描述

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

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

成品代码

  1. from PyAibote import AndroidBotMain
  2. import time
  3. # 2. 自定义一个脚本类,继承 AndroidBotMain
  4. class CustomAndroidScript(AndroidBotMain):
  5. #初始化配置
  6. Log_Level = "DEBUG"
  7. Log_Storage = True
  8. def start_xuexitong(self):
  9. #打开学习通,进入看课区域
  10. result = self.start_app("学习通", 5, 0.5)
  11. print("app运行状态:{}".format(result))
  12. place=self.get_element_rect("com.chaoxing.mobile/com.chaoxing.mobile:id=tabButton[3]", 15, 0.5)
  13. self.click((place))
  14. print("点击任务状态:{}".format(place))
  15. place=self.get_element_rect("com.chaoxing.mobile/com.chaoxing.mobile:id=myCourse", 15, 0.5)
  16. self.click((place))
  17. print("点击任务状态:{}".format(place))
  18. def select_class(self):
  19. #选择目标课程,并且判断是否有课程
  20. self.my_class=input("输入想要刷课的名称:")
  21. result = self.init_ocr_server("127.0.0.1", False, False, False)
  22. print("初始化状态:{}".format(result))
  23. result = self.get_text()
  24. print(result)
  25. if self.my_class in result:
  26. print("发现目标课程")
  27. result = self.find_text(self.my_class)
  28. print(result)
  29. self.click(result)
  30. time.sleep(1)
  31. def look_class(self):
  32. #观看课程
  33. self.current_class=float(input("(示例:2.3)\n输入你当前刷课进度:")) #当前的课程
  34. self.show_first_class()
  35. while True:
  36. self.cut_class()
  37. print("start look class")
  38. time.sleep(2)
  39. result = self.find_text("视频")
  40. print(result)
  41. self.click(result)
  42. time.sleep(3)
  43. self.ago_now()
  44. def ago_now(self):
  45. #判断课程是否看过
  46. result=self.find_text("任务点已完成")
  47. if result==():
  48. result = self.get_element_rect("com.chaoxing.mobile/android.widget.Button@text=播放", 5, 0.5)
  49. self.click(result)
  50. time.sleep(3)
  51. #判断是否看完
  52. i=1
  53. while i==1:
  54. time.sleep(5)
  55. outline=self.element_exists("com.chaoxing.mobile/android.widget.Button@text=重试", 1, 0.5)
  56. if outline: #判断是否断网
  57. self.click_element("com.chaoxing.mobile/android.widget.Button@text=重试", 1, 0.5)
  58. result = self.element_exists("com.chaoxing.mobile/com.chaoxing.mobile:id=start", 1, 0.5)
  59. if result: #判断是否看完
  60. self.back()
  61. time.sleep(2)
  62. result=self.find_text("任务点已完成")
  63. if result!=():
  64. break
  65. else:
  66. self.click_element("com.chaoxing.mobile/android.widget.Button@text=播放", 1, 0.5)
  67. self.back()
  68. def cut_class(self):
  69. #看完课程更替视频
  70. self.infor_dispose()
  71. while True:
  72. #匹配课程
  73. print(self.current_class)
  74. result = self.element_exists("com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
  75. print("当前课程的状态:{}".format(result))
  76. if result==True: #如果存在课程,就点击进入课程
  77. result=self.click_element("com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
  78. self.current_class += 0.1 # 转换到下一门课
  79. break
  80. else: #如果不存在,下滑一下屏幕再匹配。
  81. print("屏幕未找到对应元素,正在执行下滑操作")
  82. self.swipe((306, 1116), (306, 750), 1)
  83. result = self.element_exists(
  84. "com.chaoxing.mobile/android.widget.TextView@text={:.1f}".format(self.current_class), 5, 0.5)
  85. print("下滑后匹配元素状态:{}".format(result))
  86. if result: #如果匹配到了进入
  87. self.click_element(
  88. "com.chaoxing.mobile/android.widget.TextView@text={:.1f}".format(self.current_class), 5, 0.5)
  89. self.current_class += 0.1 # 转换到下一门课
  90. break
  91. else: #匹配不到可能是转换章节
  92. self.current_class+=1
  93. self.current_class-=(self.current_class%1)
  94. self.current_class+=0.1
  95. result = self.element_exists(
  96. "com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
  97. if result: #转换章节后匹配到
  98. self.click_element(
  99. "com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5,
  100. 0.5)
  101. self.current_class += 0.1 # 转换到下一门课
  102. break
  103. else: #匹配不到的话
  104. print("该课程已经刷完,或者程序出错。")
  105. break
  106. def show_first_class(self):
  107. #防止第一个课程不在屏幕内
  108. result = self.element_exists(
  109. "com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
  110. if result:
  111. print("初始化目标课程在屏幕内")
  112. else:
  113. for i in range(15):
  114. self.swipe((402, 1404), (402, 564), 2)
  115. result = self.element_exists(
  116. "com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 3, 0.5)
  117. if result:
  118. break
  119. def infor_dispose(self):
  120. #解决python浮点不精准问题
  121. self.current_class=round(self.current_class,2)
  122. self.current_class_1=self.current_class%0.1
  123. if self.current_class_1==0:
  124. self.current_class=round(self.current_class,1)
  125. def script_main(self):
  126. #执行函数
  127. self.start_xuexitong()
  128. self.select_class()
  129. self.look_class()
  130. if __name__ == '__main__':
  131. CustomAndroidScript.execute("0.0.0.0", 16678)

效果演示

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

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

安卓自动化演示

需求操作分析

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

开启APP

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

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

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

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

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

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

代码解刨

基本框架

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

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

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

定义进入APP的方法

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

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

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

定义选课方法

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

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

定义看课方法

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

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

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

定义滑动方法

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

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

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

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

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

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

  1. def cut_class(self):
  2. #看完课程更替视频
  3. self.infor_dispose() #自定义方法解决计算机浮点计算偏差问题
  4. while True:
  5. #匹配课程
  6. print(self.current_class)
  7. result = self.element_exists("com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
  8. print("当前课程的状态:{}".format(result))
  9. if result==True: #如果存在课程,就点击进入课程
  10. result=self.click_element("com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
  11. self.current_class += 0.1 # 转换到下一门课
  12. break
  13. else: #如果不存在,下滑一下屏幕再匹配。
  14. print("屏幕未找到对应元素,正在执行下滑操作")
  15. self.swipe((306, 1116), (306, 750), 1)
  16. result = self.element_exists(
  17. "com.chaoxing.mobile/android.widget.TextView@text={:.1f}".format(self.current_class), 5, 0.5)
  18. print("下滑后匹配元素状态:{}".format(result))
  19. if result: #如果匹配到了进入
  20. self.click_element(
  21. "com.chaoxing.mobile/android.widget.TextView@text={:.1f}".format(self.current_class), 5, 0.5)
  22. self.current_class += 0.1 # 转换到下一门课
  23. break
  24. else: #匹配不到可能是转换章节
  25. self.current_class+=1
  26. self.current_class-=(self.current_class%1)
  27. self.current_class+=0.1
  28. result = self.element_exists(
  29. "com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5, 0.5)
  30. if result: #转换章节后匹配到
  31. self.click_element(
  32. "com.chaoxing.mobile/android.widget.TextView@text={}".format(self.current_class), 5,
  33. 0.5)
  34. self.current_class += 0.1 # 转换到下一门课
  35. break
  36. else: #匹配不到的话
  37. print("该课程已经刷完,或者程序出错。")
  38. break

定义去除偏差方法

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

比如1.1+0.1=1.2000000002。

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

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

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

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

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

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

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

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

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

  1. def ago_now(self):
  2. #判断课程是否看过
  3. result=self.find_text("任务点已完成")
  4. if result==():
  5. result = self.get_element_rect("com.chaoxing.mobile/android.widget.Button@text=播放", 5, 0.5)
  6. self.click(result)
  7. time.sleep(3)
  8. #判断是否看完
  9. i=1
  10. while i==1:
  11. time.sleep(5)
  12. outline=self.element_exists("com.chaoxing.mobile/android.widget.Button@text=重试", 1, 0.5)
  13. if outline: #判断是否断网
  14. self.click_element("com.chaoxing.mobile/android.widget.Button@text=重试", 1, 0.5)
  15. result = self.element_exists("com.chaoxing.mobile/com.chaoxing.mobile:id=start", 1, 0.5)
  16. if result: #判断是否看完
  17. self.back()
  18. time.sleep(2)
  19. result=self.find_text("任务点已完成")
  20. if result!=():
  21. break
  22. else:
  23. self.click_element("com.chaoxing.mobile/android.widget.Button@text=播放", 1, 0.5)
  24. self.back()

最后组装方法

在执行方法中拼凑方法。

主要的方法是三大步骤。

进入,选课,以及刷课

  1. def script_main(self):
  2. #执行函数
  3. self.start_xuexitong()
  4. self.select_class()
  5. self.look_class()

总结

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

更新日志:

5.3:ago_now方法存在逻辑漏洞,导致看课途中有概率会弹出。已修改。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/537363
推荐阅读
相关标签
  

闽ICP备14008679号