Skip to content

Instantly share code, notes, and snippets.

@oogali
Created November 28, 2013 18:00
Show Gist options
  • Save oogali/7695971 to your computer and use it in GitHub Desktop.
Save oogali/7695971 to your computer and use it in GitHub Desktop.
Python CLI interface for MTA-Metro North Train Time

mnr.py: Quick CLI interface with MTA-Metro North Train Time

Usage Examples

** No arguments: returns all trains leaving from GCT in next 60 minutes **

feather:~ oogali$ mnr

*** 12:49 PM ***

Leaving from Grand Central Terminal

Scheduled Trains
----------------
12:50 PM  To Stamford             Track 110   On Time
12:53 PM  To Croton-Harmon        Track 40    On Time
12:55 PM  To N. White Plains      Track 18    On Time
1:05 PM   To New Haven            Track 29    On Time
1:08 PM   To New Haven            Track 27    On Time
1:10 PM   To Stamford             Track 111   On Time
1:20 PM   To Croton-Harmon        Track 41    On Time
1:22 PM   To Southeast            Track 20    On Time
1:23 PM   To Stamford             Track 112   On Time
1:25 PM   To N. White Plains      Track 17    On Time
1:26 PM   To Poughkeepsie         Track 36    On Time
1:34 PM   To Stamford             Track 106   On Time

** With your destination (the last stop of the train) **

feather:~ oogali$ mnr to stamford

*** 12:50 PM ***

Leaving from Grand Central Terminal

Scheduled Trains
----------------
12:50 PM  To Stamford             Track 110   On Time
1:10 PM   To Stamford             Track 111   On Time
1:23 PM   To Stamford             Track 112   On Time
1:34 PM   To Stamford             Track 106   On Time

** With starting station AND destination (last stop) **

feather:~ oogali$ ./mnr.py from stamford to new canaan

*** 12:51 PM ***

Leaving from Stamford

Scheduled Trains
----------------
12:59 PM 	To New Canaan          	Track 5   	On Time
1:59 PM 	To New Canaan          	Track 5   	On Time
#!/usr/bin/env python
"""
mnr.py: Quick CLI interface with MTA-Metro North Train Time
* twitter: @oogali * github: oogali * linkedin: oogali *
"""
import os, sys, datetime, requests
from lxml import html
from collections import namedtuple
class Travel:
Schedule = namedtuple('Schedule', 'dtime destination track status')
def __init__(self, station='Grand Central Terminal', destination=None):
# initialize a http session for cookie mgmt
self.session = requests.Session()
# load our list of stations from mta.info
self._stations = {}
self.load_stations()
# set our starting and ending stations
# default to Grand Central, if start isn't specified
station = station or 'Grand Central Terminal'
self._destination = destination
# try to find our starting station in the list returned by mta.info
if station in self._stations.keys():
self._station = self._stations[station]
else:
for s in self._stations.keys():
if station.lower() in s.lower():
self._station = self._stations[s]
break
def load_stations(self):
# grab list
r = self.session.get('http://as0.mta.info/mnr/mstations/default.cfm')
# parse html
doc = html.fromstring(r.text)
# use xpath to find all station options
for option in doc.xpath('//select[@name="P_AVIS_ID"]/option'):
idx, name = option.attrib.get('value').split(',', 2)
self._stations[name] = { 'idx': idx, 'name': name }
def station(self):
# return a title-capitalized version of the starting station name
return self._station['name'].title()
def schedule(self):
# get time+track information from mta.info for given station
r = self.session.post('http://as0.mta.info/mnr/mstations/station_status_display.cfm', data={
'P_AVIS_ID': '{},{}'.format(self._station['idx'], self._station['name']),
'Get Train Status': 'Get Train Status',
'refered': 'ault.cfm'
})
# parse html returned from mta.info
scheduled = []
doc = html.fromstring(r.text)
# loop through each result row
for row in doc.xpath('//table/tr'):
cols = row.xpath('td')
# filter out first header row
if cols[0].text == 'Scheduled Time':
continue
# if user has specified a destination, filter out trains that don't match
if self._destination is not None and self._destination.lower() not in cols[1].text.lower():
continue
# filter out trains making their last stop
if self._station['name'].lower() == cols[1].text.lower():
continue
# add this train+track to scheduled departure list
scheduled.append(Travel.Schedule(dtime=cols[0].text, destination=cols[1].text, track=cols[2].text, status=cols[3].text))
return scheduled
def main(argv=None):
if argv is None:
argv = sys.argv
args = argv[1:]
t = None
if len(args) <= 0:
t = Travel()
else:
if args[0] == 'from':
args.pop(0)
to = None
station = None
destination = None
if 'to' in args:
to = args.index('to')
args.pop(to)
if to == 0:
station = None
destination = ' '.join(args)
else:
station = ' '.join(args[0:to])
destination = ' '.join(args[to:])
else:
station = ' '.join(args)
t = Travel(station=station, destination=destination)
print '\n*** {} ***\n'.format(datetime.datetime.now().strftime('%l:%M %p'))
print 'Leaving from {}'.format(t.station())
print '\nScheduled Trains'
print '----------------'
for schedule in t.schedule():
if len(schedule.track.replace(' ', '')) == 0:
track = '(no track yet)'
else:
track = 'Track {}'.format(schedule.track)
print '{}\tTo {}\t{}\t{}'.format(schedule.dtime, schedule.destination.ljust(20), track.ljust(10), schedule.status)
print
return 0
if __name__ == '__main__':
sys.exit(main())
@oogali
Copy link
Author

oogali commented Dec 2, 2013

$ pip install lxml requests
$ alias mnr="${HOME}/mnr.py"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment