一.前言 该脚本用于智慧职教的自动学习,使用selenium框架以及requests库,代码中使用了许多面向过程写法,死循环等,欢迎有能力的大佬进行优化,共同学习。如若认为有些用处请给予回复与评分,欢迎指出不足缺点,共同进步,仅做个人学习使用,严禁用于其他用途。
二.开发环境
windows 11 Python 3.10 x86
三.调用模块
[Python] 纯文本查看复制代码
import json
import sys
import time
import requests
import watch
from prettytable import PrettyTable
[Python] 纯文本查看复制代码
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
四.代码
[Python] 纯文本查看复制代码
#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([info['data']['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"][0]['info']:
classok.append([i["ext1"], i["ext4"], i["ext9"]])
table.add_row([k, i["ext1"], i["ext4"], i["ext9"]])
k = k + 1
print(table)
watch.Watch(userName, password, classok[int(input("请选择您要执行的课程编号"))][2])
if __name__ == '__main__':
login()
[Python] 纯文本查看复制代码
#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()