Implement departure table, some tuning required for arrival table to work
This commit is contained in:
parent
c960e9a77f
commit
eb4fc0fa27
|
@ -3,9 +3,13 @@ class Station:
|
|||
self.name = name
|
||||
self.sttype = sttype
|
||||
self.extid = extid
|
||||
self.xcoord = float(xcoord)/1000000
|
||||
self.ycoord = float(ycoord)/1000000
|
||||
self.xcoord = float(xcoord)/1000000 if xcoord else None
|
||||
self.ycoord = float(ycoord)/1000000 if ycoord else None
|
||||
self.prodclass = prodclass
|
||||
self.services = []
|
||||
|
||||
def addService(self, svc):
|
||||
self.services += [svc]
|
||||
|
||||
def useId(self):
|
||||
return self.extid or self.name
|
||||
|
@ -16,7 +20,7 @@ class Station:
|
|||
def lon(self):
|
||||
return self.xcoord
|
||||
|
||||
def json(self, indent = 0, name = True, extid = True, sttype = False, coords = False, prodclass = False, distance = False):
|
||||
def json(self, indent = 0, name = True, extid = True, sttype = False, coords = False, prodclass = False, distance = False, services = False, servicekwargs = {}):
|
||||
out = " " * indent + "{\n"
|
||||
|
||||
out += (" " * indent + " \"name\": \"%s\",\n" % self.name) if name else ""
|
||||
|
@ -24,12 +28,20 @@ class Station:
|
|||
out += (" " * indent + " \"distance\": %i,\n" % int(self.distance)) if distance else ""
|
||||
out += (" " * indent + " \"type\": \"%s\",\n" % self.sttype) if sttype else ""
|
||||
|
||||
if coords:
|
||||
if coords and self.xcoord:
|
||||
out += " " * indent + " \"coords\": {\n"
|
||||
out += " " * indent + " \"lon\": %f,\n" % self.xcoord
|
||||
out += " " * indent + " \"lat\": %f\n" % self.ycoord
|
||||
out += " " * indent + " },\n"
|
||||
|
||||
if services and self.services:
|
||||
out += " " * indent + " \"services\": [\n"
|
||||
|
||||
for i in range(len(self.services)):
|
||||
out += self.services[i].json(indent + 2, i, **servicekwargs) + (",\n" if not i == len(self.services) - 1 else "\n")
|
||||
|
||||
out += " " * indent + " ],"
|
||||
|
||||
out += (" " * indent + " \"prodclass\": \"%s\",\n" % self.prodclass) if prodclass else ""
|
||||
|
||||
out = "".join(out.rsplit(",", 1))
|
||||
|
@ -38,7 +50,7 @@ class Station:
|
|||
|
||||
return out
|
||||
|
||||
def xml(self, indent = 0, name = True, extid = True, sttype = False, coords = False, prodclass = False, distance = False):
|
||||
def xml(self, indent = 0, name = True, extid = True, sttype = False, coords = False, prodclass = False, distance = False, services = False, servicekwargs = {}):
|
||||
out = " " * indent + "<station>\n"
|
||||
|
||||
out += (" " * indent + " <name>%s</name>\n" % self.name) if name else ""
|
||||
|
@ -46,12 +58,20 @@ class Station:
|
|||
out += (" " * indent + " <distance>%i</distance>\n" % int(self.distance)) if distance else ""
|
||||
out += (" " * indent + " <type>%s</type>\n" % self.sttype) if sttype else ""
|
||||
|
||||
if coords:
|
||||
if coords and self.xcoord:
|
||||
out += " " * indent + " <coords>\n"
|
||||
out += " " * indent + " <lon>%f</lon>\n" % self.xcoord
|
||||
out += " " * indent + " <lat>%f</lat>\n" % self.ycoord
|
||||
out += " " * indent + " </coords>\n"
|
||||
|
||||
if services and self.services:
|
||||
out += " " * indent + " <services>\n"
|
||||
|
||||
for i in range(len(self.services)):
|
||||
out += self.services[i].xml(indent + 2, i, **servicekwargs) + "\n"
|
||||
|
||||
out += " " * indent + " </services>\n"
|
||||
|
||||
out += (" " * indent + " <prodclass>%s</prodclass>\n" % self.prodclass) if prodclass else ""
|
||||
|
||||
out += " " * indent + "</station>"
|
||||
|
|
50
main.py
50
main.py
|
@ -6,6 +6,7 @@ import workers.conn
|
|||
import workers.val
|
||||
import workers.closest
|
||||
import workers.radar
|
||||
import workers.deparr
|
||||
|
||||
from classes.request import *
|
||||
from classes.response import *
|
||||
|
@ -151,6 +152,49 @@ def doRadar(req):
|
|||
|
||||
return Response(HTTP200, JSON if req.json else XML, content)
|
||||
|
||||
def doDepArr(req):
|
||||
try:
|
||||
name = req.args["name"][0]
|
||||
try:
|
||||
name = name.encode("latin-1").decode("utf-8")
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
|
||||
except Exception:
|
||||
content = "<h1>400 Bad Request</h1>\n"
|
||||
content += "A \"name\" value is required for this type of request."
|
||||
return Response(HTTP400, HTML, content)
|
||||
|
||||
count = req.args["count"][0] if "count" in req.args and req.args["count"] else 30
|
||||
date = req.args["date"][0] if "date" in req.args and req.args["date"] else datetime.datetime.strftime(datetime.datetime.now(pytz.timezone("Europe/Vienna")),"%d.%m.%Y")
|
||||
time = req.args["time"][0] if "time" in req.args and req.args["time"] else datetime.datetime.strftime(datetime.datetime.now(pytz.timezone("Europe/Vienna")),"%H:%M")
|
||||
mode = True if req.rtype[:3] == "arr" else False
|
||||
details = True
|
||||
|
||||
try:
|
||||
count = int(count)
|
||||
except:
|
||||
content = "<h1>400 Bad Request</h1>\n"
|
||||
content += "The \"count\" value must be a numeric value."
|
||||
return Response(HTTP400, HTML, content)
|
||||
|
||||
try:
|
||||
outtime = datetime.datetime.strptime("%s %s" % (date, time), "%d.%m.%Y %H:%M")
|
||||
except:
|
||||
content = "<h1>400 Bad Request</h1>\n"
|
||||
content += "The \"date\" value must be in DD.MM.YYYY format, the \"time\" value must be in HH:MM format."
|
||||
return Response(HTTP400, HTML, content)
|
||||
|
||||
try:
|
||||
content = workers.deparr.worker(name, count, outtime, mode, details, req.json)
|
||||
except Exception as e:
|
||||
content = "<h1>500 Internal Server Error</h1>\n"
|
||||
if "debug" in req.args:
|
||||
content += str(e)
|
||||
return Response(HTTP500, HTML, content)
|
||||
|
||||
return Response(HTTP200, JSON if req.json else XML, content)
|
||||
|
||||
def doNot(req):
|
||||
content = "<h1>400 Bad Request</h1>"
|
||||
content += "The request type you submitted is invalid."
|
||||
|
@ -160,14 +204,16 @@ def application(env, re):
|
|||
try:
|
||||
req = Request(env)
|
||||
|
||||
if req.rtype in ["conn", "connection"]:
|
||||
if req.rtype in ["conn", "connection", "connections"]:
|
||||
res = doConn(req)
|
||||
elif req.rtype in ["val", "validate"]:
|
||||
res = doVal(req)
|
||||
elif req.rtype in ["closest", "close", "near", "nearby"]:
|
||||
res = doNearby(req)
|
||||
elif req.rtype in ["radar", "live"]:
|
||||
elif req.rtype in ["radar", "live", "trains"]:
|
||||
res = doRadar(req)
|
||||
elif req.rtype in ["dep", "arr", "departure", "arrival", "departures", "arrivals"]:
|
||||
res = doDepArr(req)
|
||||
else:
|
||||
res = doNot(req)
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ def getService(sid, lines, q, eq = None):
|
|||
except Exception as e:
|
||||
if eq:
|
||||
eq.put(sys.exc_info())
|
||||
raise
|
||||
|
||||
def getDetails(cid, url, q, via = [], eq = None):
|
||||
try:
|
||||
|
@ -127,6 +128,7 @@ def getDetails(cid, url, q, via = [], eq = None):
|
|||
except:
|
||||
if eq:
|
||||
eq.put(sys.exc_info())
|
||||
raise
|
||||
|
||||
def connRequest(frm, to, count = 3, time = datetime.datetime.now(), mode = False, details = False, via = []):
|
||||
outdate = datetime.datetime.strftime(time, "%d.%m.%Y")
|
||||
|
|
103
workers/deparr.py
Normal file
103
workers/deparr.py
Normal file
|
@ -0,0 +1,103 @@
|
|||
from bs4 import BeautifulSoup
|
||||
import datetime
|
||||
import pytz
|
||||
import threading
|
||||
import queue
|
||||
import sys
|
||||
|
||||
import workers.val
|
||||
from classes import *
|
||||
|
||||
def getStation(name):
|
||||
return list(workers.val.validateName(name))[0]
|
||||
|
||||
def getService(sid, url, dtime, q = None, eq = None):
|
||||
try:
|
||||
zuppa = BeautifulSoup(HTTPClient().get(url).text, "html5lib")
|
||||
|
||||
name = zuppa.findAll("div", { "class": "block" })[0].text.strip().replace("(Zug-Nr. ", " - ").replace(")", "")
|
||||
ddate = zuppa.findAll("div", { "class": "block" })[1].text.strip()
|
||||
|
||||
table = zuppa.find("table", { "class": "resultTable" })
|
||||
rows = table.findAll("tr")[1:]
|
||||
|
||||
for row in rows:
|
||||
if len(row.findAll("td")) > 6 and row.findAll("td")[4].text.strip() == dtime:
|
||||
depst = getStation(row.findAll("td")[1].text.strip())
|
||||
currdep = row.findAll("td")[5].text.strip()
|
||||
currdep = dtime if currdep == "pünktlich" else currdep or None
|
||||
deppf = row.findAll("td")[-1].text.strip() or None
|
||||
|
||||
dest = getStation(rows[-1].findAll("td")[1].text.strip())
|
||||
atime = rows[-1].findAll("td")[2].text.strip()
|
||||
curarr = rows[-1].findAll("td")[3].text.strip()
|
||||
curarr = atime if curarr == "pünktlich" else curarr or None
|
||||
arrpf = rows[-1].findAll("td")[-1].text.strip()
|
||||
|
||||
deptime = datetime.datetime.strptime("%s %s" % (ddate, dtime), "%d.%m.%Y %H:%M")
|
||||
arrtime = datetime.datetime.strptime("%s %s" % (ddate, atime), "%d.%m.%Y %H:%M")
|
||||
|
||||
if arrtime < deptime:
|
||||
arrtime += datetime.timedelta(days = 1)
|
||||
|
||||
if q:
|
||||
q.put((sid, Service(name, depst, deptime, dest, arrtime, dest, deppf, currdep, arrpf, curarr)))
|
||||
return q
|
||||
|
||||
except:
|
||||
if eq:
|
||||
eq.put(sys.exc_info())
|
||||
raise
|
||||
|
||||
def daRequest(station, 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")
|
||||
|
||||
url = "http://fahrplan.oebb.at/bin/stboard.exe/dn?input=%s&boardType=%s&time=%s&productsFilter=1111111111111111&dateBegin=%s&dateEnd=&selectDate=&maxJourneys=%i&start=yes&dirInput=&sqView=2" % (station.extid if station.extid else station.name, "arr" if mode else "dep", outtime, outdate, count)
|
||||
|
||||
source = HTTPClient().get(url).text
|
||||
|
||||
if "traininfo.exe/dn/" not in source:
|
||||
raise ValueError("No services found.")
|
||||
|
||||
juha = BeautifulSoup(source, "html5lib")
|
||||
|
||||
services = []
|
||||
|
||||
table = juha.find("table", {"class": "resultTable"})
|
||||
|
||||
for row in table.findAll("tr")[1:-1]:
|
||||
if not len(row.findAll("td")) < 4:
|
||||
services += [(row.findAll("a")[0].get("href"), row.findAll("td")[0].text.strip())]
|
||||
|
||||
threads = []
|
||||
eq = queue.Queue()
|
||||
q = queue.PriorityQueue()
|
||||
|
||||
for i in range(len(services)):
|
||||
t = threading.Thread(target=getService, args=(i, services[i][0], services[i][1], q, eq))
|
||||
t.start()
|
||||
threads += [t]
|
||||
|
||||
for t in threads:
|
||||
t.join()
|
||||
|
||||
if not eq.empty():
|
||||
exc = eq.get()
|
||||
raise exc[1].with_traceback(exc[2])
|
||||
|
||||
while not q.empty():
|
||||
station.addService(q.get()[1])
|
||||
|
||||
return station
|
||||
|
||||
def worker(station, count = 30, time = datetime.datetime.now(pytz.timezone("Europe/Vienna")), mode = False, details = False, json = False):
|
||||
station = daRequest(getStation(station), count, time, mode, details)
|
||||
|
||||
if json:
|
||||
output = station.json(services = True)
|
||||
else:
|
||||
output = """<?xml version="1.0" encoding="UTF-8"?>\n"""
|
||||
output += station.xml(services = True)
|
||||
|
||||
return output
|
Loading…
Reference in a new issue