diff --git a/main.py b/main.py index 89f0e11..b8d9c61 100644 --- a/main.py +++ b/main.py @@ -36,7 +36,7 @@ class Handler: self.app.reply(self.st, "accepted") mod = self.app.mods["elicense"] - mod.watch(self.st["id"], date, slots) + mod.watch(date, slots, lambda: self.app.reply(self.st, "reservation made")) class App: diff --git a/mods/elicense.py b/mods/elicense.py index a7bfabd..0dbde2e 100644 --- a/mods/elicense.py +++ b/mods/elicense.py @@ -1,9 +1,10 @@ +import datetime +import dateutil import logging import json +import re import requests -from html.parser import HTMLParser - def init(CONFIG, logger): logger.setLevel(logging.DEBUG) @@ -15,12 +16,16 @@ class Mod: self.URL = "https://www.e-license.jp/el25/pc/" self.CONFIG = CONFIG - self.logging = logging - self.targets = [] + self.logging = logging + self.targets = [] + self.calender = None self.ss = self.authenticate() def cycle(self): + if len(self.targets) == 0: + return + res = self.ss.post( url = self.URL+"p04a.action", data = { @@ -30,15 +35,46 @@ class Mod: "b.schoolCd" : self.CONFIG["school"], }) res.encoding = "shift_jis" + self.calender = Calender(res.text) - parser = ReservationListParser() - parser.feed(res.text) + now = datetime.datetime.utcnow() + datetime.timedelta(hours=9) + today = now.strftime("%Y%m%d") - return + for target in self.targets: + for slot in target[1]: + begins = now.combine(now.date(), TIMETABLE[slot]) + border = begins - datetime.timedelta(hours=2) - def watch(self, date, slots): - self.logging.debug("watch request accepted: {} {}".format(+date+slots)) - self.targets.append((date, slots)) + if target[0] != today or now < border: + if self.calender.checkAvailable(target[0], slot): + self.make_reserve(target[0], slot) + target[2]() + break + self.targets = [] + + def watch(self, date, slots, cb): + self.logging.debug("watch request accepted, {} {}".format(date, slots)) + self.targets.append((date, slots, cb)) + + def make_reserve(self, date, slot): + res = self.ss.post( + url = self.URL+"p03a.action", + data = { + "b.schoolCd" : self.CONFIG["school"], + "b.processCd" : "V", + "b.kamokuCd" : 0, + "b.instructorTypeCd" : 0, + "b.dateInformationType": date, + "b.infoPeriodNumber" : slot, + "b.carModelCd" : self.calender.carModel, + "b.instructorCd" : 0, + "b.page" : 1, + "b.groupCd" : self.calender.group, + }) + res.encoding = "shift_jis" + self.calender = Calender(res.text) + + self.logging.info("reservation made, {}:{}".format(date, slots)) def authenticate(self): ss = requests.Session() @@ -53,6 +89,8 @@ class Mod: "b.kamokuCd" : "", "method:doLogin" : "ログイン".encode("shift_jis"), }) + res.encoding = "shift_jis" + self.calender = Calender(res.text) self.logging.info("authenticated") return ss except Exception as e: @@ -60,22 +98,36 @@ class Mod: return None -class ReservationListParser(HTMLParser): - path = [] +class Calender: + def __init__(self, text): + m = re.search(RE_ERROR, text) + if m is None: + m = re.search(RE_ALERT, text) + if m is not None: + raise Exception(m[1]) - def handle_starttag(self, tag, attrs): - self.path.append(tag) + self.avails = re.findall(RE_AVAIL_SLOT, text) - c = [x[1] for x in attrs if x[0] == "class"] - if len(c) == 0: - return + def checkAvailable(self, date, slot): + for avail in self.avails: + if avail[0] == date and avail[1] == str(slot): + return True + return False - if tag == "td": - print(c) - return - def handle_data(self, data): - return +TIMETABLE = { + 1: datetime.time( 9,20), + 2: datetime.time(10,20), + 3: datetime.time(11,20), + 4: datetime.time(12,20), + 5: datetime.time(14,10), + 6: datetime.time(15,10), + 7: datetime.time(16,10), + 8: datetime.time(17,10), + 9: datetime.time(18,10), + 10: datetime.time(19,10), +} - def handle_endtag(self, tag): - self.path.pop() +RE_ALERT = re.compile(r"window\.alert\('(.*)'\)") +RE_ERROR = re.compile(r"<.*? class=\"errorTitle\">メッセージ<\/.*?>\s*<.*? class=\"errorDisp\">(.*?)<\/.*?>", re.MULTILINE) +RE_AVAIL_SLOT = re.compile(r"^\s*$")