Created
September 17, 2025 05:59
-
-
Save NoNormalCreeper/46ab1ef93dceae1286f398848f999792 to your computer and use it in GitHub Desktop.
本次班级互评的问卷星自动打分脚本
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import time | |
| import sys | |
| import threading | |
| try: | |
| import keyboard # for hotkey / key events | |
| except ImportError: | |
| keyboard = None | |
| try: | |
| import pyautogui # for typing | |
| except ImportError: | |
| pyautogui = None | |
| ANSWERS = ["22", "22", "18", "13", "13"] # 默认分数 | |
| ANSWERS_2 = ["25", "25", "20", "15", "15"] | |
| EXCELLENT_STUDENTS = [2, 3, 4, 11, 25, 26, 30] # 打高分的学生编号,以问卷中的为准 | |
| GROUP_COUNT = 29 | |
| START_KEY = "p" # 用户按下 P 键开始 | |
| ABORT_KEY = "esc" # 用户按下 ESC 立即中止 | |
| COUNTDOWN_SECONDS = 5 | |
| INTER_ANSWER_DELAY = 0.1 # 每个答案之间等待 | |
| TYPE_CHAR_INTERVAL = 0.02 # 输入每个答案时字符间隔(更像人工) | |
| # 已更新:逐个答案后立即 Tab | |
| action_lock = threading.Lock() | |
| should_abort = False | |
| def ensure_libs(): | |
| missing = [] | |
| if keyboard is None: | |
| missing.append("keyboard") | |
| if pyautogui is None: | |
| missing.append("pyautogui") | |
| if missing: | |
| print("缺少依赖,请先安装: pip install " + " ".join(missing)) | |
| sys.exit(1) | |
| def abort_listener(): | |
| global should_abort | |
| if keyboard is None: | |
| return | |
| while True: | |
| if keyboard.is_pressed(ABORT_KEY): | |
| with action_lock: | |
| should_abort = True | |
| break | |
| time.sleep(0.05) | |
| def log(msg: str): | |
| ts = time.strftime('%H:%M:%S') | |
| print(f"[{ts}] {msg}") | |
| def wait_for_start_key(): | |
| log(f"等待你按下 '{START_KEY.upper()}' 键以启动 (ESC 终止)...") | |
| while True: | |
| if keyboard.is_pressed(ABORT_KEY): | |
| return False | |
| if keyboard.is_pressed(START_KEY): | |
| return True | |
| time.sleep(0.05) | |
| def countdown(seconds: int): | |
| for remaining in range(seconds, 0, -1): | |
| with action_lock: | |
| if should_abort: | |
| return False | |
| log(f"倒计时 {remaining} 秒...") | |
| time.sleep(1) | |
| return True | |
| def type_answer(text: str, group_idx: int, idx_in_group: int): | |
| log(f"输入 第{group_idx}组 第{idx_in_group}空 -> {text}") | |
| pyautogui.typewrite(text, interval=TYPE_CHAR_INTERVAL) | |
| def main(): | |
| ensure_libs() | |
| # 后台监听 ESC | |
| t = threading.Thread(target=abort_listener, daemon=True) | |
| t.start() | |
| if not wait_for_start_key(): | |
| log("已取消。") | |
| return | |
| log(f"将在 {COUNTDOWN_SECONDS} 秒后开始,请切换到浏览器并将光标放在第一题第一个输入框内。") | |
| if not countdown(COUNTDOWN_SECONDS): | |
| log("已取消。") | |
| return | |
| log("开始自动填写... (ESC 可随时终止)") | |
| for group_idx in range(1, GROUP_COUNT + 1): | |
| with action_lock: | |
| if should_abort: | |
| break | |
| log(f"开始填写第 {group_idx}/{GROUP_COUNT} 组") | |
| if group_idx + 1 in EXCELLENT_STUDENTS: | |
| current_answers = ANSWERS_2 | |
| else: | |
| current_answers = ANSWERS | |
| for i, ans in enumerate(current_answers, start=1): | |
| with action_lock: | |
| if should_abort: | |
| break | |
| type_answer(ans, group_idx, i) | |
| time.sleep(INTER_ANSWER_DELAY) | |
| keyboard.send('tab') | |
| if should_abort: | |
| break | |
| # keyboard.send('tab') # 额外一次跳到下一题第一空 | |
| log(f"第 {group_idx} 组完成,跳到下一题。") | |
| time.sleep(0.25) | |
| if should_abort: | |
| log("用户终止。") | |
| else: | |
| log("全部填写完成(未提交)。") | |
| if __name__ == "__main__": | |
| try: | |
| main() | |
| except KeyboardInterrupt: | |
| log("用户通过 Ctrl+C 中断。") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment