oebb_py/workers/conn.py
2017-11-04 21:06:04 +01:00

232 lines
7.2 KiB
Python

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, lines, q, eq = None):
try:
dep = lines[0]
arr = lines[1]
det = lines[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 None
deptime = dep.find("td", { "class": "timeValue" }).find("span").string.split()[1].strip()
depprog = dep.find("span", { "class": "prognosis" }).find("span").string.strip() if dep.find("span", { "class": "prognosis" }).find("span") else None
depplat = dep.find("td", { "class": "platform" }).find("span").string.strip() if dep.find("td", { "class": "platform" }).find("span") else 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"
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
if arrdate and not depdate:
arrdts = datetime.datetime.strptime(arrdate, "%d.%m.%Y")
depdts = arrdts - datetime.timedelta(days=1)
depdate = datetime.datetime.strftime(depdts, "%d.%m.%Y")
dest = None
if not (walk or depdate):
purl = dep.find("td", { "class": "product" }).find("a").get("href")
psource = HTTPClient().get(purl).text
zuppa = BeautifulSoup(psource, "html5lib")
depdate = zuppa.findAll("div", { "class": "block" })[1].text.strip()
arrdate = depdate
dest = list(workers.val.validateName(zuppa.findAll("div", { "class": "block" })[2].text.split(":")[1].strip()))[0]
elif not depdate:
depdate = "01.01.2000"
arrdate = depdate
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
svc = Service(name, depst, depts, arrst, arrts, dest, depplat, depprog, arrplat, arrprog)
q.put((sid, svc))
except Exception as e:
if eq:
eq.put(sys.exc_info())
raise
def getDetails(cid, url, q, via = [], eq = None):
try:
ssource = HTTPClient().get(url).text
suppe = BeautifulSoup(ssource, "html5lib")
cont = suppe.find("tr", id="trC0-%i" % cid)
if not cont:
return
# 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(True)
for vst in via:
conn.addVia(vst)
lines = cont.findAll("tr", { "class": "tpDetails" })[1:]
threads = []
iq = queue.PriorityQueue()
for line in range(0, len(lines), 3):
t = threading.Thread(target=getService, args=(line, lines[line:line + 3], iq, eq))
t.start()
threads += [t]
for t in threads:
t.join()
wdate = None
while not iq.empty():
svc = iq.get()[1]
if not wdate or svc.arrtime > wdate:
wdate = svc.arrtime
elif svc.deptime < wdate:
ttime0 = datetime.datetime(wdate.year, wdate.month, wdate.day)
ttime1 = ttime0 + datetime.timedelta(hours=svc.deptime.hour, minutes=svc.deptime.minute)
ttime2 = ttime0 + datetime.timedelta(hours=svc.arrtime.hour, minutes=svc.arrtime.minute)
if ttime1 < wdate:
ttime1 += datetime.timedelta(days=1)
ttime2 += datetime.timedelta(days=1)
if ttime1 > ttime2:
ttime2 += datetime.timedelta(days=1)
svc.deptime = ttime1
svc.arrtime = ttime2
conn.addService(svc)
q.put((cid, conn))
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")
outtime = datetime.datetime.strftime(time, "%H:%M")
url = "http://fahrplan.oebb.at/bin/query.exe/dn?start=1&S=%s&Z=%s&REQ0JourneyDate=%s&time=%s&REQ0HafasNumCons0=%s%s" % (frm.extid if frm.extid else frm.name, to.extid if to.extid else to.name, outdate, outtime, count, "&timesel=arrive" if mode else "")
for i in range(len(via)):
url += "&REQ0JourneyStops%i.0G=%s&REQ0JourneyStops%i.0A=1" % (i + 1, via[i].extid if via[i].extid else via[i].name, i + 1)
source = HTTPClient().get(url).text
if "GO_conViewMode=outward" not in source:
raise ValueError("No connection found.")
juha = BeautifulSoup(source, "html5lib")
if details:
conns = []
for a in juha.findAll("a"):
if a.get("href") and "GO_conViewMode" in a.get("href"):
conns += [a.get("href")]
threads = []
eq = queue.Queue()
q = queue.PriorityQueue()
for i in range(len(conns)):
t = threading.Thread(target=getDetails, args=(i, conns[i], q, via, 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():
yield q.get()[1]
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 = list(det.find("td", { "class": "date" }).strings)
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)
conn = Connection(details)
for vst in via:
conn.addVia(vst)
conn.addService(svc)
yield conn
def worker(frm, to, count = 3, time = datetime.datetime.now(pytz.timezone("Europe/Vienna")), mode = False, details = False, json = False, via = None):
conns = list(connRequest(getStation(frm), getStation(to), count, time, mode, details, [getStation(vst) for vst in via] if via else []))
output = """<?xml version="1.0" encoding="UTF-8"?>
<connections>
""" if not json else """{
\"connections\": [
"""
for i in range(len(conns)):
output += (conns[i].xml(1, i) + "\n") if not json else (conns[i].json(2, i) + ("\n" if i == len(conns) - 1 else ",\n"))
output += "</connections>" if not json else " ]\n}"
return output