├── README.md ├── answer.py ├── config.json ├── main.py ├── parse_answer.py └── prase_dig.py /README.md: -------------------------------------------------------------------------------- 1 | # 新理念全自动答题 2 | 3 | Forked from lnnei/Auto-AnswerXinLinian 4 | 5 | Several Modifications have been done... 6 | ### 什么被提升了 7 | 8 | · 支持Part数量任意的测试,适用所有情况 9 | 10 | · 支持双项选择题,填空,翻译自动填写(支持所有题型) 11 | 12 | · 支持填写完成自动交卷,并开始下一次测试 13 | 14 | · 遍历所有页面寻找测试,若无测试则退出 15 | 16 | · 控分功能加入 17 | 18 | ### Todo List 19 | 20 | · 测试时间控制 21 | 22 | ### 他能做什么 23 | 24 | - 他可以在10秒钟之内完成答题。 25 | 26 | - 是的,他是全自动的。你不需要选择任何东西。 27 | 28 | - 100分,Yes!(可以自行控制分数) 29 | 30 | - 他能从服务器获取答案,并且用正则表达式很快的解析答案,完成答题。 31 | 32 | ### 你需要做什么 33 | 34 | - 你需要安装Python3以上版本,并且正确安装Requests库,selenium库,Chrome以及对应的WebDriver。 35 | 36 | - 你需要在`config.json`中编辑配置 37 | 38 | - 运行`main.py` 39 | 40 | - 除此之外你不需要做任何事。 41 | 42 | ### 配置说明 43 | 44 | `username,password`: As its name. 45 | 46 | `root`: 改成学校平台对应的地址 47 | -------------------------------------------------------------------------------- /answer.py: -------------------------------------------------------------------------------- 1 | #!python3 2 | import random 3 | import json 4 | import requests 5 | from prase_dig import * 6 | from os import path 7 | 8 | current_path = path.dirname(__file__) 9 | with open(current_path + '/config.json', "r", encoding='utf8') as f: 10 | config = json.load(f) 11 | root = config['root'] 12 | answerurl = root + "/Student/viewTestTask.aspx" 13 | ctoken = None 14 | s = requests.session() 15 | 16 | 17 | def randomnocache(): 18 | return str(random.random()) 19 | 20 | 21 | def getanswer(part, ttid, sheetid, sttid): 22 | data = "action=getPart&partnum=" + str(part) + "&ttid=" + str(ttid) + "&sheetid=" + str(sheetid) + "&sttid=" + str( 23 | sttid) + "&nocache=" + randomnocache() 24 | headers = { 25 | "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", 26 | "Accept-Language": "zh-CN,zh;q=0.9", 27 | "Referer": root+"/student/viewTestTask.aspx", 28 | "Content-Type": "application/x-www-form-urlencoded", 29 | } 30 | ans = s.post(url=answerurl, data=data, headers=headers) 31 | if ans.text.find("服务器错误") == -1: 32 | return ans.text 33 | 34 | 35 | def answer(ttid, sheetid, sttid): 36 | fo = open(current_path+'/temp/EnglishAnswer.html', "w+", encoding='utf-8') 37 | try: 38 | fo.write(getanswer(1, ttid, sheetid, sttid)) 39 | fo.write(getanswer(2, ttid, sheetid, sttid)) 40 | fo.write(getanswer(3, ttid, sheetid, sttid)) 41 | fo.write(getanswer(4, ttid, sheetid, sttid)) 42 | except: 43 | pass 44 | finally: 45 | fo.close() 46 | 47 | 48 | def prase_result(): 49 | dig = callback_dig() 50 | answer(dig[0], dig[1], dig[2]) 51 | print('解析成功') 52 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": "http://10.120.48.47/npels", 3 | "username": "1231231231", 4 | "password": "1231232321" 5 | } -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | from selenium.common.exceptions import TimeoutException 3 | from selenium.webdriver.common.by import By 4 | from selenium.webdriver.support import expected_conditions as EC 5 | from selenium.webdriver.support.wait import WebDriverWait 6 | from selenium.webdriver.support.ui import Select 7 | from time import sleep 8 | from os import remove, mkdir 9 | from os.path import exists 10 | from parse_answer import * 11 | from answer import * 12 | 13 | current_path = path.dirname(__file__) 14 | with open(current_path + '/config.json', "r", encoding='utf8') as f: 15 | config = json.load(f) 16 | 17 | safe_mode = input('想拿多少分?(最高100):') 18 | safe_mode = int(safe_mode) 19 | 20 | user = config['username'] 21 | passwd = config['password'] 22 | browser = webdriver.Chrome() 23 | browser.get(config['root']) 24 | wait = WebDriverWait(browser, 3) 25 | current = 1 # 题号 26 | ansll = [] # 答案列表 27 | question_quantity = 0 # 这张卷子的问题总数 28 | 29 | 30 | def login(name, password): 31 | try: 32 | sleep(0.5) 33 | wait.until(EC.presence_of_element_located( 34 | (By.CSS_SELECTOR, '#tbName'))).send_keys(name) 35 | wait.until(EC.presence_of_element_located( 36 | (By.CSS_SELECTOR, '#tbPwd'))).send_keys(password) 37 | wait.until(EC.element_to_be_clickable( 38 | (By.CSS_SELECTOR, '#btnLogin'))).click() 39 | except: 40 | login(name, password) 41 | 42 | 43 | def intotest(is_first=1): 44 | try: 45 | sleep(1) 46 | browser.switch_to.default_content() 47 | browser.switch_to.frame('mainFrame') 48 | print('switched') 49 | if is_first: 50 | try: 51 | wait.until(EC.element_to_be_clickable( 52 | (By.CSS_SELECTOR, '#ctl00_cphContent_divWarning > div > div.homework_3 > ul > li.homework_3_2 > span > a'))).click() 53 | except TimeoutException: 54 | browser.close() 55 | print('没有测试!!!') 56 | return False 57 | try: 58 | sleep(1) 59 | wait.until(EC.element_to_be_clickable( 60 | (By.XPATH, '//table[@class="DataGridTable"]/tbody/tr/td/span/span/input[@value!=" 查 看 "]'))).click() # 点进入测试的按钮 61 | wait3 = WebDriverWait(browser, 1) 62 | try: 63 | wait3.until(EC.alert_is_present()).accept() # 可能会出提示框,点掉 64 | except: 65 | pass 66 | return True 67 | except TimeoutException: 68 | try: 69 | wait.until(EC.element_to_be_clickable( 70 | (By.XPATH, '//*[@id="ctl00_ContentPlaceHolder1_CourseTestTask1_dgTestTask_ctl19_PAGER"]/div/ul/li[14]/a'))).click() # 下一页按钮 71 | return intotest(0) 72 | except TimeoutException: 73 | print('做完了') 74 | browser.close() 75 | return False 76 | 77 | except (TimeoutError, TimeoutException): 78 | intotest(is_first) 79 | 80 | 81 | def define_question_content(question): # 判断问题类型 82 | if question.find_element_by_xpath("./following-sibling::*[1]").tag_name == 'input': 83 | return 'fill_blank' 84 | elif question.find_element_by_xpath("./following-sibling::*[1]").tag_name == 'li': 85 | if question.find_element_by_xpath("./../li/input").get_attribute('type') == 'radio': 86 | return 'radio' 87 | if question.find_element_by_xpath("./../li/input").get_attribute('type') == 'text': 88 | return 'translation' 89 | elif question.find_element_by_xpath('..').tag_name == 'li': 90 | return 'reading' 91 | else: 92 | return '' 93 | 94 | 95 | def get_answers(): 96 | global ansll 97 | global question_quantity 98 | sleep(2) 99 | pageSource = browser.page_source 100 | try: 101 | with open(current_path+'/temp/source.html', 'w+', encoding='utf-8') as f: 102 | f.write(pageSource) 103 | except FileNotFoundError: 104 | mkdir(current_path + '/temp') 105 | with open(current_path+'/temp/source.html', 'w+', encoding='utf-8') as f: 106 | f.write(pageSource) 107 | 108 | prase_result() # get the answers and save them into EnglishAnswer.html 109 | ansll = callback(safe_mode) # get all of the answers 110 | question_quantity = len(ansll) 111 | 112 | 113 | def answer_part_x(part_x=1): 114 | global ansll 115 | global current 116 | global question_quantity 117 | browser.switch_to.default_content() 118 | wait.until(EC.presence_of_element_located( 119 | (By.CSS_SELECTOR, '#aPart'+str(part_x)))).click() # P 120 | browser.switch_to.frame('mainFrame') 121 | 122 | # anlist contains all the questions of current part 123 | anlist = wait.until(EC.presence_of_all_elements_located((By.XPATH, 124 | '//span[contains(@id,"question_")]'))) 125 | print(len(anlist)) 126 | 127 | for question in anlist: 128 | wait2 = WebDriverWait(question, 3) 129 | question_type = define_question_content(question) 130 | if question_type == 'radio': 131 | wait2.until(EC.element_to_be_clickable( 132 | (By.XPATH, '../li/input[@id="'+ansll[current-1]+'"]'))).click() 133 | print('第'+str(current)+'题是选择题,填了'+ansll[current-1]) 134 | if question_type == 'fill_blank': 135 | blank = wait2.until( 136 | EC.visibility_of_element_located((By.XPATH, './following-sibling::*[1]'))) 137 | blank.clear() 138 | blank.send_keys(ansll[current - 1]) 139 | print('第'+str(current)+'题是填空题,填了'+ansll[current-1]) 140 | if question_type == 'reading': 141 | wait2.until(EC.element_to_be_clickable( 142 | (By.XPATH, '../../li/input[@id="'+ansll[current-1]+'"]'))).click() 143 | print('第'+str(current)+'题是选择题,填了'+ansll[current-1]) 144 | if question_type == 'translation': 145 | # blank = question.find_element_by_xpath('../li/input') 146 | blank = wait2.until( 147 | EC.visibility_of_element_located((By.XPATH, '../li/input'))) 148 | blank.clear() 149 | blank.send_keys(ansll[current - 1]) 150 | print('第'+str(current)+'题是翻译题,填了'+ansll[current-1]) 151 | current += 1 152 | 153 | # it means when the test is finished, auto submit 154 | if current >= question_quantity: 155 | browser.switch_to.default_content() 156 | wait.until(EC.element_to_be_clickable( 157 | (By.XPATH, '//*[@id="divHeader"]/div/div[4]/ul[2]/li[3]/input'))).click() 158 | wait.until(EC.alert_is_present()).accept() 159 | 160 | 161 | def main(user, passwd): 162 | global current 163 | global question_quantity 164 | login(user, passwd) 165 | is_first = True 166 | while intotest(is_first): 167 | is_first = False 168 | get_answers() 169 | flag = 1 170 | current = 1 171 | 172 | # Auto finist Part 1 ~ Part n 173 | while current < question_quantity: 174 | answer_part_x(flag) 175 | flag += 1 176 | 177 | 178 | if __name__ == '__main__': 179 | main(user, passwd) 180 | -------------------------------------------------------------------------------- /parse_answer.py: -------------------------------------------------------------------------------- 1 | import re 2 | import json 3 | from os import path 4 | from random import choice 5 | 6 | 7 | def main(w=0): 8 | current_path = path.dirname(__file__) 9 | content = open(current_path+'/temp/EnglishAnswer.html', 10 | encoding='utf-8').read() 11 | result = re.findall(r"(.+答案:(.*?).+)", content) 12 | questions = re.findall('question_', content) 13 | if w: 14 | # 1 系数是保证你每次都上80,但偶尔会上90。改成1.2不会上90,经常上不了80 15 | w = int(len(questions) * (100-w) / 100 * 1) 16 | print('随机选择 '+str(w)+' 道题的答案') 17 | 18 | ans_list = [] 19 | for x in result: 20 | if '、' in x[1]: 21 | xlist = x[1].split('、') 22 | for y in xlist: 23 | if w != 0: 24 | ans_list.append( 25 | choice(['this', 'it', 'kind', 'so', 'and'])) # 随机从垃圾词汇中挑选一个 26 | w -= 1 27 | else: 28 | ans_list.append(y) 29 | else: 30 | random = choice(['A', 'B']) # 只选两个是因为可以同时兼容双选和多选 31 | ans = x[1] 32 | if w != 0: 33 | ans = random 34 | w -= 1 35 | # GET THE FUCKING ID!!!! 36 | id_list = re.findall('