diff --git a/robots/hduoj.py b/robots/hduoj.py new file mode 100644 index 0000000..2ab1dea --- /dev/null +++ b/robots/hduoj.py @@ -0,0 +1,155 @@ +# coding=utf-8 +import re +import requests +from .robot import Robot +from .exceptions import AuthFailed, RequestFailed, RegexError, SubmitProblemFailed +from .utils import Language, Result + + +class HduojRobot(Robot): + def check_url(self, url): + regex = r"^http://acm.hdu.edu.cn/showproblem.php\?pid=\d{4}$" + return re.compile(regex).match(url) is not None + + def login(self, username, password): + r = self.post("http://acm.hdu.edu.cn/userloginex.php?action=login", + data={"username": username, + "userpass": password, + "login": "Sign In"}, + headers={"Content-Type": "application/x-www-form-urlencoded", + "Referer": "http://acm.hdu.edu.cn/"}) + # 登陆成功会重定向到首页,否则200返回错误页面 + if r.status_code != 302: + raise AuthFailed("Failed to login Hduoj") + + self.cookies = dict(r.cookies) + + @property + def is_logged_in(self): + r = self.get("http://acm.hdu.edu.cn/control_panel.php", cookies=self.cookies) + # 登录状态是200,否则302到登陆页面 + return r.status_code == 200 + + def get(self, url, headers=None, cookies=None, allow_redirects=False): + r = super().get(url, headers=headers, cookies=cookies, allow_redirects=allow_redirects) + r.encoding = "gb2312" + return r + + def _regex_page(self, url, regex): + r = self.get(url) + self.check_status_code(r) + data = {} + for k, v in regex.items(): + items = re.compile(v).findall(r.text) + if not items: + if k == "spj": + data[k] = False + elif k == "hint": + data["hint"] = None + else: + raise RegexError("No such data") + if k == "samples": + data[k] = [{"input": items[0], "output": items[1]}] + elif items: + if k == "spj": + data[k] = True + else: + data[k] = self._clean_html(items[0]) + data["memory_limit"] = int(data["memory_limit"]) // 1024 + data["time_limit"] = int(data["time_limit"]) + + return data + + def get_problem(self, url): + if not self.check_url(url): + raise RequestFailed("Invaild Hduoj url") + regex = {"title": r"

(.*)

", + "time_limit": r"Time Limit:\s*[\d]*/([\d]*)\s*MS", + "memory_limit": r"Memory Limit:\s*[\d]*/([\d]*)\s*K", + "description": r"Problem Description\s*
([\s\S]*?)
", + "input_description": r"Input\s*
([\s\S]*?)
", + "output_description": r"Output\s*
([\s\S]*?)
", + "hint": r"Hint(?:[\s\S]*?Hint[\s\S]*?|\s*)([\s\S]*?)", + "spj": r"Special Judge", + "samples": r'Courier New,Courier,monospace;">([\s\S]*?)(?:)'} + problem_id = re.compile(r"\d{4}").search(url).group() + data = self._regex_page(url, regex) + data["problem_id"] = problem_id + data["submit_url"] = "http://acm.hdu.edu.cn/submit.php?action=submit" + return data + + def submit(self, submit_url, language, code, origin_id): + code = code.encode("gb2312") + if language == Language.C: + language = "1" + elif language == Language.CPP: + language = "0" + else: + language = "5" + + r = self.post(submit_url, data={"check": "0", "problemid": origin_id, + "language": language, + "usercode": code}, + cookies=self.cookies, + headers={"Content-Type": "application/x-www-form-urlencoded", + "Referer": submit_url}) + + if r.status_code != 302: + raise SubmitProblemFailed("Faild to submit problem, url: %s, status code %d" % (submit_url, r.status_code)) + + def get_result(self, submission_id, username): + status_url = r"http://acm.hdu.edu.cn/status.php?&user=" + username + r = self.get(status_url, + headers={"Refer": status_url}) + self.check_status_code(r) + + data = re.compile(r"(\d+)\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:[\s\S]*?)>" + r"(.*?)[\s\S]*?(\d*)MS(\d*)K").findall(r.text) + + submission_id = data[0][0] + code = data[0][1] + + if code == "Accepted": + result = Result.accepted + elif code in ["Queuing", "Compiling", "Running"]: + result = Result.waiting + elif code == "Presentation Error": + result = Result.format_error + elif code == "Wrong Answer": + result = Result.wrong_answer + elif code == "Runtime Error": + result = Result.runtime_error + elif code == "Time Limit Exceeded": + result = Result.time_limit_exceeded + elif code == "Memory Limit Exceeded": + result = Result.memory_limit_exceeded + elif code == "Output Limit Exceeded": + result = Result.runtime_error + elif code == "Compilation Error": + result = Result.compile_error + elif code == "System Error": + result = Result.system_error + else: + result = Result.runtime_error + + if data[0][2]: + cpu_time = int(data[0][2]) + else: + cpu_time = None + + if data[0][3]: + memory = int(data[0][3]) + else: + memory = None + + error = None + + if result == Result.compile_error: + r = self.get(r"http://acm.hdu.edu.cn/viewerror.php?rid=" + submission_id, + headers={"Referer": "http://acm.hdu.edu.cn/status.php?first=&pid=&lang=0&status=0&user=" + username}) + self.check_status_code(r) + error = self._clean_html(str(re.compile("
([\s\S]*)
").findall(r.text))) + + return {"result": result, "cpu_time": cpu_time, "memory": memory, + "info": {"result_text": self._clean_html(data[0][1])}, "error": error} + diff --git a/robots/pat.py b/robots/pat.py index 110bd0c..fe84101 100644 --- a/robots/pat.py +++ b/robots/pat.py @@ -6,9 +6,12 @@ from .utils import Language, Result class PATRobot(Robot): - def __init__(self, cookies=None): + def __init__(self, cookies=None, token=""): super().__init__(cookies=cookies) - self.token = "" + self.token = token + + def save(self): + return {"cookies": self.cookies, "token": self.token} def check_url(self, url): regex = r"^https://www.patest.cn/contests/pat-(a|b|t)-practise/1\d{3}$" @@ -56,7 +59,13 @@ class PATRobot(Robot): "submit_url": r'
'} data = self._regex_page(url, regex) data["id"] = problem_id + data["time_limit"] = int(data["time_limit"]) + data["memory_limit"] = int(data["memory_limit"]) // 1024 data["submit_url"] = "https://www.patest.cn" + data["submit_url"] + # pat上都没有提示 + data["hint"] = None + # pat没有spj + data["spj"] = False return data def _regex_page(self, url, regex): diff --git a/robots/robot.py b/robots/robot.py index c52e076..6810b82 100644 --- a/robots/robot.py +++ b/robots/robot.py @@ -44,7 +44,8 @@ class Robot(object): "samples": [{"input": String, "output": String}], "spj": True/False, "time_limit": Int ms, - "memory_limit": Int M} + "memory_limit": Int M, + "hint": String/None} """ raise NotImplementedError() @@ -129,7 +130,7 @@ class Robot(object): def _clean_html(self, text): # 先去除部分html标记 - p1 = self._decode_html(re.compile(r"|

||||||").sub("", text)) + p1 = self._decode_html(re.compile(r"|

||||").sub("", text)) #
之类的转换为\n p2 = re.compile(r"").sub(r"\n", p1) return p2