|
1 |
| -import requests |
| 1 | +import json |
2 | 2 | import os
|
| 3 | +import requests |
3 | 4 | import datetime
|
4 | 5 | import time
|
| 6 | +import random |
| 7 | +import base64 |
| 8 | +import cv2 |
| 9 | +import pytesseract |
| 10 | +import tkinter as tk |
| 11 | +from tkinter import simpledialog |
| 12 | + |
| 13 | +def login(): |
| 14 | + # 获取验证码 |
| 15 | + response = requests.get("https://buct.smartclass.cn/Login.aspx", headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"}) |
| 16 | + cookies = response.cookies.get_dict() |
| 17 | + verifycode_json = json.loads(response.text) |
| 18 | + |
| 19 | + # 显示验证码图片 |
| 20 | + verifyimg = base64.b64decode(verifycode_json["Value"]["img"]) |
| 21 | + with open("verifyimg.png", "wb") as f: |
| 22 | + f.write(verifyimg) |
| 23 | + image = cv2.imread("verifyimg.png") |
| 24 | + cv2.imshow("Verification Code", image) |
| 25 | + cv2.waitKey(0) |
| 26 | + cv2.destroyAllWindows() |
| 27 | + |
| 28 | + # 输入验证码 |
| 29 | + verifycode = pytesseract.image_to_string(image).strip() |
| 30 | + if not verifycode: |
| 31 | + verifycode = simpledialog.askstring("Input Code", "Please enter the verification code:") |
5 | 32 |
|
6 |
| -# Login |
7 |
| -url = "https://buct.smartclass.cn/Login.aspx" |
8 |
| -response = requests.get(url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"}) |
9 |
| -resp_cookies = response.cookies |
| 33 | + # 登录 |
| 34 | + login_data = { |
| 35 | + "UserName": "", |
| 36 | + "PassWord": "", |
| 37 | + "isRember": "false", |
| 38 | + "VerifyCode": verifycode, |
| 39 | + "VerifyCodeId": verifycode_json["Value"]["Code"], |
| 40 | + "redirectUri": "" |
| 41 | + } |
| 42 | + response = requests.post("https://buct.smartclass.cn/Home/Login", data=login_data, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"}, cookies=cookies) |
| 43 | + cookies.update(response.cookies.get_dict()) |
| 44 | + return cookies |
10 | 45 |
|
11 |
| -# Get verification code |
12 |
| -random_num = int(str(int(time.time() * 1000000000)) * 0.0000001) |
13 |
| -verify_code_url = f"https://buct.smartclass.cn/home/VerifyImage2?{random_num}" |
14 |
| -response = requests.get(verify_code_url, cookies=resp_cookies, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"}) |
15 |
| -verify_code_json = response.text |
16 |
| -verify_code_img = response.content.decode("base64") |
17 |
| -verify_code = input("Input verification code: ") |
| 46 | +def get_csrf_token(cookies): |
| 47 | + # 获取 CSRF 令牌 |
| 48 | + response = requests.get("https://buct.smartclass.cn/wechat.json?r=2021-01-29", headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"}, cookies=cookies) |
| 49 | + csrkKey = json.loads(response.text)["csrkKey"] |
| 50 | + token = "".join(csrkKey[int((time.time() - time.time() % (10 ** i)) / (10 ** i))] for i in range(10, 0, -1)) |
| 51 | + return token |
18 | 52 |
|
19 |
| -# Login |
20 |
| -login_url = "https://buct.smartclass.cn/Home/Login" |
21 |
| -login_data = { |
22 |
| - "UserName": "", |
23 |
| - "PassWord": "", |
24 |
| - "isRember": "false", |
25 |
| - "VerifyCode": verify_code, |
26 |
| - "VerifyCodeId": verify_code_json["Code"], |
27 |
| - "redirectUri": "" |
28 |
| -} |
29 |
| -response = requests.post(login_url, data=login_data, cookies=resp_cookies, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"}) |
30 |
| -login_return = response.text |
| 53 | +def download_videos(cookies, token): |
| 54 | + # 获取课程列表 |
| 55 | + today = datetime.datetime.now().strftime("%Y-%m-%d") |
| 56 | + fromday = (datetime.datetime.now() - datetime.timedelta(days=36)).strftime("%Y-%m-%d") |
| 57 | + response = requests.get(f"https://buct.smartclass.cn/Webapi/V1/Video/GetMyVideoList?csrkToken={token}&TeacherName=&Sort=StartTime&TagID=&SyCommonKey=&StartDate={fromday}&EndDate={today}&Order=1&PageSize=100&PageNumber=1&attribute=&IncludePublic=", headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"}, cookies=cookies) |
| 58 | + video_data = json.loads(response.text) |
31 | 59 |
|
32 |
| -# Get CSRF token |
33 |
| -wechat_url = "https://buct.smartclass.cn/wechat.json?r=2021-01-29" |
34 |
| -response = requests.get(wechat_url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"}) |
35 |
| -wechat_json = response.text |
36 |
| -csrf_key = wechat_json["csrkKey"] |
37 |
| -token = "".join([csrf_key[int((time.time() - time.time() % i) / i)] for i in [1000000000000, 100000000000, 10000000000, 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10]]) |
| 60 | + # 下载视频 |
| 61 | + total_count = video_data["TotalCount"] |
| 62 | + for i in range(total_count): |
| 63 | + cover = video_data["Data"][i]["Cover"] |
| 64 | + start_time = video_data["Data"][i]["StartTime"] |
| 65 | + course_name = video_data["Data"][i]["CourseName"] |
| 66 | + start_time_formatted = start_time.replace(":", "_") |
38 | 67 |
|
39 |
| -# Get video list |
40 |
| -today = (datetime.datetime.now() - datetime.timedelta(days=36)).strftime("%Y-%m-%d") |
41 |
| -from_day = (datetime.datetime.now() - datetime.timedelta(days=14)).strftime("%Y-%m-%d") |
42 |
| -video_list_url = f"https://buct.smartclass.cn/Webapi/V1/Video/GetMyVideoList?csrkToken={token}&TeacherName=&Sort=StartTime&TagID=&SyCommonKey=&StartDate={from_day}&EndDate={today}&Order=1&PageSize=100&PageNumber=1&attribute=&IncludePublic=" |
43 |
| -response = requests.get(video_list_url, cookies=resp_cookies, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"}) |
44 |
| -video_list = response.text |
45 |
| -covers = [item.split("?")[0] for item in response.json()["Data"]["Cover"]] |
46 |
| -start_times = response.json()["Data"]["StartTime"] |
47 |
| -total_count = response.json()["TotalCount"] |
48 |
| -course_names = response.json()["Data"]["CourseName"] |
| 68 | + # 下载 VGA 视频 |
| 69 | + vga_url = cover.replace("/1/", "/0/").replace("000.jpg", "VGA.mp4") |
| 70 | + if not os.path.exists(f"D:\\OvlerDrive\\OneDrive\\downloads\\{course_name}\\{start_time_formatted}_VGA.mp4"): |
| 71 | + response = requests.get(vga_url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"}, cookies=cookies) |
| 72 | + with open(f"D:\\OvlerDrive\\OneDrive\\downloads\\{course_name}\\{start_time_formatted}_VGA.mp4", "wb") as f: |
| 73 | + f.write(response.content) |
49 | 74 |
|
50 |
| -# Process video list |
51 |
| -output_vga = ["#EXTM3U"] |
52 |
| -output_video1 = ["#EXTM3U"] |
53 |
| -for i in range(total_count): |
54 |
| - cover = covers[i] |
55 |
| - start_time = start_times[i].replace(":", "_") |
56 |
| - course_name = course_names[i] |
| 75 | + # 下载 Video1 视频 |
| 76 | + video1_url = cover.replace("/1/", "/0/").replace("000.jpg", "Video1.mp4") |
| 77 | + if not os.path.exists(f"D:\\OvlerDrive\\OneDrive\\downloads\\{course_name}\\Video1\\{start_time_formatted}_Video1.mp4"): |
| 78 | + response = requests.get(video1_url, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"}, cookies=cookies) |
| 79 | + if not os.path.exists(f"D:\\OvlerDrive\\OneDrive\\downloads\\{course_name}\\Video1"): |
| 80 | + os.makedirs(f"D:\\OvlerDrive\\OneDrive\\downloads\\{course_name}\\Video1") |
| 81 | + with open(f"D:\\OvlerDrive\\OneDrive\\downloads\\{course_name}\\Video1\\{start_time_formatted}_Video1.mp4", "wb") as f: |
| 82 | + f.write(response.content) |
| 83 | + time.sleep(0.1) |
57 | 84 |
|
58 |
| - vga_path = f"D:\\OvlerDrive\\OneDrive\\downloads\\{course_name}\\{start_time}_VGA.mp4" |
59 |
| - if not os.path.exists(vga_path): |
60 |
| - response = requests.post("http://localhost:16800/jsonrpc", json={ |
61 |
| - "jsonrpc": "2.0", |
62 |
| - "method": "aria2.addUri", |
63 |
| - "id": "QXJpYU5nXzE2NDY4MzM4NDJfMC4zNDc3MTcxOTgzNTA1NDQ1", |
64 |
| - "params": [[cover.replace("000.jpg", "VGA.mp4")], {"out": f"{course_name}/{start_time}_VGA.mp4"}] |
65 |
| - }) |
| 85 | +def get_live_streams(cookies, token): |
| 86 | + # 获取直播列表 |
| 87 | + today = datetime.datetime.now().strftime("%Y-%m-%d") |
| 88 | + fromday = (datetime.datetime.now() + datetime.timedelta(days=7)).strftime("%Y-%m-%d") |
| 89 | + response = requests.get(f"https://buct.smartclass.cn/Webapi/V1/Live/GetMyLiveList?csrkToken={token}&MajorUserID=&ClassroomID=&Sort=IsLiving%20desc%2CIsCompleted%2CStartTime&StartDate={today}&EndDate={fromday}&PageSize=50&PageNumber=1&attribute=&IncludePublic=true", headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"}, cookies=cookies) |
| 90 | + live_data = json.loads(response.text) |
66 | 91 |
|
67 |
| - video1_path = f"D:\\OvlerDrive\\OneDrive\\downloads\\{course_name}\\Video1\\{start_time}_Video1.mp4" |
68 |
| - if not os.path.exists(video1_path): |
69 |
| - response = requests.post("http://localhost:16800/jsonrpc", json={ |
70 |
| - "jsonrpc": "2.0", |
71 |
| - "method": "aria2.addUri", |
72 |
| - "id": "QXJpYU5nXzE2NDY4MzM4NDJfMC4zNDc3MTcxOTgzNTA1NDQ1", |
73 |
| - "params": [[cover.replace("000.jpg", "Video1.mp4")], {"out": f"{course_name}/Video1/{start_time}_Video1.mp4"}] |
74 |
| - }) |
| 92 | + # 获取直播流信息 |
| 93 | + total_count = live_data["TotalCount"] |
| 94 | + page2read = int(total_count * 0.02 + 1) |
| 95 | + vga_output = ["#EXTM3U"] |
| 96 | + for page in range(1, page2read + 1): |
| 97 | + response = requests.get(f"https://buct.smartclass.cn/Webapi/V1/Live/GetMyLiveList?csrkToken={token}&MajorUserID=&ClassroomID=&Sort=IsLiving%20desc%2CIsCompleted%2CStartTime&StartDate={today}&EndDate={fromday}&PageSize=50&PageNumber={page}&attribute=&IncludePublic=true", headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36"}, cookies=cookies) |
| 98 | + live_data = json.loads(response.text) |
| 99 | + for i in range(live_data["TotalCount"]): |
| 100 | + schedule_id = live_data["Data"][i]["ScheduleID"] |
| 101 | + title = live_data["Data"][i]["Title"] |
| 102 | + response = requests.post("https://buct.smartclass.cn/Live/GetLiveStreamInfo", data={"ScheduleId": schedule_id}, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"}, cookies=cookies) |
| 103 | + stream_data = json.loads(response.text) |
| 104 | + vga = stream_data["Value"]["LanLiveMainRtmpSourceStreamNames"][0] |
| 105 | + video1 = stream_data["Value"]["LanLiveMainRtmpSourceStreamNames"][1] |
| 106 | + if vga and vga not in vga_output: |
| 107 | + vga_output.append(f"#EXTINF:-1,{title}_vga") |
| 108 | + vga_output.append(vga) |
| 109 | + if video1 and video1 not in vga_output: |
| 110 | + vga_output.append(f"#EXTINF:-1,{title}_video1") |
| 111 | + vga_output.append(video1) |
| 112 | + time.sleep(0.1) |
75 | 113 |
|
76 |
| - if cover.replace("000.jpg", "VGA.mp4") not in output_vga: |
77 |
| - output_vga.append(f"#EXTINF:-1,{course_name}_vga") |
78 |
| - output_vga.append(cover.replace("000.jpg", "VGA.mp4")) |
79 |
| - if cover.replace("000.jpg", "Video1.mp4") not in output_video1: |
80 |
| - output_video1.append(f"#EXTINF:-1,{course_name}_video1") |
81 |
| - output_video1.append(cover.replace("000.jpg", "Video1.mp4")) |
82 |
| - time.sleep(0.1) |
| 114 | + with open("vga.m3u", "w", encoding="utf-8") as f: |
| 115 | + f.write("\n".join(vga_output)) |
83 | 116 |
|
84 |
| -# Save playlists |
85 |
| -with open("E:\\Video\\smartclass\\vga.m3u", "w", encoding="utf-8") as f: |
86 |
| - f.write("\n".join(output_vga)) |
| 117 | +def main(): |
| 118 | + cookies = login() |
| 119 | + token = get_csrf_token(cookies) |
| 120 | + download_videos(cookies, token) |
| 121 | + get_live_streams(cookies, token) |
87 | 122 |
|
88 |
| -with open("E:\\Video\\smartclass\\video1.m3u", "w", encoding="utf-8") as f: |
89 |
| - f.write("\n".join(output_video1)) |
| 123 | +if __name__ == "__main__": |
| 124 | + main() |
0 commit comments