#!/usr/bin/env python3 """ 简化版OJ学生做题数据查询脚本 使用方式: python scripts/get_student_oj.py --homework-id <作业ID> --student <学生姓名> 功能: 1. 登录OJ系统 2. 通过homework ID获取题目列表 3. 获取提交记录并解析学生做题情况 4. 输出Markdown格式的OJ数据 """ import io import re import sys from html import unescape from pathlib import Path # 修复Windows控制台编码 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace') import httpx def load_env(): """从.env文件加载配置""" env_path = Path(__file__).parent.parent / '.env' env = {} if env_path.exists(): for line in env_path.read_text(encoding='utf-8').split('\n'): line = line.strip() if line and not line.startswith('#') and '=' in line: key, value = line.split('=', 1) env[key] = value return env def strip_tags(html: str) -> str: """移除HTML标签""" text = re.sub(r"<[^>]+>", "", html) return unescape(text).replace("\xa0", " ").strip() def detect_status(row_html: str) -> str: """识别判题状态""" status_map = { "Accepted": "AC", "Wrong Answer": "WA", "Compile Error": "CE", "Time Limit Exceeded": "TLE", "Runtime Error": "RE", "Presentation Error": "PE", } for keyword, status in status_map.items(): if keyword in row_html: return status return "UNKNOWN" def get_student_oj_data(homework_id: str, student_name: str) -> str: """ 获取指定学生在指定作业中的OJ做题数据 Args: homework_id: 作业ID(如 6a2bbd65aeff4da880b8f01d) student_name: 学生姓名 Returns: Markdown格式的OJ数据 """ env = load_env() base_url = env.get('OJ_BASE_URL', 'https://oj.qonnwolf.com') username = env.get('OJ_USERNAME', '') password = env.get('OJ_PASSWORD', '') if not username or not password: return "❌ 错误:未配置OJ用户名或密码,请检查.env文件" # 1. 登录OJ client = httpx.Client(base_url=base_url, follow_redirects=True) try: # 先访问登录页面 client.get('/login') # 使用表单格式登录 form_data = { 'uname': username, 'password': password, 'rememberme': 'on', 'login_submit': '1' } login_resp = client.post('/login', data=form_data) login_resp.raise_for_status() # 检查登录是否成功 has_sid = any(c.name == "sid" for c in client.cookies.jar) if not has_sid: # 检查错误信息 if '密码错误' in login_resp.text or 'password' in login_resp.text.lower(): return "❌ 错误:OJ登录失败 - 密码错误" elif '不存在' in login_resp.text: return "❌ 错误:OJ登录失败 - 用户不存在" else: return "❌ 错误:OJ登录失败,请检查用户名密码" except Exception as e: return f"❌ 错误:OJ登录失败 - {e}" # 2. 获取作业题目列表 try: hw_resp = client.get(f'/homework/{homework_id}') if hw_resp.status_code != 200: return f"❌ 错误:获取作业详情失败 (HTTP {hw_resp.status_code})" # 解析题目列表 pattern = ( r'href="/p/([^"?]+)\?tid=' + re.escape(homework_id) + r'"[^>]*>([^<]+)(?: |\s)*([^<]*)' ) problems = re.findall(pattern, hw_resp.text) if not problems: return f"❌ 错误:作业 {homework_id} 中未找到题目" except Exception as e: return f"❌ 错误:获取题目列表失败 - {e}" # 3. 获取提交记录 try: record_resp = client.get(f'/record?tid={homework_id}&page=1') if record_resp.status_code != 200: return f"❌ 错误:获取提交记录失败 (HTTP {record_resp.status_code})" # 解析提交记录 rows = re.findall(r'