def getPassedDetail(self, cid, pid): resp = RequestUtil.doGet(AojApi.getUrl('passedProblem'), {'id': cid}) soup = BeautifulSoup(resp.text, "lxml") p = soup.find('div', class_='nav', text=re.compile(r'.*' + pid + '.*')) if not p: PrintUtil.error("没有该题目...") sys.exit(0) infolist = [ 'title', 'content', 'descr_input', 'descr_output', 'ex_input', 'ex_output', 'code', 'score' ] j = 0 problem = Problem() problem.pid = '' problem.timeAndMem = '' for i in range(0, 31): s = '' if p.string is not None: s = p.string elif p.pre is not None: s = p.pre.string elif p.span is not None: s = p.span.string elif p.textarea is not None: s = p.textarea.string if s is not None and s.strip() != '': setattr(problem, infolist[j], s.strip()) j = j + 1 p = p.next_sibling return problem
def getProblemInfo(self, cid, pid): ctype = globalVar.BASE_CONF.get('contest', 'ctype') cpass = globalVar.BASE_CONF.get('contest', 'cpass') data = {'id': cid, 'type': ctype} pwdProbleUrl = globalVar.OJ_CONF.get('urls', 'pwdProblems') resp = RequestUtil.doGet(pwdProbleUrl, data) \ if cpass == '1' else RequestUtil.doGet(AojApi.getUrl('problems'), data) # 解析网页数据 soup = BeautifulSoup(resp.text, "lxml") pdiv = soup.find('div', id='title_' + pid) if not pdiv: PrintUtil.error("你已经AC了或者没有该题目") sys.exit(0) p = Problem() p.pid = re.sub("\D", "", pdiv['id']) p.title = pdiv.find('div', class_='nav').string.split('.')[1].strip() p.timeAndMem = pdiv.find('div', class_='common').string.strip() contentDiv = pdiv.find_all('div') p.content = contentDiv[3].pre.string p.descr_input = contentDiv[5].pre.string p.descr_output = contentDiv[7].pre.string p.ex_input = contentDiv[9].pre.string p.ex_output = contentDiv[11].pre.string p.code = '' return p
def input_name_pass_login(ojOperate): username = input(termcolor.colored('请输入用户名: ', 'cyan')) password = getpass.getpass(termcolor.colored('请输入密码: ', 'cyan')) loginSuccess = ojOperate.login(username, password) if loginSuccess: # 保存cookie RequestUtil.session.cookies.save(ignore_discard=True, ignore_expires=True) PrintUtil.info('登录成功!') # 保存账号密码 option = input(termcolor.colored(u'\n是否保存用户名及密码? (yes/no) ', 'cyan')) if option == 'yes': # 保存密码 try: globalVar.BASE_CONF.set('user', 'username', username) # 先简单base64编码加密意思意思... bytesString = password.encode(encoding="utf-8") encodestr = base64.b64encode(bytesString) globalVar.BASE_CONF.set('user', 'password', encodestr.decode(encoding='utf-8')) with open(globalVar.BASE_CONF_PATH, 'w') as fw: globalVar.BASE_CONF.write(fw) PrintUtil.success('保存密码成功 :)') except Exception as e: PrintUtil.info("保存密码失败 :(") PrintUtil.error(e) else: sys.exit(0)
def testCode(self, fileName): # 编译 compilep = subprocess.Popen(['g++', fileName], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) res = '' for line in compilep.stdout.readlines(): res = res + line.decode() if res.find('error') >= 0: PrintUtil.info('编译错误') PrintUtil.error(res) return # 执行 ## 读取测试数据 pid = fileName.split('.')[0] problem = self.getProblemInfo( globalVar.BASE_CONF.get('contest', 'cid'), pid) ex_input = problem.ex_input ex_output = problem.ex_output execp = subprocess.Popen(['./a.out'], shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) out, err = execp.communicate(input=ex_input.encode()) PrintUtil.info("测试输出:") print(out.decode(), end="") PrintUtil.info("正确输出:") print(ex_output, end="")
def use_commond(ojOperate): if arg_len == 3: arg2 = sys.argv[2] #if re.match('^\d+$', arg2): ojOperate.saveContestInfo(arg2) return PrintUtil.error("参数错误") help_commond()
def checkout_commond(): # 切换oj if arg_len == 3: globalVar.BASE_CONF.set('base', 'oj_name', sys.argv[2]) with open(globalVar.BASE_CONF_PATH, 'w') as fw: globalVar.BASE_CONF.write(fw) return PrintUtil.error("参数错误") help_commond()
def test_commond(ojOperate): if arg_len == 3: arg1 = sys.argv[1] arg2 = sys.argv[2] if arg1 == "test": ojOperate.testCode(arg2) return PrintUtil.error("参数错误") help_commond()
def passed_commond(ojOperate): if arg_len == 2: ojOperate.showPassed() return elif arg_len == 3 and re.match('^\d+$', sys.argv[2]): ojOperate.showPassedDetail(sys.argv[2]) return PrintUtil.error("参数错误") help_commond()
def submit_commond(ojOperate): if arg_len == 3: arg1 = sys.argv[1] arg2 = sys.argv[2] if arg1 == "submit": ojOperate.showSubmitResult(arg2) return PrintUtil.error("参数错误") help_commond()
def showContestList(self, containPassed): contestList = self.getContestList(containPassed) for c in contestList: if isinstance(c, Contest): c.problemDetail() else: PrintUtil.error('contest type error') break print(''.join(' id' + '\t' + '{:35}'.format('名称') + '语言' + '\t' + '结束时间' + '\t\t' + '描述'))
def login(self, username, password): data = {'email': username, 'passwd': password} resp = RequestUtil.doPost(url=AojApi.getUrl('login'), data=data) jdata = json.loads(resp.text) if jdata['code'] == 0 and jdata['response']['message'] == 'success': return True else: PrintUtil.error(jdata['errorMessage']) return False
def saveProblemList(self): PrintUtil.info('正在缓存题目信息...') pList = self.getProblemList(globalVar.BASE_CONF.get('contest', 'cid')) if not pList: PrintUtil.warn('获取题目信息失败') try: with open(globalVar.BASE_PATH + 'problemList', 'wb') as file_object: pickle.dump(pList, file_object) except Exception as e: PrintUtil.error('缓存失败 :(') print(e) pass
def list_commond(ojOperate): if arg_len == 3 or arg_len == 4: arg2 = sys.argv[2] if arg2 == "-c": if arg_len == 4 and sys.argv[3] == '-a': ojOperate.showContestList(True) else: ojOperate.showContestList(False) return elif arg2 == "-p": ojOperate.showProblemList() return PrintUtil.error("参数错误\n") help_commond()
def showSubmitResult(self, fileName): pid = fileName.split('.')[0] if not re.match('^\d+$', pid): PrintUtil.error("文件命名错误,请以'id.'开头, 例: 70.简单求和.c") return try: f = open(fileName, "r") except: PrintUtil.error("没有找到文件.检查文件名是否有误") return code = f.read() f.close() self.submitCode(code, pid)
def check_login(ojOperate): # 判断是否登录 if not os.path.exists(globalVar.BASE_PATH + ".cookies/" + globalVar.OJ_NAME): logo = "" \ " \n" \ " █████╗ ██████╗ ██╗ \n" \ " ██╔══██╗ ██╔═══██╗ ██║ \n" \ " ███████║ ██║ ██║ ██║ \n" \ " ██╔══██║ ██║ ██║ ██ ██║ \n" \ " ██║ ██║ ╚██████╔╝ ╚█████╔╝ \n" \ " ╚═╝ ╚═╝ ╚═════╝ ╚════╝ \n" \ PrintUtil.info(logo) PrintUtil.info("欢迎使用 aoj ,登录后享受丝滑刷题") PrintUtil.info("使用\'aoj help\' 查看帮助信息") sys.exit(0) elif not ojOperate.isLogin(): PrintUtil.info('登录失效') # 验证用户是否已经保存密码 try: username = globalVar.BASE_CONF.get('user', 'username') encodePassword = globalVar.BASE_CONF.get('user', 'password') # 解码 password = base64.b64decode( encodePassword.encode('utf-8')).decode('utf-8') if username == '' or password == '': input_name_pass_login(ojOperate) else: # 账号密码不为空, 尝试自动登录 PrintUtil.info('正在尝试重新登录...') isSuccess = ojOperate.login(username, password) if isSuccess: # 保存cookie RequestUtil.session.cookies.save(ignore_discard=True, ignore_expires=True) PrintUtil.success("自动登录成功!") else: globalVar.BASE_CONF.set('user', 'password', '') with open(globalVar.BASE_CONF_PATH, 'w') as fw: globalVar.BASE_CONF.write(fw) PrintUtil.error("尝试自动登录失败, 手动登录 :(") input_name_pass_login(ojOperate) except KeyboardInterrupt: pass except: PrintUtil.error("登录失败,请稍后重试 :<") sys.exit(0)
def saveContestInfo(self, cid): PrintUtil.info('正在获取比赛信息...') resp = RequestUtil.doGet(AojApi.getUrl('contest')) jdata = json.loads(resp.text) datalist = jdata.get('list') ctype = '1' # 类型 ...1代表c 0表示java cpass = '******' # 是否需要密码 0为不需要 # 根据比赛id查找比赛类型 for data in datalist: if str(data['id']) == cid: ctype = data['isjava'] break # 判断是否需要密码 data = {'id': cid, 'type': ctype} needPasswordTest = RequestUtil.doGet(AojApi.getUrl('problems'), data) # Struts Problem Report页面报错编码不是utf-8 if 'ISO-8859-1' in needPasswordTest.encoding: PrintUtil.error('没有该比赛 -_-\"') return try: # 如果不需要密码就没有这个头信息会抛异常,比之前的解析内容判断速度快,虽然不雅 hasKeyContentLength = needPasswordTest.headers['Content-Length'] cpass = '******' passwd = input(termcolor.colored(u'你需要输入密码参加该比赛: ', 'green')) joindata = {'password': passwd, 'id': cid} passwdisRight = RequestUtil.doGet(AojApi.getUrl('pwdProblems'), joindata) if passwdisRight.text == 'no': PrintUtil.error('密码错误!') return except: pass # 保存比赛信息 globalVar.BASE_CONF.set('contest', 'cid', cid) globalVar.BASE_CONF.set('contest', 'ctype', ctype) globalVar.BASE_CONF.set('contest', 'cpass', cpass) with open(globalVar.BASE_PATH + 'base.conf', 'w') as fw: globalVar.BASE_CONF.write(fw) self.saveProblemList() PrintUtil.info("设置比赛成功! 'coj list -p' 显示题目列表\n")
def getPassedList(self, cid): resp = RequestUtil.doGet(AojApi.getUrl('passedProblem'), {'id': cid}) soup = BeautifulSoup(resp.text, "lxml") titles = soup.find_all('div', class_='nav') if not titles: PrintUtil.error("你还没有做过此比赛的题目 :)") sys.exit(0) problemList = [] for t in titles: title = t.string.strip().split('.')[1] tempStrs = title.split('(') p = Problem() p.score = int(re.sub("\D", "", tempStrs[len(tempStrs) - 1])) p.title = title.split('(')[0].strip() p.pid = t.string.strip().split('.')[0] problemList.append(p) return problemList
def show_commond(ojOperate): if arg_len == 3: arg2 = sys.argv[2] if re.match('^\d+$', arg2): ojOperate.showProblemDetail(arg2) return elif arg2 == "ranking": ojOperate.showRanking() return elif arg_len == 5: arg2 = sys.argv[2] arg3 = sys.argv[3] arg4 = sys.argv[4] if re.match('\d+', arg2) and arg3 == '-g' and re.match( r'^(java|c|cpp)$', arg4): ojOperate.showProblemDetail(arg2) ojOperate.genCode(arg2, arg4) return PrintUtil.error("参数错误") help_commond()
def login(self, username, password): # 验证码识别率较低..索性尝试5次 tryloginTime = 5 while (tryloginTime > 0): resp = RequestUtil.doPost(url=AojApi.getUrl('login'), data=self.getLoginData( username, password)) soup = BeautifulSoup(resp.text, "lxml") divlist = soup.find_all('div', class_='user') if len(divlist) > 3: info = divlist[3].font.string if info != "验证码有误": PrintUtil.error(info) return False else: return True tryloginTime = tryloginTime - 1 if tryloginTime <= 0: PrintUtil.error("oooops...验证码识别失败,再试试?")
def getRankingList(self, cid): rankData = {"id": cid} resp = RequestUtil.doGet(AojApi.getUrl('rank'), rankData) soup = BeautifulSoup(resp.text, "lxml") rankingTr = soup.find_all('tr', id=re.compile('\d*')) if not rankingTr: PrintUtil.error("没有该比赛排名...重新选择比赛") sys.exit(0) rList = [] for tr in rankingTr: stu = UserInfo() td = tr.find_all('td') stu.rank = td[0].div.string stu.username = td[1].div.string stu.name = td[2].div.string stu.stuid = td[3].div.string stu.college = td[4].div.string stu.major = td[5].div.string stu.score = td[6].div.string stu.subTime = td[7].div.string rList.append(stu) return rList
def submitCode(self, code, pid): subData = { 'answer': code, 'id': pid, 'type': globalVar.BASE_CONF.get('contest', 'ctype') } resp = RequestUtil.doPost(AojApi.getUrl('submitCode'), subData) # {"id":"125","result":"Wrong Answer.","score":0,"time":"21:34:35"} try: jdata = json.loads(resp.text) result = jdata['result'] score = jdata['score'] time = jdata['time'] color = "red" if result == "Answer Correct.": color = "green" print( termcolor.colored(result, color) + '\n' + "得分:" + termcolor.colored(str(score), color) + '\n' + "提交时间:" + termcolor.colored(time, color)) except: PrintUtil.error('oops!提交出错了,请重新提交. *_*.')
def aoj_cli_main(): if arg_len < 2: PrintUtil.error("参数错误") help_commond() return arg1 = sys.argv[1] # 不需要判断登录的命令 if arg1 == "help": help_commond() sys.exit(0) if arg1 == "checkout": checkout_commond() sys.exit(0) # 获取 对应oj 的操作类 try: module = __import__( globalVar.OJ_NAME + '.' + globalVar.OJ_NAME + 'Operate', globals(), locals(), [globalVar.OJ_NAME + 'Operate']) ojClass = getattr(module, globalVar.OJ_NAME.capitalize() + 'Operate') ojOperate = ojClass() except ModuleNotFoundError: # todo:添加支持oj列表 PrintUtil.error("不支持oj: " + globalVar.OJ_NAME + ", 使用 aoj checkout 'oj name' 切换") sys.exit(0) if arg1 == "login": input_name_pass_login(ojOperate) sys.exit(0) check_login(ojOperate) if arg1 == "list": list_commond(ojOperate) elif arg1 == "use": use_commond(ojOperate) elif arg1 == "show": show_commond(ojOperate) elif arg1 == "submit": submit_commond(ojOperate) elif arg1 == "passed": passed_commond(ojOperate) elif arg1 == "test": test_commond(ojOperate) else: PrintUtil.error("参数错误") help_commond()