mvv is the "Münchner Verkehrs- und Trafiverbund" and i hate to use their webapp to query bus- and
subway schedules. it is too slow and bloated, so i wrote a small command line interface with configurable
short names:
it shows all needed information in a nicely formatted manner. here the python source:
python mvv
version = "0.2"
origin = "Götheplatz"
origin_place = "m"
destination_place = "m"
show_hints = True
mode = "dep"
format = "pretty"
maxterminallength = 80
maxterminallength = 100
maxterminallength = 111
maxterminallength = 130
later = 0
import datetime
d = datetime.datetime.now()
import urllib
import cgi
from urllib2 import *
from HTMLParser import HTMLParser
import sys
def usage():
print """pymvv v%s by Florian Schmidt 2006-03-25
usage:
Rotkreuzplatz start from default to Rotkreuzplatz now
Goetheplatz Rotkreuzplatz start from Goetheplatz
Rotkreuzplatz +5 start in 5 minutes from now
Rotkreuzplatz arrive 17:30 arrive at 17:30
Goetheplatz Rotkreuzplatz arrive 17:30 arrive at 17:30
Goetheplatz Rotkreuzplatz start 17:30 start at 17:30
Goetheplatz Rotkreuzplatz start 17:30 csv start at 17:30 output as csv
Goetheplatz Rotkreuzplatz nohints to Rotkreuzplatz, without hints
""" % version
sys.exit(0)
if len(sys.argv) < 2:
usage()
startlen = 0
while len(sys.argv) != startlen:
startlen = len(sys.argv)
if sys.argv[-1] == "csv":
format = "csv"
del sys.argv[-1]
if sys.argv[-1] == "nohints":
show_hints = False
del sys.argv[-1]
if sys.argv[-1][0] == '+' or sys.argv[-1][0] == '-':
later = int(sys.argv[-1])
del sys.argv[-1]
if len(sys.argv) > 2 and sys.argv[-2] == "arrive":
t = map(int, sys.argv[-1].split(":"))
d = d.replace(hour=t[0], minute=t[1])
mode = "arr"
del sys.argv[-1]
del sys.argv[-1]
if len(sys.argv) > 2 and sys.argv[-2] == "start":
t = map(int, sys.argv[-1].split(":"))
d = d.replace(hour=t[0], minute=t[1])
mode = "dep"
del sys.argv[-1]
del sys.argv[-1]
if len(sys.argv) == 3:
origin = sys.argv[1].strip()
destination = sys.argv[2].strip()
del sys.argv[-1]
del sys.argv[-1]
elif len(sys.argv) == 2:
destination = sys.argv[1].strip()
del sys.argv[-1]
else:
usage()
if d < datetime.datetime.now():
d += datetime.timedelta(days=1)
if later != 0:
td = datetime.timedelta(minutes=later)
d = d + td
mappings = {}
try:
fp = file(os.path.expanduser("~/.mvv"), "rb")
for line in fp.readlines():
line.strip()
if not line or line.find("=") == -1:
continue
m = line.split("=", 1)
mappings[m[0].strip()] = m[1].strip()
fp.close()
except:
pass
if origin in mappings:
origin = mappings[origin]
if destination in mappings:
destination = mappings[destination]
if format == "pretty":
if mode == "arr":
print "from %s to %s arriving at %.16s" % (origin, destination, d)
else:
print "from %s to %s starting at %.16s" % (origin, destination, d)
dest = destination.split(":", 1)
if len(dest) > 1:
destination_place, destination = dest
org = origin.split(":", 1)
if len(org) > 1:
origin_place, origin = org
params = {
'execInst': 'normal',
'itdDateDay': d.day,
'itdDateMonth': d.month,
'itdDateYear': d.year,
'itdTimeHour': d.hour,
'itdTimeMinute': d.minute,
'itdTripDateTimeDepArr': mode,
'language': 'de',
'name_destination': destination,
'nameInfo_destination': 'invalid',
'nameInfo_origin': 'invalid',
'name_origin': origin,
'place_destination': destination_place,
'placeInfo_destination': 'invalid',
'placeInfo_origin': 'invalid',
'place_origin': origin_place,
'ptOptionsActive': '0',
'requestID': '0',
'sessionID': '0',
'target_url': '/de/home/fahrgastinformation/efa/fahrtauskunft/index.html',
'type_destination': 'stop',
'typeInfo_destination': 'invalid',
'typeInfo_origin': 'invalid',
'type_origin': 'stop',
'x': '39',
'y': '8',
}
params = urllib.urlencode(params)
url = "http://efa.mvv-muenchen.de/mvv/XSLT_TRIP_REQUEST2?%s" % params
request = Request(url)
if format == "pretty":
print "connect...",
f = urlopen(request)
if format == "pretty":
print "download...",
data = f.read()
if format == "pretty":
print "parse...",
import re
from HTMLParser import HTMLParser
class mvv_parser(HTMLParser):
rows = []
row = []
have_details = False
def handle_starttag(self, tag, attrs):
if self.have_details:
if tag == "tr":
self.row = []
def handle_endtag(self, tag):
if self.have_details and tag == "tr":
self.rows.append(self.row)
def handle_data(self, data):
data = data.strip()
if not data:
return
if not self.have_details:
if data == "Details":
self.have_details = True
else:
return
self.row.append(data)
p = mvv_parser()
p.feed(data)
def filter_transport(input):
input = input.replace("U-Bahn U", "U")
input = input.replace("MetroBus ", "Bus")
input = input.replace("S-Bahn S", "S")
input = input.replace("Tram ", "Tram")
return input
etappe = []
etappen = []
trips = []
for row in p.rows:
if len(row) < 1:
if len(etappen):
if len(etappe):
etappen[-1].extend(etappe)
trips.append(etappen)
etappen = []
etappe = []
continue
if row[0] == "Details":
continue
if len(etappe) == 0:
if row[0] == "\xa0":
continue
etappe = row
else:
if row[0] != "\xa0":
etappe.extend(row)
if len(etappe) == 6:
etappen.append([etappe[0], etappe[3], etappe[1][3:], etappe[4][3:], filter_transport(etappe[2]), etappe[5]])
elif len(etappe) == 7:
etappen.append([etappe[0], etappe[4], etappe[1][3:], etappe[5][3:], filter_transport(etappe[2]), etappe[6]])
elif len(etappe) == 2:
t = etappe[0]
if t[0:3] == "ca.":
t = "dann zu Fuß %s" % t.replace("Minuten", "Min.")
if len(etappen):
etappen[-1].append(t)
elif len(etappe) == 1:
etappen[-1].append(etappe[0])
etappe = []
if format == "pretty":
print "done.\n"
station_length = 20
transport_length = 2
max_output_len = 0
if format == "pretty":
for trip in trips:
for e in trip:
if len(e) >= 6:
station = "%s -> %s" % (e[2], e[3])
if len(station) > station_length:
station_length = len(station)
transport = e[4]
if len(transport) > transport_length:
transport_length = len(transport)
output = "%s->%s %-*.*s %-*.*s Richtung %s" % (
e[0], e[1],
station_length, station_length,
"%s -> %s" % (e[2], e[3]),
transport_length, transport_length,
e[4],
e[5]
)
if show_hints and len(e) > 6:
output += " (%s)" % (", ".join(e[6:]))
if len(output) > max_output_len:
max_output_len = len(output)
if max_output_len < maxterminallength:
line_length = max_output_len
else:
line_length = maxterminallength
for trip in trips:
if format == "pretty":
print "-" * line_length
for e in trip:
if format == "pretty":
if len(e) >= 6:
output = "%s->%s %-*.*s %-*.*s Richtung %s" % (
e[0], e[1],
station_length, station_length,
"%s -> %s" % (e[2], e[3]),
transport_length, transport_length,
e[4],
e[5]
)
if show_hints and len(e) > 6:
output += " (%s)" % (", ".join(e[6:]))
if len(output) <= maxterminallength:
print output
else:
while True:
if len(output) > maxterminallength:
p1 = output.rfind(" ", 0, maxterminallength)
p2 = output.rfind("(", 0, maxterminallength)
p3 = output.rfind(",", 0, maxterminallength)
p3 = output.rfind("-", 0, maxterminallength)
p = max(p1, p2, p3)
print output[0:p+1]
output = "%s%s" % (" " * 14, output[p+1:])
else:
print output
break
else:
print [e]
elif format == "csv":
if len(e) >= 6:
print "%s;%s;%s;%s;%s;%s" % (
e[0], e[1],
e[2], e[3],
e[4], e[5]
)
print