Pastwill 发表于 2023-4-2 18:56

【Python原创】新版职教云自动学习脚本 · selenium

本帖最后由 Pastwill 于 2023-4-2 18:57 编辑

一.前言
该脚本用于智慧职教的自动学习,使用selenium框架以及requests库,代码中使用了许多面向过程写法,死循环等,欢迎有能力的大佬进行优化,共同学习。如若认为有些用处请给予回复与评分,欢迎指出不足缺点,共同进步,仅做个人学习使用,严禁用于其他用途。
二.开发环境

windows 11 Python 3.10 x86

三.调用模块
import json
import sys
import time
import requests
import watch
from prettytable import PrettyTable
import random
import time
from lxml import etree
from prettytable import PrettyTable
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
四.代码

#app.py
import json
import sys
import time

import requests
from prettytable import PrettyTable

import watch


# 全局变量区
userName = ""
password = ""

'''
控制台日志输出脚本
'''


def out(text):
    print(time.strftime(f"[%Y-%m-%d %H:%M:%S]:{text}", time.localtime()))


'''
登陆并返回token
'''


def login():
    payload = {
      "userName": userName,
      "password": password,
      "type": 1
    }
    headers = {
      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"}
    token = json.loads(
      requests.request("POST", "https://sso.icve.com.cn/data/userLogin", json=payload, headers=headers).text)
    if token["msg"] == "ok":
      out("恭喜登陆成功!")
      global oktoken
      oktoken = token["data"]
    else:
      out("登陆失败!")
      sys.exit()
    out("开始尝试登陆!")
    payload = f'token={token["data"]}'
    headers = {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}
    info = json.loads(
      requests.request("POST", "https://user.icve.com.cn/patch/zhzj/api_getUserInfo.action", headers=headers,
                         params=payload).text)
    if "成功" in info['errorMsg']:
      out("个人信息获取成功")
      table = PrettyTable(["姓名", "学号", "城市", "学校"])
      table.add_row(['displayName'], info['data']['employeeNumber'], info['data']['province'],
                     info['data']["schoolName"]])
      print(table)
    out("开始获取课程信息!")
    url = "https://user.icve.com.cn/learning/u/userDefinedSql/getBySqlCode.json"

    payload = "data=info&page.searchItem.queryId=getStuCourseInfoById&page.searchItem.keyname=&page.curPage=1&page.pageSize=500"
    headers = {
      "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
      "Cookie": f"token={oktoken};",
      "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
    }
    info = json.loads(requests.request("POST", url, data=payload, headers=headers).text)

    classok = []
    k = 0
    table = PrettyTable(["编号", "课程名", "任课教师", "课程ID"])
    for i in info["page"]["items"]['info']:
      classok.append(, i["ext4"], i["ext9"]])
      table.add_row(, i["ext4"], i["ext9"]])
      k = k + 1
    print(table)
    watch.Watch(userName, password, classok)


if __name__ == '__main__':
    login()

#watch.py
import random
import time
from lxml import etree
from prettytable import PrettyTable
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By


def out(text):# 格式输出
    print(time.strftime(f"[%Y-%m-%d %H:%M:%S]:{text}", time.localtime()))


def Watch(userName, password, classId):
    options = webdriver.ChromeOptions()
    options.add_experimental_option('excludeSwitches', ['enable-automation'])
    # 屏蔽以开发者运行提示框
    options.add_experimental_option('useAutomationExtension', False)
    # 屏蔽保存密码提示框
    prefs = {'credentials_enable_service': False, 'profile.password_manager_enabled': False}
    options.add_experimental_option('prefs', prefs)
    # chrome 88 或更高版本的反爬虫特征处理
    options.add_argument('--disable-blink-features=AutomationControlled')
    # 浏览器对象
    preferences = {
      "webrtc.ip_handling_policy": "disable_non_proxied_udp",
      "webrtc.multiple_routes_enabled": False,
      "webrtc.nonproxied_udp_enabled": False
    }
    # 关闭webrtc 避免找到真实IP地址
    options.add_experimental_option("prefs", preferences)
    options.binary_location = r'Chrome\App\Chrome.exe'
    driver = webdriver.Chrome(service=Service(r'chromedriver.exe'), options=options)
    with open('stealth.min.js', mode='r', encoding='utf-8') as f:
      string = f.read()
    # 移除 selenium 中的爬虫特征
    driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {'source': string})
    driver.get('https://sso.icve.com.cn/sso/auth?mode=simple&source=2&redirect=https://user.icve.com.cn/cms/')
    time.sleep(1)
    driver.find_element(By.ID, 'userName').send_keys(userName)
    time.sleep(1)
    driver.find_element(By.ID, 'password11').send_keys(password)
    time.sleep(1)
    driver.find_element(By.ID, 'isTy').click()
    time.sleep(1)
    driver.find_element(By.CLASS_NAME, 'dl').click()
    time.sleep(1)
    try:
      driver.find_element(By.ID, 'close1').click()
      time.sleep(1)
      driver.find_element(By.ID, 'close2').click()
      time.sleep(1)
      driver.find_element(By.ID, 'close3').click()
      time.sleep(1)
      driver.find_element(By.ID, 'close4').click()
    except:
      out("预防性点击可能出现的提示框")
    time.sleep(4)
    if "* 校验登录状态" in driver.page_source:
      time.sleep(3)
      driver.find_element(By.ID, 'userCenterUrl').click()
      out("登录成功")
      driver.get(
            f"https://course.icve.com.cn/learnspace/sign/signLearn.action?template=blue&courseId={classId}&loginType=true&loginId={userName}&sign=0&siteCode=zhzj&domain=user.icve.com.cn")
      time.sleep(2)
      driver.switch_to.frame('mainContent')
      time.sleep(2)
      videotasker = etree.HTML(driver.page_source).xpath('//*[@completestate="0" and @itemtype="video"]/@onclick')
      doctasker = etree.HTML(driver.page_source).xpath('//*[@completestate="0" and @itemtype="doc"]/@onclick')
      vodall = len(etree.HTML(driver.page_source).xpath('//*[@itemtype="video"]/@onclick'))
      docall = len(etree.HTML(driver.page_source).xpath('//*[@itemtype="doc"]/@onclick'))

      table = PrettyTable(["视频已完成/全部", "文档已完成/全部", "总进度"])
      table.add_row([f"{vodall - len(videotasker)}/{vodall}", f"{docall - len(doctasker)}/{docall}",
                     '{:.2%}'.format((len(videotasker) + len(doctasker)) / (vodall + docall))])
      print(table)

      out("开始执行视频任务序列")
      for i in videotasker:
            time.sleep(2)
            driver.execute_script(i)
            while True:
                if 'id="mainFrame" name="mainFrame"' in driver.page_source:# 利用死循环进入播放器框架 吐槽一下职教云辣鸡代码
                  driver.switch_to.frame('mainFrame')
                  break
            while True:
                time.sleep(random.randint(3, 7))
                look = driver.execute_script(
                  'return document.getElementById("screen_player_time_1").textContent')
                print(f'观看:{driver.execute_script("return document.title")} 已观看到{look}')
                time.sleep(10)# 十秒输出
                if look == driver.execute_script(
                        'return document.getElementById("screen_player_time_2").textContent'):
                  out("观看完成,即将下一个")
                  driver.switch_to.parent_frame()
                  break
      out("开始执行文档任务序列")
      for i in doctasker:
            time.sleep(2)
            driver.execute_script(i)
            print(f'观看:{driver.execute_script("return document.title")}')
            time.sleep(7)
            out("观看完成,即将下一个")
      videotasker = etree.HTML(driver.page_source).xpath('//*[@completestate="0" and @itemtype="video"]/@onclick')
      doctasker = etree.HTML(driver.page_source).xpath('//*[@completestate="0" and @itemtype="doc"]/@onclick')
      vodall = len(etree.HTML(driver.page_source).xpath('//*[@itemtype="video"]/@onclick'))
      docall = len(etree.HTML(driver.page_source).xpath('//*[@itemtype="doc"]/@onclick'))

      if (len(videotasker) + len(doctasker)) == (vodall + docall):
            out("恭喜 本课全部观看完成 程序退出!")
            exit()


github: https://github.com/Past-GuoWang/icvepass
完整环境:https://www.123pan.com/s/CW2DVv-deHBh.html提取码:s6ZU

Z65156811 发表于 2023-4-2 20:00

有点6,可以搞其他学习平台的就更牛了

endriver 发表于 2023-4-2 20:09

感谢分享,学习了

MortyS 发表于 2023-4-2 20:35

感谢分享,学习一下思路

shitdevops 发表于 2023-4-2 20:56

牛的牛的 学习了

dreamact 发表于 2023-4-2 21:27

我靠,为什么不早点出:'(weeqw

zhaoaa 发表于 2023-4-2 22:05

要是有个学习通,我爱死你了

yahoo1920 发表于 2023-4-3 10:27

非常不错哦,学习了!!!

Wattiro 发表于 2023-4-3 21:29

感谢大佬!!

爱奴 发表于 2023-4-3 22:43

谢谢分享
页: [1] 2 3
查看完整版本: 【Python原创】新版职教云自动学习脚本 · selenium