Exploring the TTC Subway Real-time API

The API we're pulling data from is what supports the TTC's Next Train Arrivals page. With a bit of exploration through your browser's developer console, you can see that the page gets refreshed with data from a request to http://www.ttc.ca/Subway/loadNtas.action


In [1]:
import requests #to handle http requests to the API
from psycopg2 import connect

In [2]:
stationid = 3 
#We'll find out the full range of possible stations further down.
lineid = 1 
#[1,2,4]

In [3]:
# The url for the request
base_url = "http://www.ttc.ca/Subway/loadNtas.action"

In [4]:
# Our query parameters for this API request
payload = {#"subwayLine":lineid,
           "stationId":stationid,
           "searchCriteria":''} #The value in the search box
           #it has to be included otherwise the query fails
           #"_":request_epoch} #Great job naming variables...
# subwayLine and _ are redundant variables. 
# We thought we could query historical data using the "_" parameter 
# But it seems no
r = requests.get(base_url, params = payload)

So now we've just received our first request from the API and the response is stored in the requests object r. From previous examination of the API we know that the response to an API request is in JSON format. So the below code will pretty print out the response so we can have a look at the variables.


In [5]:
r.json()


Out[5]:
{'allLineXStations': None,
 'allStations': 'success',
 'data': None,
 'defaultDirection': [['YKD1', 'Southbound<br/> To Union', 'YUS'],
  ['YKD2', 'Northbound<br/> To Vaughan Metropolitan Centre', 'YUS']],
 'limit': 3,
 'ntasData': [{'createDate': '2018-04-10T20:46:16',
   'id': 20947050944,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'YKD1',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 1.039222857142857,
   'timeString': '02.00',
   'trainDestination': 'FIN1',
   'trainDestinationStation': 'Finch',
   'trainDirection': 'North',
   'trainId': 121,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:16',
   'id': 20947050945,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'YKD1',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 4.534429333333333,
   'timeString': '05.00',
   'trainDestination': 'FIN1',
   'trainDestinationStation': 'Finch',
   'trainDirection': 'North',
   'trainId': 136,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:16',
   'id': 20947050946,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'YKD1',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 8.620152952380952,
   'timeString': '09.00',
   'trainDestination': 'FIN1',
   'trainDestinationStation': 'Finch',
   'trainDirection': 'North',
   'trainId': 122,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:16',
   'id': 20947050906,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'YKD2',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 0.0,
   'timeString': '00.00',
   'trainDestination': 'VMC2',
   'trainDestinationStation': 'Vaughan Metropolitan Centre',
   'trainDirection': 'South',
   'trainId': 137,
   'trainMessage': 'AtStation'},
  {'createDate': '2018-04-10T20:46:16',
   'id': 20947050907,
   'stationDirectionText': 'Northbound<br/> To Vaughan Metropolitan Centre',
   'stationId': 'YKD2',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 2.0768331428571427,
   'timeString': '03.00',
   'trainDestination': 'WIL2',
   'trainDestinationStation': 'Wilson',
   'trainDirection': 'South',
   'trainId': 138,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:16',
   'id': 20947050908,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'YKD2',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 3.4726560000000006,
   'timeString': '04.00',
   'trainDestination': 'VMC2',
   'trainDestinationStation': 'Vaughan Metropolitan Centre',
   'trainDirection': 'South',
   'trainId': 140,
   'trainMessage': 'Arriving'}],
 'searchCriteria': '',
 'searchCriteriaMatch': None,
 'stationId': '3',
 'subwayLine': None,
 'subwayLine2': None,
 'subwayStations': ['Bathurst Station',
  'Bay Station',
  'Bayview Station',
  'Bessarion Station',
  'Bloor-Yonge Station',
  'Broadview Station',
  'Castle Frank Station',
  'Chester Station',
  'Christie Station',
  'College Station',
  'Coxwell Station',
  'Davisville Station',
  'Don Mills Station',
  'Donlands Station',
  'Downsview Park Station',
  'Dufferin Station',
  'Dundas Station',
  'Dundas West Station',
  'Dupont Station',
  'Eglinton Station',
  'Eglinton West Station',
  'Finch Station',
  'Finch West Station',
  'Glencairn Station',
  'Greenwood Station',
  'High Park Station',
  'Highway 407 Station',
  'Islington Station',
  'Jane Station',
  'Keele Station',
  'Kennedy Station',
  'King Station',
  'Kipling Station',
  'Lansdowne Station',
  'Lawrence Station',
  'Lawrence West Station',
  'Leslie Station',
  'Main Street Station',
  'Museum Station',
  'North York Centre Station',
  'Old Mill Station',
  'Osgoode Station',
  'Ossington Station',
  'Pape Station',
  'Pioneer Village Station',
  'Queen Station',
  'Queen’s Park Station',
  'Rosedale Station',
  'Royal York Station',
  'Runnymede Station',
  'Sheppard West Station',
  'Sheppard-Yonge Station',
  'Sherbourne Station',
  'Spadina Station',
  'St Andrew Station',
  'St Clair Station',
  'St Clair West Station',
  'St George Station',
  'St Patrick Station',
  'Summerhill Station',
  'Union Station',
  'Vaughan Metropolitan Centre Station',
  'Victoria Park Station',
  'Warden Station',
  'Wellesley Station',
  'Wilson Station',
  'Woodbine Station',
  'York Mills Station',
  'York University Station',
  'Yorkdale Station']}

In [6]:
data = r.json()

In [7]:
data['ntasData'][0]['createDate']


Out[7]:
'2018-04-10T20:46:16'

In [8]:
#Testing whether have to be explicit about line numbers for stations with multiple lines
payload = {#"subwayLine":lineid,
           "stationId":10, #St. George, Line 1
           "searchCriteria":''} 
r = requests.get(base_url, params = payload)
r.json()


Out[8]:
{'allLineXStations': None,
 'allStations': 'success',
 'data': None,
 'defaultDirection': [['SGU1', 'Southbound<br/> To Union', 'YUS'],
  ['SGU2', 'Northbound<br/> To Vaughan Metropolitan Centre', 'YUS'],
  ['SGL1', 'Eastbound</br> To Kennedy', 'BD'],
  ['SGL2', 'Westbound<br/> To Kipling', 'BD']],
 'limit': 3,
 'ntasData': [{'createDate': '2018-04-10T20:46:21',
   'id': 20947052333,
   'stationDirectionText': 'Northbound<br/> To Vaughan Metropolitan Centre',
   'stationId': 'SGU2',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 0.0,
   'timeString': '00.00',
   'trainDestination': 'VMC2',
   'trainDestinationStation': 'Vaughan Metropolitan Centre',
   'trainDirection': 'South',
   'trainId': 145,
   'trainMessage': 'AtStation'},
  {'createDate': '2018-04-10T20:46:21',
   'id': 20947052334,
   'stationDirectionText': 'Northbound<br/> To Vaughan Metropolitan Centre',
   'stationId': 'SGU2',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 0.9303657142857144,
   'timeString': '01.00',
   'trainDestination': 'WIL2',
   'trainDestinationStation': 'Wilson',
   'trainDirection': 'South',
   'trainId': 146,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:21',
   'id': 20947052335,
   'stationDirectionText': 'Northbound<br/> To Vaughan Metropolitan Centre',
   'stationId': 'SGU2',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 2.4766857142857144,
   'timeString': '03.00',
   'trainDestination': 'VMC2',
   'trainDestinationStation': 'Vaughan Metropolitan Centre',
   'trainDirection': 'South',
   'trainId': 148,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:20',
   'id': 20947051898,
   'stationDirectionText': 'Eastbound</br> To Kennedy',
   'stationId': 'SGL1',
   'subwayLine': 'BD',
   'systemMessageType': 'Normal',
   'timeInt': 1.5856777777777777,
   'timeString': '02.00',
   'trainDestination': 'KEN1',
   'trainDestinationStation': 'Kennedy',
   'trainDirection': 'East',
   'trainId': 235,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:20',
   'id': 20947051899,
   'stationDirectionText': 'Eastbound</br> To Kennedy',
   'stationId': 'SGL1',
   'subwayLine': 'BD',
   'systemMessageType': 'Normal',
   'timeInt': 3.229928888888889,
   'timeString': '04.00',
   'trainDestination': 'KEN1',
   'trainDestinationStation': 'Kennedy',
   'trainDirection': 'East',
   'trainId': 238,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:20',
   'id': 20947051900,
   'stationDirectionText': 'Eastbound</br> To Kennedy',
   'stationId': 'SGL1',
   'subwayLine': 'BD',
   'systemMessageType': 'Normal',
   'timeInt': 4.372895955555555,
   'timeString': '05.00',
   'trainDestination': 'KEN1',
   'trainDestinationStation': 'Kennedy',
   'trainDirection': 'East',
   'trainId': 239,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:21',
   'id': 20947052413,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'SGU1',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 0.0,
   'timeString': '00.00',
   'trainDestination': 'FIN1',
   'trainDestinationStation': 'Finch',
   'trainDirection': 'North',
   'trainId': 110,
   'trainMessage': 'AtStation'},
  {'createDate': '2018-04-10T20:46:21',
   'id': 20947052414,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'SGU1',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 10.037435428571428,
   'timeString': '11.00',
   'trainDestination': 'FIN1',
   'trainDestinationStation': 'Finch',
   'trainDirection': 'North',
   'trainId': 11,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:21',
   'id': 20947052415,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'SGU1',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 12.815018285714286,
   'timeString': '13.00',
   'trainDestination': 'FIN1',
   'trainDestinationStation': 'Finch',
   'trainDirection': 'North',
   'trainId': 118,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:20',
   'id': 20947051985,
   'stationDirectionText': 'Westbound<br/> To Kipling',
   'stationId': 'SGL2',
   'subwayLine': 'BD',
   'systemMessageType': 'Normal',
   'timeInt': 1.9141966666666668,
   'timeString': '02.00',
   'trainDestination': 'KIP2',
   'trainDestinationStation': 'Kipling',
   'trainDirection': 'West',
   'trainId': 211,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:20',
   'id': 20947051986,
   'stationDirectionText': 'Westbound<br/> To Kipling',
   'stationId': 'SGL2',
   'subwayLine': 'BD',
   'systemMessageType': 'Normal',
   'timeInt': 4.608596666666667,
   'timeString': '05.00',
   'trainDestination': 'KIP2',
   'trainDestinationStation': 'Kipling',
   'trainDirection': 'West',
   'trainId': 213,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:20',
   'id': 20947051987,
   'stationDirectionText': 'Westbound<br/> To Kipling',
   'stationId': 'SGL2',
   'subwayLine': 'BD',
   'systemMessageType': 'Normal',
   'timeInt': 7.6898903999999995,
   'timeString': '08.00',
   'trainDestination': 'KIP2',
   'trainDestinationStation': 'Kipling',
   'trainDirection': 'West',
   'trainId': 215,
   'trainMessage': 'Arriving'}],
 'searchCriteria': '',
 'searchCriteriaMatch': None,
 'stationId': '10',
 'subwayLine': None,
 'subwayLine2': '2',
 'subwayStations': ['Bathurst Station',
  'Bay Station',
  'Bayview Station',
  'Bessarion Station',
  'Bloor-Yonge Station',
  'Broadview Station',
  'Castle Frank Station',
  'Chester Station',
  'Christie Station',
  'College Station',
  'Coxwell Station',
  'Davisville Station',
  'Don Mills Station',
  'Donlands Station',
  'Downsview Park Station',
  'Dufferin Station',
  'Dundas Station',
  'Dundas West Station',
  'Dupont Station',
  'Eglinton Station',
  'Eglinton West Station',
  'Finch Station',
  'Finch West Station',
  'Glencairn Station',
  'Greenwood Station',
  'High Park Station',
  'Highway 407 Station',
  'Islington Station',
  'Jane Station',
  'Keele Station',
  'Kennedy Station',
  'King Station',
  'Kipling Station',
  'Lansdowne Station',
  'Lawrence Station',
  'Lawrence West Station',
  'Leslie Station',
  'Main Street Station',
  'Museum Station',
  'North York Centre Station',
  'Old Mill Station',
  'Osgoode Station',
  'Ossington Station',
  'Pape Station',
  'Pioneer Village Station',
  'Queen Station',
  'Queen’s Park Station',
  'Rosedale Station',
  'Royal York Station',
  'Runnymede Station',
  'Sheppard West Station',
  'Sheppard-Yonge Station',
  'Sherbourne Station',
  'Spadina Station',
  'St Andrew Station',
  'St Clair Station',
  'St Clair West Station',
  'St George Station',
  'St Patrick Station',
  'Summerhill Station',
  'Union Station',
  'Vaughan Metropolitan Centre Station',
  'Victoria Park Station',
  'Warden Station',
  'Wellesley Station',
  'Wilson Station',
  'Woodbine Station',
  'York Mills Station',
  'York University Station',
  'Yorkdale Station']}

In [9]:
#Testing whether have to be explicit about line numbers for stations with multiple lines
payload = {#"subwayLine":lineid,
           "stationId":48, #St. George, Line 2
           "searchCriteria":''} 
r = requests.get(base_url, params = payload)
r.json()


Out[9]:
{'allLineXStations': None,
 'allStations': 'success',
 'data': None,
 'defaultDirection': [['SGL1', 'Eastbound</br> To Kennedy', 'BD'],
  ['SGL2', 'Westbound<br/> To Kipling', 'BD'],
  ['SGU1', 'Southbound<br/> To Union', 'YUS'],
  ['SGU2', 'Northbound<br/> To Vaughan Metropolitan Centre', 'YUS']],
 'limit': 3,
 'ntasData': [{'createDate': '2018-04-10T20:46:21',
   'id': 20947052333,
   'stationDirectionText': 'Northbound<br/> To Vaughan Metropolitan Centre',
   'stationId': 'SGU2',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 0.0,
   'timeString': '00.00',
   'trainDestination': 'VMC2',
   'trainDestinationStation': 'Vaughan Metropolitan Centre',
   'trainDirection': 'South',
   'trainId': 145,
   'trainMessage': 'AtStation'},
  {'createDate': '2018-04-10T20:46:21',
   'id': 20947052334,
   'stationDirectionText': 'Northbound<br/> To Vaughan Metropolitan Centre',
   'stationId': 'SGU2',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 0.9303657142857144,
   'timeString': '01.00',
   'trainDestination': 'WIL2',
   'trainDestinationStation': 'Wilson',
   'trainDirection': 'South',
   'trainId': 146,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:21',
   'id': 20947052335,
   'stationDirectionText': 'Northbound<br/> To Vaughan Metropolitan Centre',
   'stationId': 'SGU2',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 2.4766857142857144,
   'timeString': '03.00',
   'trainDestination': 'VMC2',
   'trainDestinationStation': 'Vaughan Metropolitan Centre',
   'trainDirection': 'South',
   'trainId': 148,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:21',
   'id': 20947052590,
   'stationDirectionText': 'Eastbound</br> To Kennedy',
   'stationId': 'SGL1',
   'subwayLine': 'BD',
   'systemMessageType': 'Normal',
   'timeInt': 1.5856777777777777,
   'timeString': '02.00',
   'trainDestination': 'KEN1',
   'trainDestinationStation': 'Kennedy',
   'trainDirection': 'East',
   'trainId': 235,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:21',
   'id': 20947052591,
   'stationDirectionText': 'Eastbound</br> To Kennedy',
   'stationId': 'SGL1',
   'subwayLine': 'BD',
   'systemMessageType': 'Normal',
   'timeInt': 3.229928888888889,
   'timeString': '04.00',
   'trainDestination': 'KEN1',
   'trainDestinationStation': 'Kennedy',
   'trainDirection': 'East',
   'trainId': 238,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:21',
   'id': 20947052592,
   'stationDirectionText': 'Eastbound</br> To Kennedy',
   'stationId': 'SGL1',
   'subwayLine': 'BD',
   'systemMessageType': 'Normal',
   'timeInt': 4.372895955555555,
   'timeString': '05.00',
   'trainDestination': 'KEN1',
   'trainDestinationStation': 'Kennedy',
   'trainDirection': 'East',
   'trainId': 239,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:22',
   'id': 20947052697,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'SGU1',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 0.0,
   'timeString': '00.00',
   'trainDestination': 'FIN1',
   'trainDestinationStation': 'Finch',
   'trainDirection': 'North',
   'trainId': 110,
   'trainMessage': 'AtStation'},
  {'createDate': '2018-04-10T20:46:22',
   'id': 20947052698,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'SGU1',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 10.037435428571428,
   'timeString': '11.00',
   'trainDestination': 'FIN1',
   'trainDestinationStation': 'Finch',
   'trainDirection': 'North',
   'trainId': 11,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:22',
   'id': 20947052699,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'SGU1',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 12.815018285714286,
   'timeString': '13.00',
   'trainDestination': 'FIN1',
   'trainDestinationStation': 'Finch',
   'trainDirection': 'North',
   'trainId': 118,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:21',
   'id': 20947052499,
   'stationDirectionText': 'Westbound<br/> To Kipling',
   'stationId': 'SGL2',
   'subwayLine': 'BD',
   'systemMessageType': 'Normal',
   'timeInt': 1.9141966666666668,
   'timeString': '02.00',
   'trainDestination': 'KIP2',
   'trainDestinationStation': 'Kipling',
   'trainDirection': 'West',
   'trainId': 211,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:21',
   'id': 20947052500,
   'stationDirectionText': 'Westbound<br/> To Kipling',
   'stationId': 'SGL2',
   'subwayLine': 'BD',
   'systemMessageType': 'Normal',
   'timeInt': 4.228725555555556,
   'timeString': '05.00',
   'trainDestination': 'KIP2',
   'trainDestinationStation': 'Kipling',
   'trainDirection': 'West',
   'trainId': 213,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:46:21',
   'id': 20947052501,
   'stationDirectionText': 'Westbound<br/> To Kipling',
   'stationId': 'SGL2',
   'subwayLine': 'BD',
   'systemMessageType': 'Normal',
   'timeInt': 7.6898903999999995,
   'timeString': '08.00',
   'trainDestination': 'KIP2',
   'trainDestinationStation': 'Kipling',
   'trainDirection': 'West',
   'trainId': 215,
   'trainMessage': 'Arriving'}],
 'searchCriteria': '',
 'searchCriteriaMatch': None,
 'stationId': '48',
 'subwayLine': None,
 'subwayLine2': '1',
 'subwayStations': ['Bathurst Station',
  'Bay Station',
  'Bayview Station',
  'Bessarion Station',
  'Bloor-Yonge Station',
  'Broadview Station',
  'Castle Frank Station',
  'Chester Station',
  'Christie Station',
  'College Station',
  'Coxwell Station',
  'Davisville Station',
  'Don Mills Station',
  'Donlands Station',
  'Downsview Park Station',
  'Dufferin Station',
  'Dundas Station',
  'Dundas West Station',
  'Dupont Station',
  'Eglinton Station',
  'Eglinton West Station',
  'Finch Station',
  'Finch West Station',
  'Glencairn Station',
  'Greenwood Station',
  'High Park Station',
  'Highway 407 Station',
  'Islington Station',
  'Jane Station',
  'Keele Station',
  'Kennedy Station',
  'King Station',
  'Kipling Station',
  'Lansdowne Station',
  'Lawrence Station',
  'Lawrence West Station',
  'Leslie Station',
  'Main Street Station',
  'Museum Station',
  'North York Centre Station',
  'Old Mill Station',
  'Osgoode Station',
  'Ossington Station',
  'Pape Station',
  'Pioneer Village Station',
  'Queen Station',
  'Queen’s Park Station',
  'Rosedale Station',
  'Royal York Station',
  'Runnymede Station',
  'Sheppard West Station',
  'Sheppard-Yonge Station',
  'Sherbourne Station',
  'Spadina Station',
  'St Andrew Station',
  'St Clair Station',
  'St Clair West Station',
  'St George Station',
  'St Patrick Station',
  'Summerhill Station',
  'Union Station',
  'Vaughan Metropolitan Centre Station',
  'Victoria Park Station',
  'Warden Station',
  'Wellesley Station',
  'Wilson Station',
  'Woodbine Station',
  'York Mills Station',
  'York University Station',
  'Yorkdale Station']}

In [10]:
data = r.json()
data['ntasData'][0]['createDate'].replace('T',' ')


Out[10]:
'2018-04-10 20:46:21'

Building a scraping script

By opening up the inspector tools in the browser, we can see the full list of station ids by hovering over the Select a subway station dropdown list. Stations increase in number from West to East.

For Line 1 they are numbered 1-32 (from Downsview to Finch, in order)

For Line 2 they are numbered 33-63 (from Kipling to Kennedy)

For Line 4 they are numbered 64-68 (from Sheppard to Don Mills)

Thus we can construct a dictionary that will represent every possible API call:


In [11]:
lines = {1: range(1, 33), #max value must be 1 greater
         2: range(33, 64), # west to east (Kipling onwards)
         3: range(64, 68)} # also west to east (Sheppard onwards)

In [12]:
def get_API_response(*args):
    baseurl = "http://www.ttc.ca/Subway/loadNtas.action"
    if len(args) > 1:
        line_id = args[0]
        station_id = args[2]
        payload = {"subwayLine":line_id,
               "stationId":station_id,
               "searchCriteria":''}
    else:
        station_id = args[0]
        payload = {"stationId":station_id,
               "searchCriteria":''}
    r = requests.get(baseurl, params = payload) 
    return r.json()

def insert_request_info(con, data, line_id, station_id):
    request_row = {}
    request_row['data_'] = data['data']
    request_row['stationid'] = station_id
    request_row['lineid'] = line_id
    request_row['all_stations'] = data['allStations']
    request_row['create_date'] = data['ntasData'][0]['createDate'].replace( 'T', ' ')
    cursor = con.cursor()
    cursor.execute("INSERT INTO public.requests(data_, stationid, lineid, all_stations, create_date)"
                   "VALUES(%(data_)s, %(stationid)s, %(lineid)s, %(all_stations)s, %(create_date)s)"
                   "RETURNING requestid", request_row)
    request_id = cursor.fetchone()[0]
    con.commit()
    return request_id

def insert_ntas_data(con, ntas_data, request_id):
    cursor = con.cursor()
    sql = """INSERT INTO public.ntas_data(
            requestid, id, station_char, subwayline, system_message_type, 
            timint, traindirection, trainid, train_message)
            VALUES (%(requestid)s, %(id)s, %(station_char)s, %(subwayline)s, %(system_message_type)s, 
            %(timint)s, %(traindirection)s, %(trainid)s, %(train_message)s);
          """
    for record in ntas_data:
        record_row ={}
        record_row['requestid'] = request_id
        record_row['id'] = record['id']
        record_row['station_char'] = record['stationId']
        record_row['subwayline'] = record['subwayLine']
        record_row['system_message_type'] = record['systemMessageType']
        record_row['timint'] = record['timeInt']
        record_row['traindirection'] = record['trainDirection']
        record_row['trainid'] = record['trainId']
        record_row['train_message'] = record['trainMessage']
        cursor.execute(sql, record_row)
    con.commit()
    cursor.close()

def query_stations(con, lines):
    data = {}
    for line_id, stations in lines.items():
        for station_id in stations:
            data = get_API_response(station_id)
            request_id = insert_request_info(con, data, line_id, station_id)
            insert_ntas_data(con, data['ntasData'], request_id)
    return data, request_id

Database schema

Looking at the response above. I've written up a basic schema of two tables to store the responses to the API. it's in create_tables.sql. Use this file to setup of PostgreSQL database either using terminal (Linux/OSX) or command line (Windows). Alternately, you can download PgAdmin v3 or v4 (depending on your platform) which will provide you with a GUI to setup and manage the database. In the latter case, the default database name is 'postgres' and use 'postgres' as the password as well when setting up the server.


In [13]:
dbsettings = {'database':'ttc',
              'user':'postgres'}
#              'host':'localhost'} 
con = connect(database = dbsettings['database'],
              user = dbsettings['user'])
              #host = dbsettings['host'])

In [14]:
data = query_stations(con, lines) # be patient, this command can take a while to complete

In [15]:
data


Out[15]:
({'allLineXStations': None,
  'allStations': 'success',
  'data': None,
  'defaultDirection': [['LES1', 'Eastbound<br/> to Don Mills', 'SHE'],
   ['LES2', 'Westbound<br/> To Sheppard-Yonge', 'SHE']],
  'limit': 3,
  'ntasData': [{'createDate': '2018-04-10T20:47:04',
    'id': 20947068027,
    'stationDirectionText': 'Westbound<br/> To Sheppard-Yonge',
    'stationId': 'LES1',
    'subwayLine': 'SHEP',
    'systemMessageType': 'Normal',
    'timeInt': 2.4838590604026844,
    'timeString': '03.00',
    'trainDestination': 'DML1',
    'trainDestinationStation': 'Don Mills',
    'trainDirection': 'East',
    'trainId': 461,
    'trainMessage': 'Arriving'}],
  'searchCriteria': '',
  'searchCriteriaMatch': None,
  'stationId': '67',
  'subwayLine': None,
  'subwayLine2': None,
  'subwayStations': ['Bathurst Station',
   'Bay Station',
   'Bayview Station',
   'Bessarion Station',
   'Bloor-Yonge Station',
   'Broadview Station',
   'Castle Frank Station',
   'Chester Station',
   'Christie Station',
   'College Station',
   'Coxwell Station',
   'Davisville Station',
   'Don Mills Station',
   'Donlands Station',
   'Downsview Park Station',
   'Dufferin Station',
   'Dundas Station',
   'Dundas West Station',
   'Dupont Station',
   'Eglinton Station',
   'Eglinton West Station',
   'Finch Station',
   'Finch West Station',
   'Glencairn Station',
   'Greenwood Station',
   'High Park Station',
   'Highway 407 Station',
   'Islington Station',
   'Jane Station',
   'Keele Station',
   'Kennedy Station',
   'King Station',
   'Kipling Station',
   'Lansdowne Station',
   'Lawrence Station',
   'Lawrence West Station',
   'Leslie Station',
   'Main Street Station',
   'Museum Station',
   'North York Centre Station',
   'Old Mill Station',
   'Osgoode Station',
   'Ossington Station',
   'Pape Station',
   'Pioneer Village Station',
   'Queen Station',
   'Queen’s Park Station',
   'Rosedale Station',
   'Royal York Station',
   'Runnymede Station',
   'Sheppard West Station',
   'Sheppard-Yonge Station',
   'Sherbourne Station',
   'Spadina Station',
   'St Andrew Station',
   'St Clair Station',
   'St Clair West Station',
   'St George Station',
   'St Patrick Station',
   'Summerhill Station',
   'Union Station',
   'Vaughan Metropolitan Centre Station',
   'Victoria Park Station',
   'Warden Station',
   'Wellesley Station',
   'Wilson Station',
   'Woodbine Station',
   'York Mills Station',
   'York University Station',
   'Yorkdale Station']},
 213)

Querying data from database

Now we will pull the data we've inserted in the Postgre database


In [16]:
lines = {1: [3]}# station_id = 3 (St. George), line_id = 1 (YUS)

In [17]:
data, request_id = query_stations(con, lines)

In [18]:
data


Out[18]:
{'allLineXStations': None,
 'allStations': 'success',
 'data': None,
 'defaultDirection': [['YKD1', 'Southbound<br/> To Union', 'YUS'],
  ['YKD2', 'Northbound<br/> To Vaughan Metropolitan Centre', 'YUS']],
 'limit': 3,
 'ntasData': [{'createDate': '2018-04-10T20:47:16',
   'id': 20947072057,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'YKD1',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 0.0,
   'timeString': '00.00',
   'trainDestination': 'FIN1',
   'trainDestinationStation': 'Finch',
   'trainDirection': 'North',
   'trainId': 121,
   'trainMessage': 'AtStation'},
  {'createDate': '2018-04-10T20:47:16',
   'id': 20947072058,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'YKD1',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 4.534429333333333,
   'timeString': '05.00',
   'trainDestination': 'FIN1',
   'trainDestinationStation': 'Finch',
   'trainDirection': 'North',
   'trainId': 136,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:47:16',
   'id': 20947072059,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'YKD1',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 7.379200571428571,
   'timeString': '08.00',
   'trainDestination': 'FIN1',
   'trainDestinationStation': 'Finch',
   'trainDirection': 'North',
   'trainId': 122,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:47:16',
   'id': 20947072228,
   'stationDirectionText': 'Northbound<br/> To Vaughan Metropolitan Centre',
   'stationId': 'YKD2',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 1.3254445714285714,
   'timeString': '02.00',
   'trainDestination': 'WIL2',
   'trainDestinationStation': 'Wilson',
   'trainDirection': 'South',
   'trainId': 138,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:47:16',
   'id': 20947072229,
   'stationDirectionText': 'Southbound<br/> To Union',
   'stationId': 'YKD2',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 2.687013714285714,
   'timeString': '03.00',
   'trainDestination': 'VMC2',
   'trainDestinationStation': 'Vaughan Metropolitan Centre',
   'trainDirection': 'South',
   'trainId': 140,
   'trainMessage': 'Arriving'},
  {'createDate': '2018-04-10T20:47:16',
   'id': 20947072230,
   'stationDirectionText': 'Northbound<br/> To Vaughan Metropolitan Centre',
   'stationId': 'YKD2',
   'subwayLine': 'YUS',
   'systemMessageType': 'Normal',
   'timeInt': 4.395184,
   'timeString': '05.00',
   'trainDestination': 'WIL2',
   'trainDestinationStation': 'Wilson',
   'trainDirection': 'South',
   'trainId': 141,
   'trainMessage': 'Arriving'}],
 'searchCriteria': '',
 'searchCriteriaMatch': None,
 'stationId': '3',
 'subwayLine': None,
 'subwayLine2': None,
 'subwayStations': ['Bathurst Station',
  'Bay Station',
  'Bayview Station',
  'Bessarion Station',
  'Bloor-Yonge Station',
  'Broadview Station',
  'Castle Frank Station',
  'Chester Station',
  'Christie Station',
  'College Station',
  'Coxwell Station',
  'Davisville Station',
  'Don Mills Station',
  'Donlands Station',
  'Downsview Park Station',
  'Dufferin Station',
  'Dundas Station',
  'Dundas West Station',
  'Dupont Station',
  'Eglinton Station',
  'Eglinton West Station',
  'Finch Station',
  'Finch West Station',
  'Glencairn Station',
  'Greenwood Station',
  'High Park Station',
  'Highway 407 Station',
  'Islington Station',
  'Jane Station',
  'Keele Station',
  'Kennedy Station',
  'King Station',
  'Kipling Station',
  'Lansdowne Station',
  'Lawrence Station',
  'Lawrence West Station',
  'Leslie Station',
  'Main Street Station',
  'Museum Station',
  'North York Centre Station',
  'Old Mill Station',
  'Osgoode Station',
  'Ossington Station',
  'Pape Station',
  'Pioneer Village Station',
  'Queen Station',
  'Queen’s Park Station',
  'Rosedale Station',
  'Royal York Station',
  'Runnymede Station',
  'Sheppard West Station',
  'Sheppard-Yonge Station',
  'Sherbourne Station',
  'Spadina Station',
  'St Andrew Station',
  'St Clair Station',
  'St Clair West Station',
  'St George Station',
  'St Patrick Station',
  'Summerhill Station',
  'Union Station',
  'Vaughan Metropolitan Centre Station',
  'Victoria Park Station',
  'Warden Station',
  'Wellesley Station',
  'Wilson Station',
  'Woodbine Station',
  'York Mills Station',
  'York University Station',
  'Yorkdale Station']}

In [19]:
cursor = con.cursor()

In [20]:
cursor.execute('''SELECT timint FROM ntas_data WHERE requestid = ''' + str(request_id) + ''' limit 10''')

In [21]:
rows = cursor.fetchall()

In [22]:
print(rows)


[(Decimal('0.0'),), (Decimal('4.534429333333333'),), (Decimal('7.379200571428571'),), (Decimal('1.3254445714285714'),), (Decimal('2.687013714285714'),), (Decimal('4.395184'),)]

In [23]:
import numpy

In [25]:
print(numpy.mean(rows)) # Average (expected) wait time at St. George. Note this is not the true wait time.


3.386878698412698233333333333