Python-Appium自动化测试-学习通自动刷视频(1)

【仅供交流学习使用,转载请注明出处】
真的仅供交流学习使用…

准备

准备工具:windows系统,python编译器,selenium包,pythonIDE(推荐jupyter notebook,笔者使用的是pycharm),appium,模拟器(笔者使用的是nox),Android SDK,java JDK 网上有很多安装教程,这里笔者就不赘述了
【连真机也可以,但是炸了就不好玩了(滑稽)】
【小提示:安装selenium失败请加源,为方便读者---->清华源:https://pypi.tuna.tsinghua.edu.cn/simple】
安装完成后打开模拟器,在命令行中输入

adb connect 127.0.0.1:62001

这里说明一下,端口号一定要对齐,否则就会连接不上
夜神模拟器默认端口是62001,其他端口都以620开头,至于其他模拟器端口网上都可以查到
如果你增添了模拟器那么你要连接的就不一定是62001了,端口号可以通过以下代码查看:

netstat -ano |findstr 620

然后我们在appium上开启服务(记下端口号默认是4723)
ok,一切就绪准备开始吧
首先我们在Nox上安装学习通
打开cmd(或shell),输入:

adb shell

然后在打开学习通瞬间在adb shell中输入并回车:

dumpsys activity | grep mFocusedActivity

如果你多试几次,结果应该如下:

C:\Users\Administrator>adb shell
R17:/ # dumpsys activity | grep mFocusedActivity
  mFocusedActivity: ActivityRecord{e2f77e8 u0 com.vphone.launcher/.Launcher t2}
R17:/ # dumpsys activity | grep mFocusedActivity
  mFocusedActivity: ActivityRecord{add4c1c u0 com.chaoxing.mobile/.activity.SplashActivity t21}
R17:/ # dumpsys activity | grep mFocusedActivity
  mFocusedActivity: ActivityRecord{9b9f64e u0 com.chaoxing.mobile/.activity.DoodleActivity t21}
R17:/ # dumpsys activity | grep mFocusedActivity
  mFocusedActivity: ActivityRecord{8c0765f u0 com.chaoxing.mobile/.main.ui.MainTabActivity t21}
R17:/ #

第一个是还没打开,第二个是学习通app的发起入口,第三个是广告界面,第四个就是主界面了,这里我们只需要第二个。
其中com.chaoxing.mobile代表学习通app
.activity.SplashActivity代表打开的动作。
然后我们就可以在IDE中及其快(tong)乐(ku)地coding了
引入库:

from appium import webdriver
from time import sleep
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from appium.webdriver.common.touch_action import TouchAction

设置帽子:

desired_caps = {
    "platformName": "Android",                    # 这个就不解释了
    "platformVersion": "7.1.2",                   # 安卓系统版本号
    "deviceName": "127.0.0.1:62025",              # 默认是安卓5,笔者选了安卓7后端口号发生改变
    "newCommandTimeout": "60000",                 # 设置多少秒后停止,防止它突然暴毙
    "appPackage": "com.chaoxing.mobile",          # 谁:学习通的"名字" 
    "appActivity": ".activity.SplashActivity",	  # 动作:打开它
    "noReset": "True"                             # 是否缓存,为了防止每次登录都要输一遍密码就开缓存
}

然后我们执行上面的帽子:

def cx_open():
    driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
    print("打开超星APP啦!")
    return driver
cx_driver = cx_open()

笔者使用cx_driver代指打开超星学习通,之后的操作我们也围绕着它进行

思路

首先我们理一下思路,如何实现自动化
通常我们去看学习通中的一个视频的流程是这样的:

  • 打开学习通
  • 点击“我”进入我的主页
  • 点击课程
  • 选择哪一门课
  • 点击章节【弹出来一个课程的列表】
  • 点击第一个
  • 看视频【任务点完成】
  • 退出
  • 点击下一个

  • 好,我们也按照这个思路来

开始

前面我们已经打开了学习通app,下面我们就定义一个操作学习通的类

class CxAuto:
	def __init__(self):                     # 定义类的"全局"变量
		pass
	def start_point_me(self):               # 点击我
		pass
	def start_point_class(self):            # 点击课程
		pass
	def start_point_course(self): 			# 点击具体哪一门课
		pass
	def start_point_course_section(self):	# 点击章节
		pass
	def start_main_circullation(self): 		# 不停地刷视频
		pass

好,以上是一个粗略的框架

我们需要一个值来确定到底是哪一门课,而这个值可以由用户指定,如此我们可以把类的定义函数写出来:
    def __init__(self, course_index):
        self.course_index = course_index 							# 指定课程的下标,如何使用见下文
        self.screenWidth = cx_driver.get_window_size()["width"]     # 用于以后滑屏
        self.screenHeight = cx_driver.get_window_size()["height"]

然后我们打开appium,点击appium中类似放大镜的按钮,即Start Inspector session,将以上的帽子输入并保存,然后运行,此时你会看到超星学习通又被打开一次,appium会弹出一个界面,这是用来帮助定位的。

app中的定位和网页类似,可以通过xpath和id进行定位
我们首先要做的就是等待"我"这个元素加载出来然后点击它,因为以后也会用到,我们就在类中先把判断元素是否存在和等待元素加载的函数做出来,代码如下:
    def is_element_xpath_exist(self, x_path):  # 判断某xpath下的元素是否存在
        if cx_driver.find_elements_by_xpath(x_path) == []:
            return False
        else:
            return True

    def is_element_id_exist(self, x_id):  # 判断某id下的元素是否存在
        if cx_driver.find_elements_by_id(x_id) == []:
            return False
        else:
            return True

    def wait_element_by_xpath(self, x_path, sleep_time): # 等待某xpath元素出现
        while True:
            try:										 # 有时候这里等着等着连接就断了,需要try
                while self.is_element_xpath_exist(x_path=x_path):
                    return True
                else:
                    print("等待中...")
                    sleep(int(sleep_time))
            except Exception as e:
                print(e)

    def wait_element_by_id(self, x_id, sleep_time): # 等待某id元素出现
        while True:
            try:
                while self.is_element_id_exist(x_id=x_id):
                    return True
                else:
                    print("等待中...")
                    sleep(int(sleep_time))
            except Exception as e:
                print(e)
在有工具函数的支持下我们很容易就可以写出点击"我"的函数:
    def start_point_me(self):
        # 点击我
        wo_xpath = "//android.widget.RelativeLayout[4]"
        if self.wait_element_by_xpath(wo_xpath, 5):
            WebDriverWait(cx_driver, 20).until(EC.element_to_be_clickable((By.XPATH, wo_xpath)),
                                               message='timeout').click()
            print("看看我的主页~")  # 这行请忽略(捂脸~)
依样画葫芦,我们同时也可以很容易写出其他的点击函数,并且开头都冠以start_point的前缀标识:
    def start_point_class(self):
        # 点击课程
        course_xpath = "com.chaoxing.mobile:id/myCourse"
        if self.wait_element_by_id(course_xpath, 5):
            WebDriverWait(cx_driver, 20).until(EC.element_to_be_clickable((By.ID, course_xpath)),
                                               message='timeout').click()
            print("看看我的课程~")

    def start_point_course(self):
        # 点击具体课程
        course_xpath = "//android.widget.RelativeLayout/android.support.v7.widget.RecyclerView/android.widget.FrameLayout[%s]" % self.course_index
        if self.wait_element_by_xpath(course_xpath, 5):
            WebDriverWait(cx_driver, 10).until(EC.element_to_be_clickable((By.XPATH, course_xpath)),
                                               message='timeout').click()
            print("打开课程,开始了哦")

    def start_point_course_section(self):
        # 点击章节所在页
        class_page_xpath = "//android.widget.LinearLayout[1]/android.widget.FrameLayout[2]/android.widget.TextView"
        if self.wait_element_by_xpath(class_page_xpath, 5):
            WebDriverWait(cx_driver, 10).until(EC.element_to_be_clickable((By.XPATH, class_page_xpath)),
                                               message='timeout').click()

接下来我们就要写刷视频的核心代码了,可以肯定它是一个循环,虽然不知道是否有什么其他情况

我们还是可以把大概框架写出来:
    def start_main_circullation(self):
        class_list_xpath = "//android.widget.RelativeLayout/android.support.v7.widget.RecyclerView/android.widget.RelativeLayout"
        # 返回键的id
        back_id = "com.chaoxing.mobile:id/iv_chapter_back"
        # 设置主循环变量
        m = 1
        # 设置开始变量  如果用户有需求可以从某节开始,因代码较少,功能较次,为读者看的清楚就不放出来了
        k = 0
        # 主循环
        while m:
            num = len(cx_driver.find_elements_by_xpath(class_list_xpath)) - 1
            print("准备!")
            # 设置B循环变量
            n = 1
            # 设置已爬取列表(防止看了一遍,又去看一遍)
            curScreenItemSet = []
            # B循环:单页爬虫核心循环,去头去尾(手机中通常有卡一半的按钮,这个我们就不要了)
            while n < num:
            	pass   						 # 待完善
            # 滑动,下一页
            cx_driver.swipe(self.screenWidth * 0.5, self.screenHeight * 0.65, self.screenWidth * 0.5,
                            self.screenHeight * 0.25, 500)
            sleep(0.5)
好了,下面我们的任务是把单页循环给写出来,以下是大致框架:
            while n < num:
                try:
                    # 爬取当前页面
                    ls = self.cx_crawl_main_list(class_list_xpath)
                    # 取页面第n个小节
                    sleep(0.5)
                    identification = ls[n].find_element_by_id("com.chaoxing.mobile:id/tv_sub_index").get_attribute(
                        'text')
                    print("看看课程%s.^v^." % identification)
                    # 该小节的一系列操作
                    if identification not in curScreenItemSet:
                        print("欸~  这个可以!")
                        pass # 劈里啪啦一顿操作就把这个看完了
                        #返回列表的代码放到看视频完成的地方,这样可以避免很多麻烦
                        

这里有个获取列表的函数,就是把当前页面上的元素装进列表里,每点进去一次该列表指向就会发生改变,通俗地说就是失效,这时我们必须重新获取,也是将它写成函数的重要原因,具体代码如下:

获取列表函数:
    def cx_crawl_main_list(self, class_list_xpath):
        print("让我再看看列表,没看仔细,5~")
        WebDriverWait(cx_driver, 20).until(EC.element_to_be_clickable((By.XPATH, class_list_xpath)),
                                           message='timeout')
        sleep(1)
        ls = cx_driver.find_elements_by_xpath(class_list_xpath)
        return ls
再下面,我们的任务是把对单个小节操作的代码写出来,也就是那个劈里啪啦一顿的操作:
                    if identification not in curScreenItemSet:
                        print("欸~  这个可以!")
                        # 点进去
                        self.cx_crawl_point_in(n)
                        try:
                            print("等它加载一下")
                            top_title_xpath = "com.chaoxing.mobile:id/tv_chapter_name"
                            self.wait_element_by_id(top_title_xpath, 5)
                            # 查是否空白页
                            if self.cx_crawl_is_white(back_id):
                                curScreenItemSet.append(identification)
                                n += 1
                                continue
                            # 确定视频位置
                            self.cx_crawl_vedio_where()
                            temporary_xpath = "//android.webkit.WebView/android.webkit.WebView/android.view.View"
                            self.wait_element_by_xpath(temporary_xpath, 5)
                            print("稍微等等,我怕没加载完^x^")
                            # 判断是否已完成
                            if self.cx_crawl_is_finish():
                                curScreenItemSet.append(identification)
                                n += 1
                                continue
                            print("开始播放了哦~")
                            if self.cx_crawl_vedio_play():
                                curScreenItemSet.append(identification)
                                n += 1
                        except Exception as e:
                            print(e)
                    else:
                        print("这个看过了哦~")

这里面我用了很多未定义函数,为的就是理清思路【其实只是为了好看(时而滑稽之)】
下面我们对每一个函数冠以cx_crawl的前缀进行定义:

点进去函数:
    def cx_crawl_point_in(self, n):
   	    #这里注意下标,具体的可以根据appium来定位和寻找下表规律
        WebDriverWait(cx_driver, 20).until(EC.element_to_be_clickable(
            (By.XPATH,
             "//android.widget.RelativeLayout/android.support.v7.widget.RecyclerView/android.widget.RelativeLayout[{}]".format(
                 n + 1))),
            message='timeout').click()
查看是否空白页函数:
    def cx_crawl_is_white(self, back_id):
      					# 空页处理
        white_xpath = "//android.support.v4.view.ViewPager/android.widget.RelativeLayout/android.widget.TextView"
        white_con_xpath = "//android.webkit.WebView/android.webkit.WebView/android.view.View[1]"
        				# 等它加载一下
        V4_id = "com.chaoxing.mobile:id/vp_chapter"
        self.wait_element_by_id(V4_id, 3)
        sleep(2)
        				#空页有两种形式,需要分别看
        p = self.is_element_xpath_exist(white_xpath)
        q = "暂无内容" in cx_driver.find_element_by_xpath(white_con_xpath).get_attribute(
            "text") if self.is_element_xpath_exist(white_con_xpath) else 1
        				# 如果一旦出现了一种形式的空页说明它就是空页
        if p or q:
            print("这个居然是空 白 页,天哪,快回快回@x@")

            WebDriverWait(cx_driver, 10).until(EC.element_to_be_clickable((By.ID, back_id)),
                                               message='timeout').click()
            sleep(0.5)
            return 1
        # 如果不是以上两种情况,代表那没事了
        return 0

确定视频位置函数,这个有很多种情况,见下:

  • 压根就没标题,视频就在眼前
  • 每一单元的第一个小节基本是3到4个标题
  • 其他的有两个标题,视频在第一个标题
于是写确定视频位置函数如下:
    def cx_crawl_vedio_where(self):
        title_id = "com.chaoxing.mobile:id/tb_chapter"
        title_xpath = "//android.widget.LinearLayout/android.support.v7.app.ActionBar.Tab"
        sleep(2)
        if self.is_element_id_exist(title_id):
            WebDriverWait(cx_driver, 20).until(EC.element_to_be_clickable((By.XPATH, title_xpath)),
                                               message='timeout')
            # 判断是否是标题,是标题则处理
            if self.is_element_xpath_exist(title_xpath + "[3]"):
                print("我知道!这是标题课,对不对?^z^")
                # 如果有第三个证明是标题,判断数量4-3,3-2
                title_num = len(cx_driver.find_elements_by_xpath(title_xpath))
                if title_num == 3:
                    WebDriverWait(cx_driver, 10).until(
                        EC.element_to_be_clickable((By.XPATH, title_xpath + "[2]")),
                        message='timeout').click()
                else:
                    WebDriverWait(cx_driver, 10).until(
                        EC.element_to_be_clickable((By.XPATH, title_xpath + "[3]")),
                        message='timeout').click()

因为是操作函数,不需要返回值
这时已经可以确定视频就在当前界面,同时学习通会指明你是否看过视频,它的标识就是我们判断的依据
不幸的是,这个标识也有三种情况,而且完全随机,见代码中的a和b

  • 标识在a中,b不存在
  • 标识在b中,a是空白
  • 标识在a中,b不仅存在还有很多乱七八糟的东西
判断是否完成函数:
    def cx_crawl_is_finish(self):
        sleep(1.5)
        base_xpath = "//android.webkit.WebView/android.webkit.WebView/android.view.View"
        if self.wait_element_by_xpath(base_xpath, 3):
            a = self.is_element_xpath_exist(
                "//android.webkit.WebView/android.webkit.WebView/android.view.View[1]/android.view.View[1]")
            b = self.is_element_xpath_exist(
                "//android.webkit.WebView/android.webkit.WebView/android.view.View[2]/android.view.View[1]")
            c = self.is_element_xpath_exist(
                "//android.webkit.WebView/android.webkit.WebView/android.view.View[2]/android.view.View[1]/android.view.View")
            if a or (b and not c):
            	# 确定已经完成无疑了,回去
                back_id = "com.chaoxing.mobile:id/iv_chapter_back"
                WebDriverWait(cx_driver, 10).until(EC.element_to_be_clickable((By.ID, back_id)),
                                                   message='timeout').click()
                print("哎,看来这个已经完成了~")
                sleep(0.5)
                return 1
            return 0

最后的最后就是我们的播放函数了,学习通的视频似乎有反爬,第一次无论如何也加载不出来,等它弹出是否重新加载时点击是就瞬间好了。。。
最好(gou)的是视频不仅不能倍速不能快进而且在中间还会有答题,就卡在那里了,好在基本上都是判断题。
分析学习通视频特点:

  • 第一次要加载两遍
  • 不知道什么时候就会蹦出来一个题目卡你
  • 视频时长不确定
  • 如果断网会有重试按钮跳出,重试之后视频是自动暂停的,需要手动点击播放
  • 题目基本为判断题(有少数例外,需手动)
  • 判断错误后题目会显示你错误了,此时你再选择另外一个选项即可
  • 说白了这个题目就是防止你轻轻松松地刷视频

思路:全选对,提交,错了那就再选错,提交

视频播放函数:
    def cx_crawl_vedio_play(self):
        retry_id = "com.chaoxing.mobile:id/btnOk"
        content_id = "com.chaoxing.mobile:id/test_tv_question"
        dui_xpath = "//android.support.v7.widget.RecyclerView/android.widget.LinearLayout[1]"
        cuo_xpath = "//android.support.v7.widget.RecyclerView/android.widget.LinearLayout[2]"
        go_id = "com.chaoxing.mobile:id/btn_check_answer"
        next_id = "com.chaoxing.mobile:id/btn_next"
        check_id = "com.chaoxing.mobile:id/tv_answer"
        back_id = "com.chaoxing.mobile:id/iv_chapter_back"
        interface_id = "com.chaoxing.mobile:id/surface_container"
        # 点击播放按钮
        Play_button_xpath = "//android.view.View/android.view.View/android.widget.Image"
        WebDriverWait(cx_driver, 15).until(
            EC.element_to_be_clickable((By.XPATH, Play_button_xpath)),
            message='timeout').click()
        # 点击重试
        sleep(15)
        if self.is_element_id_exist(retry_id):
            WebDriverWait(cx_driver, 60).until(EC.element_to_be_clickable((By.ID, retry_id)),
                                               message='timeout').click()
        print("小脚本为您持续监测...")
        # 设置检测循环
        while True:
            try:
                #                         等待时间
                sleep(60)
                if self.is_element_id_exist(content_id):
                    print("答题~!")
                    WebDriverWait(cx_driver, 10).until(
                        EC.element_to_be_clickable((By.ID, content_id)),
                        message='timeout')
                    # 点击对
                    WebDriverWait(cx_driver, 10).until(
                        EC.element_to_be_clickable((By.XPATH, dui_xpath)),
                        message='timeout').click()
                    # 点击提交
                    WebDriverWait(cx_driver, 10).until(EC.element_to_be_clickable((By.ID, go_id)),
                                                       message='timeout').click()
                    sleep(0.5)
                    # 检查是否正确
                    if "正确" in WebDriverWait(cx_driver, 10).until(
                            EC.element_to_be_clickable((By.ID, check_id)),
                            message='timeout').get_attribute("text"):
                        # 点击继续
                        if self.is_element_id_exist(next_id):
                            WebDriverWait(cx_driver, 10).until(
                                EC.element_to_be_clickable((By.ID, next_id)),
                                message='timeout').click()
                        if self.is_element_id_exist(go_id):
                            WebDriverWait(cx_driver, 10).until(
                                EC.element_to_be_clickable((By.ID, go_id)),
                                message='timeout').click()
                    else:
                        # 点击错
                        WebDriverWait(cx_driver, 10).until(
                            EC.element_to_be_clickable((By.XPATH, cuo_xpath)),
                            message='timeout').click()
                        # 点击提交
                        if self.is_element_id_exist(go_id):
                            WebDriverWait(cx_driver, 10).until(
                                EC.element_to_be_clickable((By.ID, go_id)),
                                message='timeout').click()
                        if self.is_element_id_exist(next_id):
                            WebDriverWait(cx_driver, 10).until(
                                EC.element_to_be_clickable((By.ID, next_id)),
                                message='timeout').click()
                elif self.is_element_id_exist(back_id):
                    # 视频播放完会自动回到页面,等回退按钮出来后就点击回退按钮
                    WebDriverWait(cx_driver, 10).until(EC.element_to_be_clickable((By.ID, back_id)),
                                                       message='timeout').click()
                    print("完成啦!下一个哦~")
                    sleep(0.5)
                    return 1
                elif self.is_element_id_exist(retry_id):
                    print("网络或app出错,等待连接中...")
                    while self.is_element_id_exist(retry_id):
                        sleep(5)
                        WebDriverWait(cx_driver, 10).until(
                            EC.element_to_be_clickable((By.ID, retry_id)),
                            message='timeout').click()
                    print("成功重新连接,恢复中,稍等哦~")
                    interface = cx_driver.find_element_by_id(interface_id)
                    TouchAction(cx_driver).press(el=interface, pressure=0.25).release().perform()
                else:
                    print("我还没挂,吱个声 嘻嘻^v^")  # 捂脸...
            except Exception as e:
                print(e)
                print("出错啦! 是不是没网了")

好了,到这里我们的刷视频CxAuto类就完成了
我们只需将各个部分整合即可得到我们想要的代码了

下面奉上完整代码:

from appium import webdriver
from time import sleep
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from appium.webdriver.common.touch_action import TouchAction

desired_caps = {
    "platformName": "Android",
    "platformVersion": "7.1.2",
    "deviceName": "127.0.0.1:62025",
    "newCommandTimeout": "60000",
    "appPackage": "com.chaoxing.mobile",
    "appActivity": ".activity.SplashActivity",
    "noReset": "True"
}


def cx_open():
    driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
    print("打开超星APP啦!")
    return driver


cx_driver = cx_open()


class CxAuto:
    def __init__(self, course_index):
        self.course_index = course_index
        self.screenWidth = cx_driver.get_window_size()["width"]
        self.screenHeight = cx_driver.get_window_size()["height"]

    def is_element_xpath_exist(self, x_path):
        if cx_driver.find_elements_by_xpath(x_path) == []:
            return False
        else:
            return True

    def is_element_id_exist(self, x_id):
        if cx_driver.find_elements_by_id(x_id) == []:
            return False
        else:
            return True

    def wait_element_by_xpath(self, x_path, sleep_time):
        while True:
            try:
                while self.is_element_xpath_exist(x_path=x_path):
                    return True
                else:
                    print("等待中...")
                    sleep(int(sleep_time))
            except Exception as e:
                print(e)

    def wait_element_by_id(self, x_id, sleep_time):
        while True:
            try:
                while self.is_element_id_exist(x_id=x_id):
                    return True
                else:
                    print("等待中...")
                    sleep(int(sleep_time))
            except Exception as e:
                print(e)

    def start_point_me(self):
        # 点击我
        wo_xpath = "//android.widget.RelativeLayout[4]"
        if self.wait_element_by_xpath(wo_xpath, 5):
            WebDriverWait(cx_driver, 20).until(EC.element_to_be_clickable((By.XPATH, wo_xpath)),
                                               message='timeout').click()
            print("看看我的主页~")

    def start_point_class(self):
        # 点击课程
        course_xpath = "com.chaoxing.mobile:id/myCourse"
        if self.wait_element_by_id(course_xpath, 5):
            WebDriverWait(cx_driver, 20).until(EC.element_to_be_clickable((By.ID, course_xpath)),
                                               message='timeout').click()
            print("看看我的课程~")

    def start_point_course(self):
        # 点击具体课程
        course_xpath = "//android.widget.RelativeLayout/android.support.v7.widget.RecyclerView/android.widget.FrameLayout[%s]" % self.course_index
        if self.wait_element_by_xpath(course_xpath, 5):
            WebDriverWait(cx_driver, 10).until(EC.element_to_be_clickable((By.XPATH, course_xpath)),
                                               message='timeout').click()
            print("打开课程,开始了哦")

    def start_point_course_section(self):
        # 点击章节所在页
        class_page_xpath = "//android.widget.LinearLayout[1]/android.widget.FrameLayout[2]/android.widget.TextView"
        if self.wait_element_by_xpath(class_page_xpath, 5):
            WebDriverWait(cx_driver, 10).until(EC.element_to_be_clickable((By.XPATH, class_page_xpath)),
                                               message='timeout').click()

    def cx_crawl_main_list(self, class_list_xpath):
        print("让我再看看列表,没看仔细,5~")
        WebDriverWait(cx_driver, 20).until(EC.element_to_be_clickable((By.XPATH, class_list_xpath)),
                                           message='timeout')
        sleep(1)
        ls = cx_driver.find_elements_by_xpath(class_list_xpath)
        return ls

    def cx_crawl_point_in(self, n):
        WebDriverWait(cx_driver, 20).until(EC.element_to_be_clickable(
            (By.XPATH,
             "//android.widget.RelativeLayout/android.support.v7.widget.RecyclerView/android.widget.RelativeLayout[{}]".format(
                 n + 1))),
            message='timeout').click()

    def cx_crawl_is_white(self, back_id):
        # 空页处理
        white_xpath = "//android.support.v4.view.ViewPager/android.widget.RelativeLayout/android.widget.TextView"
        white_con_xpath = "//android.webkit.WebView/android.webkit.WebView/android.view.View[1]"
        V4_id = "com.chaoxing.mobile:id/vp_chapter"
        self.wait_element_by_id(V4_id, 3)
        sleep(2)
        p = self.is_element_xpath_exist(white_xpath)
        q = "暂无内容" in cx_driver.find_element_by_xpath(white_con_xpath).get_attribute(
            "text") if self.is_element_xpath_exist(white_con_xpath) else 1
        if p or q:
            print("这个居然是空 白 页,天哪,快回快回@x@")

            WebDriverWait(cx_driver, 10).until(EC.element_to_be_clickable((By.ID, back_id)),
                                               message='timeout').click()
            sleep(0.5)
            return 1
        return 0

    def cx_crawl_vedio_where(self):
        title_id = "com.chaoxing.mobile:id/tb_chapter"
        title_xpath = "//android.widget.LinearLayout/android.support.v7.app.ActionBar.Tab"
        sleep(2)
        if self.is_element_id_exist(title_id):
            WebDriverWait(cx_driver, 20).until(EC.element_to_be_clickable((By.XPATH, title_xpath)),
                                               message='timeout')
            # 判断是否是标题,是标题则处理
            if self.is_element_xpath_exist(title_xpath + "[3]"):
                print("我知道!这是标题课,对不对?^z^")
                # 如果有第三个证明是标题,判断数量4-3,3-2
                title_num = len(cx_driver.find_elements_by_xpath(title_xpath))
                if title_num == 3:
                    WebDriverWait(cx_driver, 10).until(
                        EC.element_to_be_clickable((By.XPATH, title_xpath + "[2]")),
                        message='timeout').click()
                else:
                    WebDriverWait(cx_driver, 10).until(
                        EC.element_to_be_clickable((By.XPATH, title_xpath + "[3]")),
                        message='timeout').click()

    def cx_crawl_is_finish(self):
        sleep(1.5)
        base_xpath = "//android.webkit.WebView/android.webkit.WebView/android.view.View"
        if self.wait_element_by_xpath(base_xpath, 3):
            a = self.is_element_xpath_exist(
                "//android.webkit.WebView/android.webkit.WebView/android.view.View[1]/android.view.View[1]")
            b = self.is_element_xpath_exist(
                "//android.webkit.WebView/android.webkit.WebView/android.view.View[2]/android.view.View[1]")
            c = self.is_element_xpath_exist(
                "//android.webkit.WebView/android.webkit.WebView/android.view.View[2]/android.view.View[1]/android.view.View")
            if a or (b and not c):
                back_id = "com.chaoxing.mobile:id/iv_chapter_back"
                WebDriverWait(cx_driver, 10).until(EC.element_to_be_clickable((By.ID, back_id)),
                                                   message='timeout').click()
                print("哎,看来这个已经完成了~")
                sleep(0.5)
                return 1
            return 0

    def cx_crawl_vedio_play(self):
        retry_id = "com.chaoxing.mobile:id/btnOk"
        content_id = "com.chaoxing.mobile:id/test_tv_question"
        dui_xpath = "//android.support.v7.widget.RecyclerView/android.widget.LinearLayout[1]"
        cuo_xpath = "//android.support.v7.widget.RecyclerView/android.widget.LinearLayout[2]"
        go_id = "com.chaoxing.mobile:id/btn_check_answer"
        next_id = "com.chaoxing.mobile:id/btn_next"
        check_id = "com.chaoxing.mobile:id/tv_answer"
        back_id = "com.chaoxing.mobile:id/iv_chapter_back"
        interface_id = "com.chaoxing.mobile:id/surface_container"
        # 点击播放按钮
        Play_button_xpath = "//android.view.View/android.view.View/android.widget.Image"
        WebDriverWait(cx_driver, 15).until(
            EC.element_to_be_clickable((By.XPATH, Play_button_xpath)),
            message='timeout').click()
        # 点击重试
        sleep(15)
        if self.is_element_id_exist(retry_id):
            WebDriverWait(cx_driver, 60).until(EC.element_to_be_clickable((By.ID, retry_id)),
                                               message='timeout').click()
        print("小脚本为您持续监测...")
        # 设置检测循环
        while True:
            try:
                #                         等待时间
                sleep(60)
                if self.is_element_id_exist(content_id):
                    print("答题~!")
                    print("努力回魂中,稍微等一下哦~")
                    WebDriverWait(cx_driver, 10).until(
                        EC.element_to_be_clickable((By.ID, content_id)),
                        message='timeout')
                    # 点击对
                    WebDriverWait(cx_driver, 10).until(
                        EC.element_to_be_clickable((By.XPATH, dui_xpath)),
                        message='timeout').click()
                    # 点击提交
                    WebDriverWait(cx_driver, 10).until(EC.element_to_be_clickable((By.ID, go_id)),
                                                       message='timeout').click()
                    sleep(0.5)
                    # 检查是否正确
                    if "正确" in WebDriverWait(cx_driver, 10).until(
                            EC.element_to_be_clickable((By.ID, check_id)),
                            message='timeout').get_attribute("text"):
                        # 点击继续
                        if self.is_element_id_exist(next_id):
                            WebDriverWait(cx_driver, 10).until(
                                EC.element_to_be_clickable((By.ID, next_id)),
                                message='timeout').click()
                        if self.is_element_id_exist(go_id):
                            WebDriverWait(cx_driver, 10).until(
                                EC.element_to_be_clickable((By.ID, go_id)),
                                message='timeout').click()
                    else:
                        # 点击错
                        WebDriverWait(cx_driver, 10).until(
                            EC.element_to_be_clickable((By.XPATH, cuo_xpath)),
                            message='timeout').click()
                        # 点击提交
                        if self.is_element_id_exist(go_id):
                            WebDriverWait(cx_driver, 10).until(
                                EC.element_to_be_clickable((By.ID, go_id)),
                                message='timeout').click()
                        if self.is_element_id_exist(next_id):
                            WebDriverWait(cx_driver, 10).until(
                                EC.element_to_be_clickable((By.ID, next_id)),
                                message='timeout').click()
                elif self.is_element_id_exist(back_id):
                    # 视频播放完会自动回到页面,等回退按钮出来后就点击回退按钮
                    WebDriverWait(cx_driver, 10).until(EC.element_to_be_clickable((By.ID, back_id)),
                                                       message='timeout').click()
                    print("完成啦!下一个哦~")
                    sleep(0.5)
                    return 1
                elif self.is_element_id_exist(retry_id):
                    print("网络或app出错,等待连接中...")
                    while self.is_element_id_exist(retry_id):
                        sleep(5)
                        WebDriverWait(cx_driver, 10).until(
                            EC.element_to_be_clickable((By.ID, retry_id)),
                            message='timeout').click()
                    print("成功重新连接,恢复中,稍等哦~")
                    interface = cx_driver.find_element_by_id(interface_id)
                    TouchAction(cx_driver).press(el=interface, pressure=0.25).release().perform()
                else:
                    print("我还没挂,吱个声 嘻嘻^v^")
            except Exception as e:
                print(e)
                print("出错啦! 是不是没网了")

    def start_main_circullation(self):
        class_list_xpath = "//android.widget.RelativeLayout/android.support.v7.widget.RecyclerView/android.widget.RelativeLayout"
        back_id = "com.chaoxing.mobile:id/iv_chapter_back"
        # 设置主循环变量
        m = 1
        # 主循环
        while m:
            num = len(cx_driver.find_elements_by_xpath(class_list_xpath)) - 1
            print("准备!")
            # 设置B循环变量
            n = 1
            # 设置已爬取列表
            curScreenItemSet = []
            # B循环:单页爬虫核心循环,去头去尾
            while n < num:
                try:
                    # 爬取当前页面
                    ls = self.cx_crawl_main_list(class_list_xpath)
                    # 取页面第n个小节
                    sleep(0.5)
                    identification = ls[n].find_element_by_id("com.chaoxing.mobile:id/tv_sub_index").get_attribute(
                        'text')
                    print("看看课程%s.^v^." % identification)
                    # 该课程的一系列操作
                    if identification not in curScreenItemSet:
                        print("欸~  这个可以!")
                        # 点进去
                        self.cx_crawl_point_in(n)
                        try:
                            print("等它加载一下")
                            top_title_xpath = "com.chaoxing.mobile:id/tv_chapter_name"
                            self.wait_element_by_id(top_title_xpath, 5)
                            # 查是否空白页
                            if self.cx_crawl_is_white(back_id):
                                curScreenItemSet.append(identification)
                                n += 1
                                continue
                            # 确定视频位置
                            self.cx_crawl_vedio_where()
                            temporary_xpath = "//android.webkit.WebView/android.webkit.WebView/android.view.View"
                            self.wait_element_by_xpath(temporary_xpath, 5)
                            print("稍微等等,我怕没加载完^x^")
                            # 判断是否已完成
                            if self.cx_crawl_is_finish():
                                curScreenItemSet.append(identification)
                                n += 1
                                continue
                            print("开始播放了哦~")
                            if self.cx_crawl_vedio_play():
                                curScreenItemSet.append(identification)
                                n += 1
                        except Exception as e:
                            print(e)
                    else:
                        print("这个看过了哦~")
                except Exception as e:
                    n += 1
                    print(e)
                    print("这个不行欸,怎么办怎么办x_x 算啦,还是看看下面的吧~")
            # 滑动,下一页
            cx_driver.swipe(self.screenWidth * 0.5, self.screenHeight * 0.65, self.screenWidth * 0.5,
                            self.screenHeight * 0.25, 500)
            sleep(0.5)


def start(n):
    go_go_go = CxAuto(n)  # 假设我要刷的课在课表的第五行,读者也可以进行改动用名称来定位

    go_go_go.start_point_me()

    go_go_go.start_point_class()

    go_go_go.start_point_course()

    go_go_go.start_point_course_section()

    go_go_go.start_main_circullation()


if __name__ == '__main__':
    start(5)

好了,就讲这么多吧

公开发布,如果有大佬觉得尚有改进之处请在评论区留言
【仅供参考学习使用】
【更新:Python-Appium自动化测试-学习通自动刷视频(2)】

你可能感兴趣的:(python,selenium,app,定位)