山野村夫-陈墨 发表于 2020-3-14 22:02

刷网课,应该能实现

新冠肺炎可怕,增加网课头大。
selenium强大,解决了它。


一、功能描述:
      目标: 超星平台 新型冠状病毒防疫公益课或和其他网页结构内类似的课
软件环境: python3 +selenium + chrome+ chromedriver

二、程序完整版( yun_code 是云打码的接口 )
"""    通过selenium 实现刷课程序
      超星平台
    url: http://passport2.chaoxing.com/login?fid=&refer=http://i.mooc.chaoxing.com
"""
fromseleniumimport webdriver
importrequests
importyun_code
importtime
importrandom
importeasygui as g

classchaoxing_spider():

    def __init__(self,user_name, user_password,   school_name,class_name):
      self.url = "http://passport2.chaoxing.com/login?fid=&refer=http://i.mooc.chaoxing.com"
      self.user_name = user_name
      self.user_password = user_password
      self.school_name = school_name
      self.class_name = class_name

      #设置无界面参数
      # 创建chrome参数对象
      chrome_options = webdriver.ChromeOptions()
      #chrome_options.add_argument('--headless')
      chrome_options.add_argument('--no-sandbox') # 非沙盒模式
      chrome_options.add_argument('--disable-gpu')
      chrome_options.add_argument('--disable-dev-shm-usage')
      self.driver = webdriver.Chrome( options=chrome_options , executable_path="Chrome/chromedriver.exe")
      print("运行")



    #登录账号细节
    def _sign(self):
      self.driver.get( self.url )
      # 1、获取验证码url,返回图片内容和cookies
      img = self.driver.find_element_by_id("numVerCode").get_attribute("src")
      # 2、请求验证码url
      ans = requests.get( img )
      # 3、照片cookies
      ans_cookies= []
      for item inans.cookies:
            ans_cookies.append({'name':item.name , 'value':item.value} )

      # 4、将验证码写到jpg里
      with open(b"file/011.jpg", "wb")as f:
            f.write( ans.content)

      # 5、利用云打码获取验证码
      code= yun_code.get_code( 1004,b'file/011.jpg')

      # 选择学校
      self.driver.find_element_by_link_text("选择单位").click()
      self.driver.find_element_by_id("searchSchool1").send_keys(self.school_name )
      self.driver.find_element_by_class_name("zw_t_btn").click()
      #此处有加载过程,需要尝试
      for i in range(10):
            try:
                self.driver.find_element_by_link_text( self.school_name).click()
                break
            except :
                time.sleep(1)

      #填写账号、密码、验证码
      self.driver.find_element_by_id("unameId").send_keys( self.user_name)
      self.driver.find_element_by_id("passwordId").send_keys( self.user_password)
      # 6、填写验证码
      self.driver.find_element_by_id("numcode").send_keys( code )
      # 7、将验证码cookies添加到driver
      for item inans_cookies:
            self.driver.add_cookie( item)
      # 8、登录
      self.driver.find_element_by_xpath("//*[@id='form']/table/tbody/tr/td/label/input").click()


    # 登录账号、对外接口
    def sign(self):
      for i inrange(10):
            print("第{}登录。。。。".format( i+1 ))
            try:
                self._sign()
                print("\t登录成功!")
                return True
            except :
                time.sleep(1)
      returnFalse

    # 选择课程, 返回当前课程地址
    def selected_class(self):
      print("选择课程。。。。。")
      self.driver.get(self.driver.current_url )
      #切换到iframe
      for i in range(10):
            try:
                self.driver.switch_to.frame("frame_content")
            except :
                time.sleep(1)
      # 发现课程,点击课程
      self.driver.find_element_by_partial_link_text(self.class_name ).click()
      # self.driver.get(self.driver.current_url )

      ##n = window.handle 获取当前页面左右的句柄
      ##switch_to_window( n) 切换到最前的一页
      ##todo 解决问题: 点击超链接( target="_blank")后current_url 和page_souce本页没有改变
      self.driver.switch_to.window(self.driver.window_handles)
      print("\t选择成功!")
      returnself.driver.current_url

    # 获取某一章节的视频url
    def open_class(self, url ):
      self.driver.get( url )
      self.driver.refresh() # 更新界面
      time.sleep( 2 )
      self.driver.find_element_by_xpath("*//div/div/div/div/div/div/h3/span/a") .click()
      # 获取 章节对象
      part_list = []
      part_list = self.driver.find_elements_by_xpath(" //*[@id='coursetree']//h4")
      for item in part_list:
            ans = item.find_element_by_xpath("span").text
            # print( ans )
            if ans:
                for i inrange(5):
                  try:
                        item.find_element_by_xpath("a").click()
                        print("章节:",str(item.find_element_by_xpath("*//span").text).strip() )
                        break
                  except:
                        time.sleep(1)
                break
      # 获取当页视频、有加载过程,需要等待
      for i in range(10):
            try:
                video__url = self.driver.find_element_by_xpath("*//iframe[@id='iframe']").get_attribute("src")
                return   video__url
            exceptException as e:
                time.sleep(1)
      return ""


    # 看视频
    defview_video(self, url ):
      self.driver.get(url )
      iframe=[]
      for i in range(10):
            iframe = self.driver.find_elements_by_xpath("*//iframe")
            if iframe:
                break
            time.sleep(1)
      # 如果是图片,则不存在iframe
      if not iframe:
            print("这是图片,不看了")
            return
      index = 1
      for item iniframe:
            self.driver.switch_to.frame( item )
            print("\t正在看第{}个视频".format(index ))
            for i in range(10):
                try:# todo 这个切换一定注意
                  self.driver.find_element_by_xpath("*//div[@id='reader']").click()
                  time.sleep(1)
                  # 视频时长
                  time_leng =self.driver.find_element_by_xpath("//*[@id='video']/div/div/span").text
                  time_num =int(str(time_leng).split(":").strip())*60 + int(str(time_leng).split(":").strip())
                  print("\t\t时长:", time_num)
                  time.sleep( int(time_num) )
                  break
                except Exception as e:
                  print(i,e)
                  time.sleep(1)
            print("\t\t第{}个视频结束了".format( index ) )
            # 回到默认页面
            self.driver.switch_to.default_content()
            index +=1


    # 逻辑实现
    def run(self):
      if not self.sign():
            print("登录失败!")
            return
      class_url = self.selected_class()
      while True:
            video_url = self.open_class( class_url )
            ifvideo_url:
                self.view_video( video_url )
                time.sleep( random.randint(1,10))
            else:
                break

if __name__ == '__main__':
    ans = g.multenterbox(msg='输入信息!',   fields=['账号','密码','学校信息','课程'],
                         values=["账号","密码", "学校名称","新型冠状病毒"])
    if len(ans)== 4:
      account = ans
      password = ans
      school_name = ans
      class_name = ans
      spider = chaoxing_spider( account ,password , school_name, class_name )
      spider.run()


三、一点反思:
   (1)iframe 、frame 框架的嵌套。
<body>
      <iframe id="iframe_id"    src=“iframe_url”>
               <inputid="input_id"/>
       </iframe>
</body>
这种情况下执行 webdriver.find_element_by_id("input_id")必然报错, 因为 input_id 在iframe 中,而不在当前文档中。
               ①用webdriver.switch_to_frame( “frame_id”) 切换到iframe, 此时的webdriver的文档iframe文档, 但是这个有个加载过程,需要延时。之后webdriver.find_element_by_id("input_id")。
               ②获取iframe的url, webdriver.get( iframe_url), 此时的页面就是ifram的页面。直接操作webdriver.find_element_by_id("input_id")。
             ps: 如果采用①,应该记得返回主文档, 来一句webdriver.switch_to_default_content().

   (2)<a href=""target="_BLANK">超链接的跳转。
               此时点击超链接,虽然页面跳转了 , 但是webdriver.page_course 和webdriver.current_url 还是原来的,并不是超链接跳转之后的。解决这个问题的方法:
                n = window.handle 获取当前页面左右的句柄switch_to_window( n) 切换到最前的一页
               
   (3)加载未完成执行操作,报错
            ①执行点击查找之前进行一次webdruiver.get(),因为它是加载完之后执行后面程序
            ②延迟;强制延时,time.sleep();   (貌似没用)显式等待;隐式等待。

   

SQ-Will 发表于 2020-3-14 22:38

超星的视频很多看一半要做题才能继续的,而且挂着浪费时间,浪费电。可以劫持下播放器,nop掉播放器控制时间的代码,然后把播放时间写入最后一秒,就能秒过一节课了。多年前上大学,花了一小时过了两门公开课~

山野村夫-陈墨 发表于 2020-3-20 18:44

jidesheng6 发表于 2020-3-19 21:44
膜拜大佬,真是苦了你了,超星平台太贱了

平台太挺好,给大家提供了一个学习的平台。只是学校太贱了,安排一些莫名其妙的杂课。
学吧,都是一些冠冕堂皇的废话,华而不实。 不学吧,学分放在那儿

asdcy2003 发表于 2020-3-14 22:51

求成品最好能适应 现在所有 网课天天挂科 太累

橡鳄君 发表于 2020-3-14 22:52

刷了后台能查出来的,

alanye 发表于 2020-3-14 22:59

其实我觉得刷网课这种行为并不好,对自己没有好处。况且老师可以在后台看到的。

729 发表于 2020-3-14 23:01

SQ-Will 发表于 2020-3-14 22:38
超星的视频很多看一半要做题才能继续的,而且挂着浪费时间,浪费电。可以劫持下播放器,nop掉播放器控制时 ...

求技术嘿嘿 这个感觉好玩

纣王妲己 发表于 2020-3-14 23:23

SQ-Will 发表于 2020-3-14 22:38
超星的视频很多看一半要做题才能继续的,而且挂着浪费时间,浪费电。可以劫持下播放器,nop掉播放器控制时 ...

现在秒过不行了 隔了一个月红信要求重看现在暴力猴解决

山野村夫-陈墨 发表于 2020-3-14 23:25

SQ-Will 发表于 2020-3-14 22:38
超星的视频很多看一半要做题才能继续的,而且挂着浪费时间,浪费电。可以劫持下播放器,nop掉播放器控制时 ...

你的意思就是后台的观看时间是浏览器直接反馈,而不是做个时间差?

山野村夫-陈墨 发表于 2020-3-14 23:27

asdcy2003 发表于 2020-3-14 22:51
求成品最好能适应 现在所有 网课天天挂科 太累

我会把这个代码加工完善, 但是不会发出来。
不太好,我觉得

山野村夫-陈墨 发表于 2020-3-14 23:29

橡鳄君 发表于 2020-3-14 22:52
刷了后台能查出来的,

有些课,实在就是折磨人。 上,浪费时间、精力,不上还不行。只能刷了
页: [1] 2 3 4
查看完整版本: 刷网课,应该能实现