import json import os from pathlib import Path import re import threading import time from tkinter import filedialog import traceback import gradio as gr import requests from tqdm import tqdm import tempfile lock = threading.Lock() event = threading.Event() requests.packages.urllib3.disable_warnings() reference_subject = { '语文': '01', '历史': '12', '数学': '02', '生物': '13', '英语': '03', '通用技术': '102', '信息技术': '26', '物理': '05', '政治': '27', '化学': '06', '地理':"14" } subject_codes={ '01': '语文', '12': '历史', '02': '数学', '13': '生物', '03': '英语', '102': '通用技术', '26': '信息技术', '05': '物理', '27': '政治', '06': '化学', '14':'地理' } headers = [ { "Accept": "application/json, text/plain, */*", "Accept-Encoding": "gzip, deflate, br, zstd", "Accept-Language": "zh-CN,zh;q=0.9", "Connection": "keep-alive", "Host": "www.zhixue.com", "Referer": "https://www.zhixue.com/middlehomework/web-student/views/", "Sec-Fetch-Dest": "empty", "Sec-Fetch-Mode": "cors", "Sec-Fetch-Site": "same-origin", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36", "appName": "com.iflytek.zxzy.web.zx.stu", "sec-ch-ua": '"Not A(Brand";v="8", "Chromium";v="132", "Google Chrome";v="132"', "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": '"Windows"' }, { "Host": "www.zhixue.com", "sucOriginAppKey": "zhixue_student", "User-Agent": "zhixue_student/1.0.2026 (iPhone; iOS 16.2; Scale/3.00)", "appName": "com.zhixue.student", "Connection": "keep-alive", "Accept-Language": "zh-Hans-CN;q=1, zh-Hant-CN;q=0.9, en-CN;q=0.8", "Accept": "*/*", "Accept-Encoding": "gzip, deflate, br" }, { "Host": "mhw.zhixue.com", "Content-Type": "application/json", "Accept": "application/json, text/plain, */*", "appName": "com.zhixue.student", "sucOriginAppKey": "zhixue_student", "Accept-Language": "zh-CN,zh-Hans;q=0.9", "Origin": "https://mhw.zhixue.com", "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 16_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko)", "Referer": "https://mhw.zhixue.com/zhixuestudent/views/homeworkReport/homework-report.html", "Accept-Encoding": "gzip, deflate, br", "Connection": "keep-alive" } ] def get_token(): global token response = requests.get("https://www.zhixue.com/middleweb/newToken", headers=headers[0], verify=False) response.encoding = "utf-8" response = response.json() result = response["result"]["token"] if result: token = result return True else: print("获取 token 失败。") return False def format_time(timestamp): return time.strftime("%Y-%m-%d %H:%M", time.localtime(timestamp // 1000)) def get(url): headers[1].update({"Host": url.split("/")[2], "sucUserToken": token}) response = requests.get(url, headers=headers[1], verify=False) response.encoding = "utf-8" return response.json() def post(url, data): headers[2].update({ "Host": url.split("/")[2], "Origin": f'https://{url.split("/")[2]}', "sucUserToken": token, "Authorization": token }) response = requests.post(url, headers=headers[2], json=data, verify=False) response.encoding = "utf-8" return response.json() def parse_range(s, max_value): result = [] for item in s.split(): if "-" in item: l = item.split("-") if len(l) == 2 and l[0].isdigit() and l[1].isdigit(): begin = int(l[0]) - 1 end = int(l[1]) - 1 if not (begin < 0 and end < 0 or begin >= max_value and end >= max_value): step = -1 if begin > end else 1 for i in range(begin, end + step, step): if 0 <= i < max_value and not i in result: result.append(i) elif item.isdigit(): n = int(item) - 1 if 0 <= n < max_value and not n in result: result.append(n) return result def to_file(file, source_type, name=""): result = ({"name": name or Path(file).name, "path": file, "is_text": bool(name)} if isinstance(file, str) else {"name": name, "path": file["description"], "is_text": True} if file["fileType"] == 5 else {"name": file.get("name", "") or Path(file["path"]).name, "path": file["path"], "is_text": False}) result["name"] = re.sub('[\\\\/:*?"<>|]', "_", result["name"]) result["type"] = source_type return result # 修改点1:添加uid参数 def analyze_homework(homework, include_text, uid): hwId = homework["hwId"] hwType = homework["hwType"] stuHwId = homework["stuHwId"] file_list = [] data = {"base": {"appId": "APP"}, "params": {"hwId": hwId, "stuHwId": stuHwId, "studentId": uid}} # 使用传入的uid值 if hwType == 102: response = post("https://mhw.zhixue.com/hwreport/question/getStuReportDetail", data) if "result" in response: result = response["result"] file_list.append(to_file(result["hwDescription"], "题目", result["hwTitle"] + "_说明.txt")) for problem in result["mainTopics"]: content = problem["content"] + problem["answerHtml"] + problem["analysisHtml"] file_list += [to_file(path, "题目") for path in re.findall('bigger="(.+?)"', content)] file_list += [to_file(path, "提交") for item in problem["subTopics"] for path in item["answerResList"]] elif hwType == 105: response = post("https://mhw.zhixue.com/hw/homework/attachment/list", data) file_list += [to_file(item, "题目") for item in response["result"]] response = post("https://mhw.zhixue.com/hwreport/question/getStuReportDetail", data) if "result" in response: result = response["result"] file_list.append(to_file(result["hwDescription"], "题目", result["hwTitle"] + "_说明.txt")) file_list += [to_file(item, "答案") for item in result.get("answerAttachList", [])] for problem in result["mainTopics"]: file_list += [to_file(path, "提交") for item in problem["subTopics"] for path in item["answerResList"]] elif hwType == 107: response = post("https://mhw.zhixue.com/hw/clock/answer/getClockHomeworkDetail", data) result = response["result"] file_list.append(to_file(result["description"], "题目", result["title"] + "_说明.txt")) file_list += ([to_file(item, "题目") for item in result.get("hwTopicAttachments", [])] + [to_file(item, "答案") for item in result.get("hwAnswerAttachments", [])] + [to_file(item, "答案") for item in result["hwClockRecordPreviewResponses"][0].get("teacherAnswerAttachments", [])] + [to_file(item, "提交", result["title"] + "_提交.txt") for item in result["hwClockRecordPreviewResponses"][0].get("answerAttachments", [])]) file_list = [file for file in file_list if file["path"] and (include_text or not file["is_text"])] return file_list def query_homework(uid, tlsysSessionId, subject, status, max_count): headers[0].update({"Cookie": f"tlsysSessionId={tlsysSessionId}"}) successful = get_token() if not successful: return "获取 token 失败","" page_size = max_count if subject == ["语文", "数学", "英语", "物理", "化学", "生物", "地理", "历史", "政治",'通用技术', '信息技术']: subjects = ["-1"] else: subjects = [reference_subject[i] for i in subject] if status == "全部": status = "" elif status == "已完成": status = "1" else: status = "0" fetch_list = [] if status != "1": fetch_list += [{"subject": subject, "status": 0} for subject in subjects] if status != "0": fetch_list += [{"subject": subject, "status": 1} for subject in subjects] global homework_list homework_list = [] timestamps = [int(time.time() * 1000)] * len(fetch_list) finished = [False] * len(fetch_list) while not all(finished): print("\x9B1F\x9B0J", end="") index = len(homework_list) for i in tqdm(range(len(fetch_list)), unit=""): if finished[i]: continue response = get("https://mhw.zhixue.com/homework_middle_service/stuapp/getStudentHomeWorkList" f'?completeStatus={fetch_list[i]["status"]}&createTime={timestamps[i]}&pageIndex=2' f'&pageSize={page_size}&subjectCode={fetch_list[i]["subject"]}&token={token}') if response["code"] != 200: raise RuntimeError("获取作业列表失败") result_list = response["result"]["list"] homework_list += result_list if len(result_list) < page_size: finished[i] = True if result_list: timestamps[i] = result_list[-1]["beginTime"] print("\x9B1F\x9B0J", end="") homework_list_temp=[] global homework_list_oringin homework_list_oringin = homework_list for i in range(index, len(homework_list)): begin_time = format_time(homework_list[i]["beginTime"]) end_time = format_time(homework_list[i]["endTime"]) homework_list_temp.append(f"[{homework_list[i]['subjectName']}]|{homework_list[i]['hwTitle']}|{begin_time}-{end_time}") homework_list = homework_list_temp return token, gr.update(choices=homework_list, value=[]) # 修改点2:添加uid参数 def parse_homework(token, include_text, homework_selection, uid): result = [] for i in homework_selection: for j in range(len(homework_list)): if i == homework_list[j]: result.append(j) selected_homework = result file_list = [] for i in tqdm(selected_homework, unit=""): # 修改点3:传递uid参数 file_list += analyze_homework(homework_list_oringin[i], include_text, uid) global file_list_output file_list_output = [file["name"] for file in file_list] global homework_downloaded_path homework_downloaded_path = [file["path"] for file in file_list] global homework_is_text homework_is_text = [file["is_text"] for file in file_list] return gr.update(choices=file_list_output, value=[]) def download_file(token, homework_view): download_list = [] for i in homework_view: for j in range(len(file_list_output)): if i == file_list_output[j]: if not homework_is_text[j]: download_list.append(homework_downloaded_path[j]) else: with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".txt") as f: f.write(homework_downloaded_path[j]) temp_path = f.name download_list.append(temp_path) return download_list with gr.Blocks(title="智学网作业获取器") as demo: gr.Markdown("# 🚀 智学网作业获取器") gr.Markdown("## Backfront Created by Levrium,UI Design by Start_ten") gr.Markdown("操作说明请见https://zhuanlan.zhihu.com/p/691808543") with gr.Row(): with gr.Column(): gr.Markdown("### 📝 查询作业") uid = gr.Textbox( label="uid", placeholder="请输入uid...", ) tlsysSessionId = gr.Textbox( label="tlsysSessionId", placeholder="请输入tlsysSessionId...", ) with gr.Row(): with gr.Column(scale=2): subject = gr.CheckboxGroup( choices=["语文", "数学", "英语", "物理", "化学", "生物", "地理", "历史", "政治",'通用技术', '信息技术'], label="具体学科", value=["语文", "数学", "英语", "物理", "化学", "生物", "地理", "历史", "政治",'通用技术', '信息技术'] ) with gr.Column(scale=1): all_chosen = gr.Button( value="全选", variant="secondary" ) all_chosen.click( fn=lambda: ["语文", "数学", "英语", "物理", "化学", "生物", "地理", "历史", "政治",'通用技术', '信息技术'], inputs=[], outputs=[subject] ) all_clear = gr.Button( value="全不选", variant="secondary" ) all_clear.click( fn=lambda: [], inputs=[], outputs=[subject] ) status = gr.Radio( choices=["全部", "已完成", "未完成"], label="作业状态", value="全部" ) max_count = gr.Slider( label="最大请求作业数", value=10, minimum=1, maximum=50, step=1 ) with gr.Column(): token = gr.Textbox( label="TOKEN", interactive=False ) homework_selection = gr.CheckboxGroup( label="作业列表(可多选)", choices=[], interactive=True ) submit_btn = gr.Button("查询作业", variant="primary") submit_btn.click( fn=query_homework, inputs=[uid, tlsysSessionId, subject, status, max_count], outputs=[token, homework_selection ] ) gr.Markdown("---") with gr.Row(): with gr.Column(): gr.Markdown("### 📄 解析作业并下载") text_parse = gr.Checkbox( label="是否解析题目、提交的文本?", value=False ) homework_view = gr.CheckboxGroup( label="作业内容", choices=[], interactive=True ) submit_btn = gr.Button("解析作业", variant="primary") # 修改点4:添加uid输入 submit_btn.click( fn=parse_homework, inputs=[token, text_parse, homework_selection, uid], # 添加uid输入 outputs=[homework_view, ] ) with gr.Column(): file_output = gr.File(label="作业文件", interactive=False) download_btn = gr.Button("下载作业", variant="primary") download_btn.click( fn=download_file, inputs=[token, homework_view], outputs=[file_output] ) if __name__ == "__main__": demo.launch()