#! /usr/bin/env python # -*- coding:utf-8 -*- import codecs import csv import urllib import urllib.request import urllib.parse import os import sys import time import http.cookiejar import shlex import gspread class Write2Spread(object): def __init__(self, username, password, url, sheetnum): try: gc = gspread.login(username, password) self.ws = gc.open_by_url(url).get_worksheet(int(sheetnum)) except gspread.exceptions.AuthenticationError: print("Oops! Incorrect username or password. Please try again.", file=sys.stderr) def append_row(self, values): """ 値のリストをスプレットシートの最後の列として追加する. :param values: 書き込みたい値のリスト.長さはスプレットシートのカラムを超えなければよい. """ self.ws.append_row(values) class Atcoder(object): def __init__(self, contest_name): cookie = http.cookiejar.CookieJar() self.opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie)) self.contest_name = contest_name def login(self, username, password): post = { 'name': username, 'password': password } data = urllib.parse.urlencode(post).encode('UTF-8') self.opener.open(self.__contest_url() + "login", data) def get_standings(self): res = self.opener.open(self.__contest_url() + "standings/csv/") lines = res.read().decode("Shift-JIS").splitlines() reader = csv.reader(lines) # Skip header next(reader) return [team_score for team_score in reader] def __contest_url(self): return "http://" + self.contest_name + ".contest.atcoder.jp/" def get_old_csv(): res = "" with codecs.open(OLD_STANDINGS_FILE_NAME, 'r') as f: reader = csv.reader(f) res = [team for team in reader] return res def update_csv(new_content): with codecs.open(OLD_STANDINGS_FILE_NAME, 'w') as f: f.seek(0) writer = csv.writer(f) for row in new_content: writer.writerow(row) f.truncate() def find_score(teamid, standings): for score in standings: if len(score) > 3 and score[2] == teamid: return score return [] def get_diff(score1, score2): length = len(score1) res = [] for idx, s1, s2 in zip(range(0, length-5), score1[4:], score2[4:]): if s1 != s2: res.append(idx) return res def get_updates(atcoder): standings = atcoder.get_standings() old_standings = get_old_csv() res = [] for team in standings: if len(team) < 3: continue teamname = team[1] teamid = team[2] score = find_score(teamid, standings) old_score = find_score(teamid, old_standings) d = list(map(lambda x: PROBLEM_IDS[int(x / 3)], [x for x in get_diff(score, old_score) if x % 3 == 0 and x / 3 < len(PROBLEM_IDS)])) if len(d) > 0: res.append([teamid, teamname, d]) return (res, standings) PROBLEM_IDS = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"] OLD_STANDINGS_FILE_NAME = "old.csv" def update_spreadsheet(w2s, updates): try: for update in updates: print(update) if len(update) > 0: for problem in update[2]: w2s.append_row([update[0], update[1], problem]) except: raise def say(updates): for update in updates: os.system('say -v Victoria ' + quote(update[0]) def main(): google_user_name = 'a@b.c' google_password = 'your google password' spreadsheet_url = 'URL of the spreadsheet' spreadsheet_sheetnum = 0 w2s = Write2Spread(google_user_name, google_password, spreadsheet_url, spreadsheet_sheetnum) atcoder = Atcoder('') atcoder_user_name = 'atcoder user id' atcoder_password = 'atcoder password' atcoder.login(atcoder_user_name, atcoder_password) interval = 3 while True: try: updates, standings = get_updates(atcoder) update_spreadsheet(w2s, updates) say(updates) update_csv(standings) print(".", end="", flush=True) time.sleep(interval) except KeyboardInterrupt: print("Bye") sys.exit() if __name__ == "__main__": main()