Advertisement
SorahISA

Codeforces scoreboard scrapper (old)

Jan 30th, 2025
52
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.98 KB | Source Code | 0 0
  1. from urllib.parse import urlencode
  2. from hashlib import sha512
  3. import getpass, json, os, re, requests, time
  4.  
  5. def login(s, handle, password):
  6.     res = s.get('https://codeforces.com/enter')
  7.     csrf_token = re.findall('<meta name="X-Csrf-Token" content="(.{32})"/>', res.text)[0]
  8.     data = {
  9.         'csrf_token': csrf_token,
  10.         'action': 'enter',
  11.         'ftaa': '',
  12.         'bfaa': '',
  13.         'handleOrEmail': handle,
  14.         'password': password
  15.     }
  16.     res = s.post('https://codeforces.com/enter', data = data)
  17.     assert 'Logout' in res.text
  18.  
  19. def logout(s):
  20.     res = s.get('https://codeforces.com')
  21.     link = re.findall('<a href="(/.{32}/logout)">Logout</a>', res.text)[0]
  22.     res = s.get('https://codeforces.com' + link)
  23.     assert 'Logout' not in res.text
  24.  
  25. def get_all_contestants(contestId):
  26.     key = input('Codeforces Key: ')
  27.     secret = input('Codeforces Secret: ')
  28.     data = urlencode({
  29.         'apiKey': key,
  30.         'contestId': contestId,
  31.         # 'handle': '*',
  32.         # 'from': 100,
  33.         # 'count': 5,
  34.         'time': int(time.time())
  35.     })
  36.     methods = 'contest.status'
  37.     apiSig = sha512(f'123456/{methods}?{data}#{secret}'.encode()).hexdigest()
  38.    
  39.     res = requests.get(f'https://codeforces.com/api/{methods}?{data}', params = {'apiSig': '123456' + apiSig})
  40.     # print(res.url)
  41.     all_subs = json.loads(res.text)['result']
  42.     all_subs.reverse()
  43.    
  44.     sub_id = {}
  45.     for i, sub in enumerate(all_subs):
  46.         # print(sub)
  47.         if (sub['author']['participantType'] in ['CONTESTANT']):
  48.             name = sub['author']['members'][0]['handle']
  49.             # for mem in sub['author']['members']:
  50.                 # if (len(name) != 0):
  51.                     # name += ", "
  52.                 # name += mem['handle'];
  53.             # status = 1 if (sub['author']['participantType'] in ['VIRTUAL']) else status = 0
  54.             sub_id.setdefault(name, [])
  55.             sub_id[name].append([sub['problem']['index'], sub['id'], sub['relativeTimeSeconds'], i])
  56.    
  57.     return sub_id
  58.  
  59. def get_submission_detail(s, groupID, ID):
  60.     time.sleep(2)
  61.     res = s.get('https://codeforces.com')
  62.     csrf_token = re.findall('<meta name="X-Csrf-Token" content="(.{32})"/>', res.text)[0]
  63.     data = {
  64.         'csrf_token': csrf_token,
  65.         'submissionId': ID,
  66.     }
  67.     res = s.post(f'https://codeforces.com/group/{groupID}/data/judgeProtocol', data = data)
  68.     return res.text
  69.  
  70. def process_subtask(s):
  71.     subtasks = []
  72.     pos = 0
  73.     while pos != -1:
  74.         pos = s.find('Group', pos + 1)
  75.         if pos == -1:
  76.             break
  77.         pos = s.find(':', pos)
  78.         posL = s.find(' ', pos) + 1
  79.         posR = s.find(' ', posL)
  80.         subtasks.append(float(s[posL:posR]))
  81.     return subtasks
  82.  
  83. def f_contests():
  84.    
  85.     try:
  86.         os.mkdir('ranking/contests')
  87.     except OSError as error:
  88.         print("Directory 'ranking/contests' already created")
  89.    
  90.     with open('files/contests.json') as f_contests:
  91.         contests = json.load(f_contests)
  92.    
  93.     for contest in contests:
  94.         with open('ranking/contests/' + contest, 'w') as f:
  95.             json.dump(contests[contest], f, indent = 4)
  96.    
  97.     with open('ranking/contests/index.json', 'w') as f:
  98.         json.dump(contests, f, indent = 4)
  99.    
  100.     return contests
  101.  
  102. def f_tasks():
  103.    
  104.     try:
  105.         os.mkdir('ranking/tasks')
  106.     except OSError as error:
  107.         print("Directory 'ranking/tasks' already created")
  108.    
  109.     with open('files/tasks.json') as f_tasks:
  110.         tasks = json.load(f_tasks)
  111.    
  112.     for task in tasks:
  113.         with open('ranking/tasks/' + task, 'w') as f:
  114.             json.dump(tasks[task], f, indent = 4)
  115.    
  116.     with open('ranking/tasks/index.json', 'w') as f:
  117.         json.dump(tasks, f, indent = 4)
  118.    
  119.     return tasks
  120.  
  121. def f_teams():
  122.    
  123.     try:
  124.         os.mkdir('ranking/teams')
  125.     except OSError as error:
  126.         print("Directory 'ranking/teams' already created")
  127.    
  128.     teams = {}
  129.    
  130.     with open('ranking/teams/index.json', 'w') as f:
  131.         json.dump(teams, f, indent = 4)
  132.    
  133.     return teams
  134.  
  135. def f_users(contestants):
  136.    
  137.     try:
  138.         os.mkdir('ranking/users')
  139.     except OSError as error:
  140.         print("Directory 'ranking/users' already created")
  141.    
  142.     users = {}
  143.    
  144.     for key in contestants:
  145.         users[key] = {'f_name': key, 'l_name': '', 'team': None}
  146.        
  147.         with open('ranking/users/' + key, 'w') as f:
  148.             json.dump(users[key], f, indent = 4)
  149.    
  150.     with open('ranking/users/index.json', 'w') as f:
  151.         json.dump(users, f, indent = 4)
  152.    
  153.     return users
  154.  
  155. def f_history(contestants, tasks):
  156.    
  157.     history = []
  158.     for key in contestants:
  159.         score = {}
  160.         for x in contestants[key]:
  161.             if (len(x) != 5):
  162.                 continue
  163.             if (tasks[x[0]]['score_mode'] == 'max_subtask'):
  164.                 score.setdefault(x[0], [0] * len(x[4]))
  165.                 flag_inc = False
  166.                 for i, val in enumerate(x[4]):
  167.                     if (val > score[x[0]][i]):
  168.                         score[x[0]][i] = val
  169.                         flag_inc = True
  170.                 if (flag_inc):
  171.                     history.append([key, x[0], x[2], sum(score[x[0]])])
  172.             elif (tasks[x[0]]['score_mode'] == 'max'):
  173.                 score.setdefault(x[0], 0)
  174.                 if (sum(x[4]) > score[x[0]]):
  175.                     score[x[0]] = sum(x[4]);
  176.                     history.append([key, x[0], x[2], score[x[0]]])
  177.    
  178.     history.sort(key = lambda sub : sub[2])
  179.    
  180.     with open('ranking/history', 'w') as f:
  181.         json.dump(history, f, indent = 4)
  182.    
  183.     return history
  184.  
  185. def f_scores(history):
  186.    
  187.     scores = {}
  188.     for sub in history:
  189.         scores.setdefault(sub[0], {})
  190.         scores[sub[0]].setdefault(sub[1], sub[3])
  191.         scores[sub[0]][sub[1]] = max(scores[sub[0]][sub[1]], sub[3])
  192.    
  193.     with open('ranking/scores', 'w') as f:
  194.         json.dump(scores, f, indent = 4)
  195.    
  196.     return scores
  197.  
  198. def f_subchanges(contestants, tasks):
  199.    
  200.     try:
  201.         os.mkdir('ranking/subchanges')
  202.     except OSError as error:
  203.         print("Directory 'ranking/subchanges' already created")
  204.    
  205.     subchanges = {}
  206.     for key in contestants:
  207.         for x in contestants[key]:
  208.             subchange = {
  209.                 'submission': str(x[3]),
  210.                 'time': x[2],
  211.             }
  212.             if (len(x) != 5):
  213.                 subchange['score'] = 0
  214.                 subchange['extra'] = ['0'] * len(tasks[x[0]]['extra_headers'])
  215.             else:
  216.                 subchange['score'] = sum(x[4])
  217.                 subchange['extra'] = [str(int(score)) if (score.is_integer()) else str(score) for score in x[4]]
  218.            
  219.             subchanges[str(x[2]) + str(x[3]) + 's'] = subchange
  220.            
  221.             with open('ranking/subchanges/' + str(x[2]) + str(x[3]) + 's', 'w') as f:
  222.                 json.dump(subchange, f, indent = 4)
  223.    
  224.     with open('ranking/subchanges/index.json', 'w') as f:
  225.         json.dump(subchanges, f, indent = 4)
  226.  
  227. def f_sublist(contestants, tasks):
  228.    
  229.     try:
  230.         os.mkdir('ranking/sublist')
  231.     except OSError as error:
  232.         print("Directory 'ranking/sublist' already created")
  233.    
  234.     sublists = {}
  235.     for key in contestants:
  236.         sublist = []
  237.         for x in contestants[key]:
  238.             subsublist = {
  239.                 'user': key,
  240.                 'task': x[0],
  241.                 'time': x[2],
  242.                 'key': str(x[3]),
  243.                 'token': False,
  244.             }
  245.             if (len(x) != 5):
  246.                 subsublist['score'] = 0
  247.                 subsublist['extra'] = ['0'] * len(tasks[x[0]]['extra_headers'])
  248.             else:
  249.                 subsublist['score'] = sum(x[4])
  250.                 subsublist['extra'] = [str(int(score)) if (score.is_integer()) else str(score) for score in x[4]]
  251.             sublist.append(subsublist)
  252.        
  253.         sublists[key] = sublist
  254.        
  255.         with open('ranking/sublist/' + key, 'w') as f:
  256.             json.dump(sublist, f, indent = 4)
  257.    
  258.     return sublists
  259.  
  260. def f_submissions(contestants):
  261.    
  262.     try:
  263.         os.mkdir('ranking/submissions')
  264.     except OSError as error:
  265.         print("Directory 'ranking/submissions' already created")
  266.    
  267.     submissions = {}
  268.     for key in contestants:
  269.         for x in contestants[key]:
  270.             submission = {
  271.                 'user': key,
  272.                 'task': x[0],
  273.                 'time': x[2]
  274.             }
  275.             submissions[str(x[3])] = submission
  276.            
  277.             with open('ranking/submissions/' + str(x[3]), 'w') as f:
  278.                 json.dump(submission, f, indent = 4)
  279.    
  280.     with open('ranking/submissions/index.json', 'w') as f:
  281.         json.dump(submissions, f, indent = 4)
  282.    
  283.     return submissions
  284.  
  285. def main_func():
  286.     handle      = input('Handle: ')
  287.     password    = getpass.getpass('Password: ')
  288.     groupID     = input('Group ID: ')
  289.     contestId   = int(input('Contest ID: '))
  290.     contestants = get_all_contestants(contestId)
  291.    
  292.     s = requests.Session()
  293.     login(s, handle, password)
  294.     for key in contestants:
  295.         for x in contestants[key]:
  296.             detail = get_submission_detail(s, groupID, x[1])
  297.             if ('Points' in detail):
  298.                 x.append(process_subtask(detail))
  299.     logout(s)
  300.    
  301.     # for key in contestants:
  302.         # print(key)
  303.         # for x in contestants[key]:
  304.             # print(x)
  305.    
  306.     try:
  307.         os.mkdir('ranking')
  308.     except OSError as error:
  309.         print("Directory 'ranking' already created")
  310.    
  311.     contests    = f_contests()
  312.     tasks       = f_tasks()
  313.     teams       = f_teams()
  314.     users       = f_users(contestants)
  315.     history     = f_history(contestants, tasks)
  316.     scores      = f_scores(history)
  317.     subchanges  = f_subchanges(contestants, tasks)
  318.     sublists    = f_sublist(contestants, tasks)
  319.     submissions = f_submissions(contestants)
  320.  
  321. if __name__ == '__main__':
  322.     main_func()
  323.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement