-
Notifications
You must be signed in to change notification settings - Fork 1
/
aoj.py
executable file
·155 lines (131 loc) · 5.62 KB
/
aoj.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Algospot Online Judge Command-line interface
# Author: Junseong Lee <[email protected]>
# Created: 2013-03-01
# -- Imports
import os
import re
import argparse
import urllib
import urllib2
import getpass
import unicodedata
from cookielib import MozillaCookieJar
# -- Globals
SITE_PREFIX = 'http://algospot.com/'
LOGIN_URL = SITE_PREFIX + 'accounts/login/'
PROB_PREFIX = SITE_PREFIX + 'judge/problem/'
REGEXP_CSRF = re.compile(r"name='csrfmiddlewaretoken' value='([a-zA-Z0-9]+)'")
LANGUAGES = ('java', 'scala', 'hs', 'py', 'js', 'rb', 'cpp')
# -- Exceptions
class AOJProblemNotExist(Exception):
pass
class AOJFileNotExist(Exception):
pass
class AOJForbidden(Exception):
pass
# -- Classes
class AOJClient(object):
def __init__(self, cookie_file_path='aoj-cookie.txt'):
self.cookie_file_path = cookie_file_path
self.cookiejar = MozillaCookieJar()
if os.path.isfile(cookie_file_path):
self.cookiejar.load(cookie_file_path)
self.opener = urllib2.build_opener(
urllib2.HTTPRedirectHandler(),
urllib2.HTTPHandler(),
urllib2.HTTPSHandler(),
urllib2.HTTPCookieProcessor(self.cookiejar))
def get_csrf_token(self, url):
request = urllib2.Request(url=url)
response = self.opener.open(request)
data = response.read()
return REGEXP_CSRF.findall(data)[0]
def refresh_session(self):
print 'Not Logged In!'
context = {'csrfmiddlewaretoken': self.get_csrf_token(LOGIN_URL),
'username': raw_input('Username: '), 'password': getpass.getpass('Password: ')}
request = urllib2.Request(url=SITE_PREFIX+'accounts/login/',
data=urllib.urlencode(context))
self.opener.open(request)
self.cookiejar.save(self.cookie_file_path)
def check_problem_exist(self, problem_name):
try:
request = urllib2.Request(url=PROB_PREFIX+'read/'+problem_name)
response = self.opener.open(request)
except urllib2.HTTPError as err:
if err.code == 404: # Not Found
raise AOJProblemNotExist
else:
raise
def detect_language(self, source_file):
if '.' in source_file:
selected_language = source_file[source_file.rfind('.')+1:]
else:
selected_language = ''
while selected_language not in LANGUAGES:
selected_language = raw_input('Please select your langauge: (' + '/'.join(LANGUAGES) + ') ? ').strip().lower()
return selected_language
def submit(self, submission):
self.check_problem_exist(submission.problem)
context = {}
context['language'] = self.detect_language(submission.source)
context['csrfmiddlewaretoken'] = self.get_csrf_token(url=PROB_PREFIX+'submit/'+submission.problem)
try:
with open(submission.source) as f:
context['source'] = f.read()
except IOError:
raise AOJFileNotExist()
def try_submit(first=True):
if not first:
self.refresh_session()
request = urllib2.Request(url=PROB_PREFIX+'submit/'+submission.problem,
data=urllib.urlencode(context))
response = self.opener.open(request)
if not response.geturl().lower().startswith(LOGIN_URL):
print 'Submission Complete!'
return
try_submit(first=False)
try_submit()
def get_submission_list(self, problem_name):
self.check_problem_exist(problem_name)
request = urllib2.Request(url=SITE_PREFIX+'judge/submission/recent/?problem='+problem_name)
response = self.opener.open(request)
try:
import lxml.html
except ImportError:
print 'lxml library is needed for parsing HTML'
return
html = lxml.html.fromstring(unicode(response.read().decode('utf8')))
context = {}
fields = ('id', 'problem', 'user', 'language', 'length', 'state', 'stats', 'submitted_on')
length = {'id': 9, 'problem': 15, 'user': 15, 'language': 5, 'length': 7, 'state': 15, 'stats': 7, 'submitted_on': 15}
template = u'%(id)s %(problem)s %(user)s %(language)s %(length)s %(state)s %(stats)s %(submitted_on)s'
def width(string):
return sum(1+(unicodedata.east_asian_width(c) in 'WF') for c in string)
for tr in html.cssselect('table.submission_list tr'):
for field in fields:
element = tr.find_class(field)
if element:
context[field] = unicode(element[0].text_content().strip())
else:
context[field] = u''
context[field] = ' ' * (length[field] - width(context[field])) + context[field]
print template % context
class AOJSubmission(object):
def __init__(self, problem, source):
self.problem = problem.upper()
self.source = source
# -- main
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='AOJ-Cli: Command line interface for Algospot Online Judge (http://www.algospot.com)')
parser.add_argument('problem', metavar='PROBNAME', type=str, nargs=1, help='name of the problem')
parser.add_argument('source', type=str, nargs='?', help='filename to submit')
args = parser.parse_args()
client = AOJClient()
if args.source:
submission = AOJSubmission(args.problem[0], args.source)
client.submit(submission)
else:
client.get_submission_list(args.problem[0].upper())