From caca14c66a997591e74bf54bca4dcda0d7585c9f Mon Sep 17 00:00:00 2001 From: Klaus-Uwe Mitterer Date: Fri, 22 Sep 2017 17:25:26 +0200 Subject: [PATCH] Implement connection finder. All features of oebbApi now implemented. --- classes/__init__.py | 18 ++-- main.py | 14 +-- workers/conn.py | 215 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 228 insertions(+), 19 deletions(-) diff --git a/classes/__init__.py b/classes/__init__.py index 4c62a20..fd10124 100644 --- a/classes/__init__.py +++ b/classes/__init__.py @@ -17,9 +17,9 @@ class Station: return self.xcoord class Service: - def __init__(self, name, svtype, depst, deptime, arrst, arrtime, deppf = None, currdep = None, arrpf = None, curarr = None, img = None, url = None): + def __init__(self, name, depst, deptime, arrst, arrtime, dest = None, deppf = None, currdep = None, arrpf = None, curarr = None): self.name = name - self.svtype = svtype + self.dest = dest self.depst = depst self.deptime = deptime self.arrst = arrst @@ -28,14 +28,14 @@ class Service: self.currdep = currdep self.arrpf = arrpf self.curarr = curarr - self.img = img - self.url = url + + def duration(): + return self.arrtime - self.deptime class Connection: - def __init__(self, buyurl = None, statusurl = None): + def __init__(self, buyurl = None): self.services = [] self.buyurl = buyurl - self.statusurl = statusurl def addService(self, service): self.services.append(service) @@ -75,3 +75,9 @@ class Connection: return self.services[-1].currarr except: return None + + def duration(self): + try: + return self.services[-1].arrtime - self.services[0].deptime + except: + return None diff --git a/main.py b/main.py index 6399ef8..919d311 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,6 @@ import cgi import datetime +import pytz import workers.conn import workers.val @@ -36,10 +37,11 @@ def application(env, re): yield "\"from\" and \"to\" values are required for this type of request.".encode() return - count = args["count"][0] if "count" in args and args["count"] else 3 - date = args["date"][0] if "date" in args and args["date"] else datetime.datetime.strftime(datetime.datetime.now(),"%d.%m.%Y") - time = args["time"][0] if "time" in args and args["time"] else datetime.datetime.strftime(datetime.datetime.now(),"%H:%M") + count = args["count"][0] if "count" in args and args["count"] else 1 + date = args["date"][0] if "date" in args and args["date"] else datetime.datetime.strftime(datetime.datetime.now(pytz.timezone("Europe/Vienna")),"%d.%m.%Y") + time = args["time"][0] if "time" in args and args["time"] else datetime.datetime.strftime(datetime.datetime.now(pytz.timezone("Europe/Vienna")),"%H:%M") mode = True if "mode" in args and args["mode"] and args["mode"][0].lower() == "arr" else False + details = True if "details" in args else False try: count = int(count) @@ -60,16 +62,18 @@ def application(env, re): return try: - output = workers.conn.worker(frm, to, count, outtime, mode) + output = workers.conn.worker(frm, to, count, outtime, mode, details) except Exception as e: re("500 Internal Server Error", []) yield "

500 Internal Server Error

".encode() if "debug" in args: yield str(e).encode() + raise return re("200 OK", []) - return output.encode() + yield output.encode() + return elif rtype.lower() in ["val", "validate"]: try: diff --git a/workers/conn.py b/workers/conn.py index 112587b..a425653 100644 --- a/workers/conn.py +++ b/workers/conn.py @@ -1,9 +1,15 @@ from bs4 import BeautifulSoup import requests import datetime -import workers.val +import pytz -def connRequest(frm, to, count = 3, time = datetime.datetime.now(), mode = False): +import workers.val +from classes import * + +def getStation(name): + return list(workers.val.validateName(name))[0] + +def connRequest(frm, to, count = 3, time = datetime.datetime.now(), mode = False, details = False): outdate = datetime.datetime.strftime(time,"%d.%m.%Y") outtime = datetime.datetime.strftime(time,"%H:%M") @@ -13,11 +19,204 @@ def connRequest(frm, to, count = 3, time = datetime.datetime.now(), mode = False if "GO_conViewMode=outward" not in source: raise ValueError("No connection found.") - return source + juha = BeautifulSoup(source, "html5lib") + + if details: + for a in juha.findAll("a"): + if a.get("href") and "HWAI=CONNECTION$" in a.get("href"): + dpage = a.get("href") -def getStation(name): - return list(workers.val.validateName(name))[0] + ssource = requests.get(dpage).text + suppe = BeautifulSoup(ssource, "html5lib") + + for i in range(0, count): + cont = suppe.find("tr", id="trC0-%i" % i) + if not cont: + break -def worker(frm, to, count = 3, time = datetime.datetime.now(), mode = False): - source = connRequest(frm, to, count, time, mode) - conns = dissem(source) + buyurl = None + + for url in cont.findAll("a"): + if url.get("href") and "https://tickets.oebb.at/de/ticket/ticket?" in url.get("href"): + buyurl = url.get("href") + + conn = Connection(buyurl) + + lines = cont.findAll("tr", { "class": "tpDetails" })[1:] + cdate = None + + for line in range(0, len(lines), 3): + serv = lines[line:line + 3] + dep = serv[0] + arr = serv[1] + det = serv[2] + + depst = list(workers.val.validateName(dep.find("td", { "class": "station" }).findAll("a")[0].string))[0] + depdate = dep.find("td", { "class": "date" }).string.strip() or cdate + deptime = dep.find("td", { "class": "timeValue" }).find("span").string.split()[1].strip() + depprog = (dep.find("span", { "class": "prognosis" }).find("span") or dep.find("span", { "class": "prognosis" })).string.strip() or None + depplat = (dep.find("td", { "class": "platform" }).find("span") or dep.find("td", { "class": "platform" })).string.strip() or None + + walk = dep.find("img", { "class": "product" }).get("src") == "/img/vs_oebb/fuss_pic.gif" + name = dep.find("img", { "class": "product" }).get("alt") if not walk else "Walk" + + if not walk: + purl = dep.find("td", { "class": "product" }).find("a").get("href") + psource = requests.get(purl).text + + zuppa = BeautifulSoup(psource, "html5lib") + dest = list(workers.val.validateName(zuppa.findAll("div", { "class": "block" })[2].text.split(":")[1].strip()))[0] + + arrst = list(workers.val.validateName(arr.find("td", { "class": "station" }).findAll("a")[0].string))[0] + arrdate = (arr.find("td", { "class": "date" }).find("span") or arr.find("td", { "class": "date" })).string.strip() or depdate + arrtime = arr.find("td", { "class": "timeValue" }).find("span").string.split()[1].strip() + arrprog = (arr.find("span", { "class": "prognosis" }).find("span") or arr.find("span", { "class": "prognosis" })).string.strip() or None + arrplat = (arr.find("td", { "class": "platform" }).find("span") or arr.find("td", { "class": "platform" })).string.strip() or None + + depts = datetime.datetime.strptime("%s %s" % (depdate, deptime), "%d.%m.%Y %H:%M") + arrts = datetime.datetime.strptime("%s %s" % (arrdate, arrtime), "%d.%m.%Y %H:%M") + + depprog = deptime if depprog == "pünktlich" else depprog + arrprog = arrtime if arrprog == "pünktlich" else arrprog + + cdate = arrdate + + svc = Service(name, depst, depts, arrst, arrts, dest, depplat, depprog, arrplat, arrprog) + conn.addService(svc) + + yield conn + + else: + for i in range(0, count): + det = juha.find("tr", id="trOverviewC0-%i" % i) + if not det: + break + + stations = det.find("td", { "class": "station" }).findAll("div") + depst = getStation(stations[0].text.strip()) + arrst = getStation(stations[-1].text.strip()) + + dates = det.find("td", { "class": "date" }).text.split() + depdate = dates[0] + try: + arrdate = dates[1] + except: + arrdate = depdate + + times = det.find("div", { "class": "planed" }).text + deptime = times.split()[0] + arrtime = times.split()[2] + + projections = det.find("div", { "class": "prognosis" }) + curdep = None + curarr = None + + depts = datetime.datetime.strptime("%s %s" % (depdate, deptime), "%d.%m.%Y %H:%M") + arrts = datetime.datetime.strptime("%s %s" % (arrdate, arrtime), "%d.%m.%Y %H:%M") + + name = "/".join([img.get("title") for img in det.findAll("img", { "class": "product" })]) + + ticketurl = det.find("td", { "class": "fares" }).find("a").get("href") + + svc = Service(name, depst, depts, arrst, arrts, currdep = curdep, curarr = curarr) + con = Connection(ticketurl) + + con.addService(svc) + + yield con + +def worker(frm, to, count = 3, time = datetime.datetime.now(pytz.timezone("Europe/Vienna")), mode = False, details = False): + conns = connRequest(getStation(frm), getStation(to), count, time, mode, details) + i = 0 + + output = """ + +""" + + for conn in conns: + hrs, scs = divmod(conn.duration().total_seconds(), 3600) + mns, rmd = divmod(scs, 60) + + chg = max(len([service for service in conn.services if service.name != "Walk"]) - 1, 0) if details else max(len([service for service in conn.services[0].name.split("/") if service != "Walk"]) - 1, 0) + + ddt = datetime.datetime.strftime(conn.deptime(), "%d.%m.%Y") + dtm = datetime.datetime.strftime(conn.deptime(), "%H:%M") + + adt = datetime.datetime.strftime(conn.arrtime(), "%d.%m.%Y") + atm = datetime.datetime.strftime(conn.arrtime(), "%H:%M") + + output += """ + + %s + %s + + + %s + %s + +
+ + %s + + + + %s + + + %s + %i +
+ +""" % (i, conn.depst().name, conn.depst().useId(), conn.arrst().name, conn.arrst().useId(), ddt, dtm, adt, atm, "%i:%i" % (hrs, mns), chg) + + j = 0 + + for service in conn.services: + output += """ + %s + + + %s + %s + + %s + +""" % (j, service.name, service.depst.name, service.depst.useId(), datetime.datetime.strftime(service.deptime,"%d.%m.%Y"), datetime.datetime.strftime(service.deptime, "%H:%M")) + + if service.currdep: + output += " %s\n" % service.currdep + + if service.deppf: + output += " %s\n" % service.deppf + + output += """ + + + %s + %s + + %s + +""" % (service.arrst.name, service.arrst.useId(), datetime.datetime.strftime(service.arrtime, "%d.%m.%Y"), datetime.datetime.strftime(service.arrtime, "%H:%M")) + + if service.curarr: + output += " %s\n" % service.curarr + + if service.arrpf: + output += " %s\n" % service.arrpf + + output += """ + +""" + + j += 1 + + output += """ +
+""" + + i += 1 + + output += """
""" + + return output