学习强国手机助手

前景:

        用手机刷学习强国时要一直盯着手机,总感觉费时费劲,刚好最近学习python写个小工具帮忙自动学习,实现了文章和视频学习,答题类不一定都能正确。上班时电脑连着USB就可以放那,自己可以上班干自己事情。

开发工具:

AirtestIDE:负责获取界面元素,poco远程解析控制手机

pycharm:负责写python逻辑,pyqt5负责界面显示日志

工具界面:

开发条件:

        Android手机,打开USB调试,第一次运行允许安装pocoservice

处理逻辑代码:

from PyQt5.QtCore import QThread, pyqtSignal
from poco.drivers.android.uiautomation import AndroidUiautomationPoco
from airtest.core.api import *
import subprocess
import redef is_in_array(array, element):for item in array:if item == element:return Truereturn False# 定义一个线程类
class QCtrlThread(QThread):# 成员read_done_tile = []  # 已读文章或视频log_signal = pyqtSignal(str)# 初始化def __init__(self, parent=None):super(QCtrlThread, self).__init__(parent)print("QCtrlThread init")# run函数是子线程中的操作,线程启动后开始执行def run(self):self.log_signal.emit("开始学习")poco = AndroidUiautomationPoco(use_airtest_input=True, screenshot_each_action=False)poco.device.wake()start_app("cn.xuexi.android")sleep(2)self.get_score(poco)self.log_signal.emit("学习结束。。。")def connect_android(self):# 执行命令print("connect_android")cur_path = os.path.abspath('.')print(cur_path)run_airtest_path = cur_path + "\\airtest"cmd = r'"{}" devices'.format(run_airtest_path + '\\core\\android\\static\\adb\\windows\\adb.exe')print(cmd)if os.path.exists(run_airtest_path):p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)else:p = subprocess.Popen('adb devices', stdout=subprocess.PIPE, shell=True)# 获取输出结果output, err = p.communicate()# 处理输出结果output_str = output.decode('utf-8')print(output_str)device_list = output_str.split("\n")device_name = ""for i in range(0, len(device_list)):device_txt = device_list[i]if device_txt.find("List of devices attached") >= 0:continueprint(device_txt)if device_txt.find("device") > 0:device_split = device_txt.split("	")device_name = device_split[0]print("cmd result:", device_name)breakif len(device_name) < 8:self.log_signal.emit("设备未查找到,请连接设备,确认开发者选项-USB调试已打开")return Falsedevice_url = "Android://127.0.0.1:5037/" + device_nameself.log_signal.emit("开始连接手机设备名称:" + device_url)connect_device(device_url)return Truedef operate(self, poco):cnt_score = 0  # 得分计数list_view = poco("android.widget.FrameLayout").child("androidx.recyclerview.widget.RecyclerView").child("android.widget.FrameLayout")print("当前界面展示项:", len(list_view))for i in range(0, len(list_view)):title_view = list_view[i].offspring("cn.xuexi.android:id/general_card_title_id")if title_view.exists() is True:title_txt = title_view.get_text()self.log_signal.emit("标题:" + title_txt)if is_in_array(self.read_done_tile, title_txt) is False:  # 未读title_view.focus([0.5, 0.5]).click()sleep(1)#  开始点击音频|视频新闻self.play(poco)cnt_score += 2self.read_done_tile.append(title_txt)list_view.swipe([0, -0.5])  # 滑动return cnt_scoredef play(self, poco):self.log_signal.emit("开始视频|文章学习")#  电视if poco(name="cn.xuexi.android:id/EXTRA_INFO_LAYER_VIEW_ID"):self.log_signal.emit("开始播放视频")if poco(text="继续播放"):poco(text="继续播放").focus([0.5, 0.5]).click()while 1:if poco(text="重新播放"):breakelse:sleep(1)#  返回poco(name="cn.xuexi.android:id/EXTRA_INFO_LAYER_VIEW_ID").child("android.widget.FrameLayout")[1].child("android.widget.FrameLayout")[2].child("android.widget.ImageView").focus([0.5, 0.5]).click()else:#  文章self.log_signal.emit("开始阅读")if poco("android.widget.Button"):poco("android.widget.Button").focus([0.5, 0.5]).click()# 获取播放时间arr_view = poco("android.widget.Button").parent().child("android.view.View")#  print(len(arr_view))if len(arr_view) > 2:str_time = arr_view[2].get_text()self.log_signal.emit("时长:" + str_time)split_time = str_time.split(":")int_time = int(split_time[0]) * 60 + int(split_time[1])print("时长秒:" + str(int_time))sleep(int_time)else:# self.log_signal.emit("开始播报")# if poco(name="play-0"):#     poco(name="play-0").focus([0.5, 0.5]).clicked()# else:article_body = poco(name="xxqg-article-body")for t in range(0, 30):if article_body:article_body.swipe([0, -0.1])sleep(1)self.log_signal.emit("阅读完毕")#  返回if poco(name="cn.xuexi.android:id/TOP_LAYER_VIEW_ID"):poco(name="cn.xuexi.android:id/TOP_LAYER_VIEW_ID").child("android.widget.ImageView").focus([0.5, 0.5]).click()sleep(1)def answer(self, poco):if poco("com.uc.webview.export.WebView").exists() is False:return Falsewhile 1:if poco(name="返回"):poco(name="返回").click()break# 查看提示tips_content = ""if poco(text="查看提示"):poco(text="查看提示").focus([0.5, 0.5]).click()sleep(1)if poco(text="提示"):tips_view = poco(text="提示").parent().parent().child("android.view.View")tips_content = tips_view[1].child("android.view.View").get_text()self.log_signal.emit("提示:\n" + tips_content)tips_head = poco(text="提示").parent().child("android.view.View")tips_head[0].focus([0.5, 0.5]).click()  # 关闭提示sleep(0.5)else:article_body.swipe([0, -0.5])sleep(1)continue#  self.log_signal.emit("开始答题")if poco("android.widget.EditText"):self.log_signal.emit("填空题")if poco("android.widget.EditText"):new_content = poco("android.widget.EditText").parent().parent().child("android.view.View")edit_views = poco("android.widget.EditText").parent().child("android.view.View")  # 需要填入的项if edit_views.exists() is True:self.log_signal.emit("需要填入字数:", len(edit_views))if tips_content == "请观看视频":  # 随便选一个self.log_signal.emit("请观看视频")else:for i in range(0, len(new_content)):print(new_content[i].get_text())if len(new_content) > 1:  # 最后一段last_part_txt = new_content[len(new_content) - 1].get_text()key_txt = last_part_txt[0:4]index = tips_content.find(key_txt)if index != -1:print("填入:", tips_content[index: -1])print("填入:", tips_content[index: -2])else:self.log_signal.emit("解析错误")if poco("android.widget.ListView"):self.log_signal.emit("选择题")items = ["A.", "B.", "C.", "D.", "E."]# items_value = []is_select = Falsefor i in range(0, len(items)):  # 获取选题内容if poco(text=items[i]):item = poco(text=items[i]).parent().child("android.view.View")item_txt = item[1].get_text()self.log_signal.emit(items[i] + ":" + item_txt)if item_txt.find("正确") == 0:self.log_signal.emit("主观判断题,都判正确")poco(text=items[i]).focus([0.5, 0.5]).click()breakelse:items_value = item[1].get_text()is_sub = items_value in tips_contentif is_sub is True:self.log_signal.emit("选中:" + items[i])poco(text=items[i]).focus([0.5, 0.5]).click()is_select = Trueif poco(text="单选题"):breakelse:if tips_content == "请观看视频":  # 随便选一个poco(text=items[i]).focus([0.5, 0.5]).click()breakif poco(text="单选题") and is_select is False:poco(text=items[0]).focus([0.5, 0.5]).click()  # 默认选中第一个if poco(text="确定"):poco(text="确定").focus([0.5, 0.5]).click()sleep(1)if poco(text="下一题"):poco(text="下一题").focus([0.5, 0.5]).click()sleep(1)def get_score(self, poco):self.log_signal.emit("开始查找得分")if poco(name="cn.xuexi.android:id/comm_head_xuexi_score"):str_score = poco(name="cn.xuexi.android:id/comm_head_xuexi_score").get_text()self.log_signal.emit("得分:" + str_score)poco(name="cn.xuexi.android:id/comm_head_xuexi_score").click()sleep(2)if poco(text="学习积分"):list_class = ["我要选读文章", "我要视听学习", "每日答题"]for i in range(0, len(list_class)):print("开始学习:", list_class[i])read_news_label = poco(text=list_class[i])if read_news_label:read_news_label.swipe([0, 0.2])  # 滑动一下防止最后一项没显示sleep(1)read_news_views = read_news_label.parent().child("android.widget.TextView")print("read_news_views length:", len(read_news_views))if read_news_label.parent().child(name="去看看"):read_news_label.parent().child(name="去看看").click()  # 进入得分sleep(1)news_score_cnt = 0while 1:try:if list_class[i] == "每日答题":news_score_cnt += self.answer(poco)read_news_label.swipe([0, -0.2])  # 滑动一下防止最后一项没显示else:news_score_cnt += self.operate(poco)if news_score_cnt >= 2:breakexcept:self.log_signal.emit("解析异常")self.get_score(poco)else:self.log_signal.emit("界面不对,请回到主页面")

界面代码:

from MainWindow import *
from ctrlThread import QCtrlThread
from PyQt5.QtWidgets import QMainWindowclass XUEXIWindow(QMainWindow, Ui_MainWindow):def __init__(self, parent=None):super(XUEXIWindow, self).__init__(parent)self.setupUi(self)# 绑定按钮点击事件self.btn_start.clicked.connect(self.start)self.btn_connenct.clicked.connect(self.connect_device)self.thread = QCtrlThread()  # 实例化一个线程self.thread.log_signal.connect(self.change_log)def start(self):print('Start clicked')# 启动线程,执行线程类中run函数if self.thread.isRunning():self.textEdit.append("正在学习中...")returnself.thread.start()def connect_device(self):print("开始连接设备")self.thread.connect_android()def change_log(self, msg):print("log:", msg)self.textEdit.append(str(msg))

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

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

相关文章

IDEA中git的常用操作(保姆级教学)

IDEA中git的常用操作&#xff08;保姆级教学&#xff09; 以下是git的工作原理&#xff0c;觉得繁琐的可以跳过不看 Workspace&#xff1a;工作区 (平时存放代码的地方) Index / Stage&#xff1a;暂存区&#xff08;用于临时存放存放你的改动&#xff0c;事实上就是一个文件&…

SemCity: 一个应用于真实户外环境场景生成的3D Diffusion模型

论文标题&#xff1a; SemCity: Semantic Scene Generation with Triplane Diffusion 论文作者&#xff1a; Jumin Lee1, Sebin Lee1, Changho Jo, Woobin Im, Juhyeong Seon, Sung-Eui Yoon 项目地址&#xff1a;https://sglab.kaist.ac.kr/SemCity/ 前言&#xff1a; 该论…

JVM笔记-常用命令

1、jstat jstat是一个极强的监视JVM的工具&#xff0c;可以用来监视JVM的各种堆和非堆的大小以及内存使用量。 Usage: jstat -help|-optionsjstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]jstat的常用用法如图所示&#xff…

maven-test不通过导致无法打包

背景 别人写的一个test包&#xff0c;没有测试通过&#xff0c;导致最后没有打包成功 解决方案 package生命周中不要勾选test

《我的医养信息化之路》之三十三:健康保养“4S”店

最近早上起来肩部的骨头出现酸痛&#xff0c;不由得有点感慨岁月不饶人。我已经感觉到年近50岁各种器官的衰退&#xff0c;从30岁开始我就慢慢感觉到一点点的变化。年龄老化导致的系统整体功能水平低下&#xff0c;从而产生各种器质性慢性病症。因此&#xff0c;系统功能低下才…

Swagger使用和注释介绍

一&#xff1a;介绍 1、什么是Swagger Swagger是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法&#xff0c;参数和模型紧密集成到服务器端的代码&#xff…

GPU术语

可向量化循环 可向量化循环通常是指在编程中&#xff0c;能够被转换为向量操作或矩阵运算的循环结构。 在传统编程中&#xff0c;对于数组或向量中的每个元素执行相同的操作时&#xff0c;开发者可能会使用for循环逐一进行处理。然而&#xff0c;许多现代编程语言和库提供了向…

在做题中学习(50):搜索插入位置

35. 搜索插入位置 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a;二分查找 思路&#xff1a;题目是有序的&#xff0c;时间复杂度O(logN),二分没跑了&#xff0c;题目说如果找不到target&#xff0c;返回它应该被插入位置的下标&#xff0c;所以可以分析一下示例2…

零基础代码随想录【Day27】|| 39. 组合总和,40.组合总和II, 131.分割回文串

目录 DAY27 39. 组合总和 解题思路&代码 40.组合总和II 解题思路&代码 131.分割回文串 解题思路&代码 DAY27 39. 组合总和 力扣题目链接(opens new window) 给定一个无重复元素的数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有…

如果你作 为Java程序员曾经遭遇过NullPointerException,请举起手

如果你作 为Java程序员曾经遭遇过NullPointerException&#xff0c;请举起手 1.让Optional发光发热&#xff1a;去除代码中对null的检查&#xff0c; 采用防御式检查减少NullPointerException java8实战 书籍 第225页 免费下载链接&#xff1a; https://pan.quark.cn/s/5cf68…

STM32:配置EXTI—对射式红外传感器计次

文章目录 1、中断1.2 中断系统1.3 中断执行流程 2、STM32中断2.2EXTI&#xff08;外部中断&#xff09;2.3 EXTI 的基本结构2.4 AFIO复用IO口 3、NVIC基本结构3.2 NVIC优先级分组 4、配置EXTI4.2 AFIO 库函数4.3 EXTI 库函数4.4 NVIC 库函数4.5 配置EXTI的步骤4.6 初始化EXTI 1…

自动装车系统中激光雷达如何应对复杂环境

自动装车系统中激光雷达的稳定运行策略 在自动装车系统的设计和实施中&#xff0c;激光雷达作为核心传感器之一&#xff0c;其性能和准确性直接关系到整个系统的稳定性和工作效率。然而&#xff0c;实际运行中的现场环境往往复杂多变&#xff0c;对激光雷达的稳定运行构成一定…

[AI OpenAI-doc] 迁移指南 Beta

我们已经改变了助手 API 在 beta 的 v1 版本和 v2 版本之间工具和文件的工作方式。今天&#xff0c;通过 API&#xff0c;两个 beta 版本仍然可以访问&#xff0c;但我们建议尽快迁移到我们 API 的最新版本。我们将在 2024 年底之前废弃 beta 的 v1 版本。 如果您今天不使用助手…

华人团队用大模型实现“读心术”:大脑活动直接变文字

NeurIPS收录的一项新研究&#xff0c;让大模型也学会“读心术”了&#xff01; 通过学习脑电波数据&#xff0c;模型成功地把受试者的脑电图信号翻译成了文本。 而且整个过程不需要大型设备&#xff0c;只要一块特制的“头巾”就能实现。 这项成果名为DeWave&#xff0c;能在…

鸿蒙内核源码分析(时间管理篇) | 谁是内核基本时间单位

时间概念太重要了&#xff0c;在鸿蒙内核又是如何管理和使用时间的呢? 时间管理以系统时钟 g_sysClock 为基础&#xff0c;给应用程序提供所有和时间有关的服务。 用户以秒、毫秒为单位计时.操作系统以Tick为单位计时&#xff0c;这个认识很重要. 每秒的tick大小很大程度上决…

解决 git克隆拉取代码报SSL certificate problem错误

问题&#xff1a;拉取代码时报错&#xff0c;SSL证书问题:证书链中的自签名证书问题 解决&#xff1a;只需要关闭证书验证&#xff0c;执行下面代码即可&#xff1a; git config --global http.sslVerify "false" 再次拉取代码就可以了

STC89C52驱动XPT2046AD转换

目录 简介封装接线&#xff08;单端&#xff09;时序以及命令字SPI时序命令字 程序XPT2046.CXPT2046.hmain.c测试 简介 XPT2046是一款4线电阻式触摸屏控制器&#xff0c;采用12位125 kHz采样SAR类型A / D转换器。XPT2046工作电压低至2.2V&#xff0c;支持1.5V至VCC的数字I/O接…

暗区突围服务器连接失败/网络异常/无法连接下载解决方法

暗区突围是一款仿真战场的模拟&#xff0c;首要介绍的自然是游戏中基本都会参与的模式&#xff0c;叫做战术行动&#xff0c;大家参与其中是会作为特遣队员的身份来做任务&#xff0c;面临的是一个全面自给自足的战场环境&#xff0c;这种模式要求玩家在进入暗区之前自行筹备所…

Jmeter 中 CSV 如何参数化测试数据并实现自动断言

当我们使用Jmeter工具进行接口测试&#xff0c;可利用CSV Data Set Config配置元件&#xff0c;对测试数据进行参数化&#xff0c;循环读取csv文档中每一行测试用例数据&#xff0c;来实现接口自动化。此种情况下&#xff0c;很多测试工程师只会人工地查看响应结果来判断用例是…

PC小程序解密及反编译

一、小程序包解密 小程序原始加密包位置C:\Users\administrator\Documents\WeChat Files\Applet\wx234324324324 二、wxappUnpacker反编译 npm install./bingo D:\temp\小程序包解密\wxpack\wx234324324324.wxapkg 三、查看反编译后的文件