Spaces:
Sleeping
Sleeping
import re | |
import threading | |
import time | |
from pathlib import Path | |
import gradio as gr | |
import requests | |
from tqdm import tqdm | |
import tempfile | |
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 | |
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}} | |
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=[]) | |
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=""): | |
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(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 | |
def save_config(uid, tlsysSessionId): | |
config_content = f"uid={uid}\ntlsysSessionId={tlsysSessionId}" | |
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".txt") as f: | |
f.write(config_content) | |
return f.name | |
def load_config(file): | |
if not file: | |
return None, None | |
with open(file.name, "r") as f: | |
content = f.read() | |
uid = re.search(r"uid=(\S+)", content) | |
tlsysSessionId = re.search(r"tlsysSessionId=(\S+)", content) | |
return (uid.group(1) if uid else None, (tlsysSessionId.group(1) if tlsysSessionId else None)) | |
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(scale=2): | |
config_upload = gr.File(label="上传配置文件", type="filepath", file_types=[".txt"]) | |
with gr.Column(scale=1): | |
load_config_btn = gr.Button("识别配置文件", variant="secondary") | |
save_config_btn = gr.Button("导出配置文件", variant="secondary") | |
with gr.Column(scale=2): | |
config_download = gr.File(label="下载配置文件", interactive=False) | |
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") | |
submit_btn.click( | |
fn=parse_homework, | |
inputs=[token, text_parse, homework_selection, 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=[homework_view], | |
outputs=[file_output] | |
) | |
# 配置文件功能绑定 | |
load_config_btn.click( | |
fn=load_config, | |
inputs=[config_upload], | |
outputs=[uid, tlsysSessionId] | |
) | |
save_config_btn.click( | |
fn=save_config, | |
inputs=[uid, tlsysSessionId], | |
outputs=[config_download] | |
) | |
if __name__ == "__main__": | |
demo.launch() |