Initial import of lefrecce - lefrecce - Retrieve information about next trains and stations via lefrecce.it
(HTM) hg clone https://bitbucket.org/iamleot/lefrecce
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
---
(DIR) changeset a76124023feb0e0db87e89dfca3aebb7edb20b7f
(HTM) Author: Leonardo Taccari <iamleot@gmail.com>
Date: Mon, 1 Jan 2018 01:34:26
Initial import of lefrecce
Diffstat:
lefrecce.py | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 177 insertions(+), 0 deletions(-)
---
diff -r 000000000000 -r a76124023feb lefrecce.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/lefrecce.py Mon Jan 01 01:34:26 2018 +0100
@@ -0,0 +1,177 @@
+#!/usr/pkg/bin/python3.6
+
+#
+# Copyright (c) 2017 Leonardo Taccari
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+
+from datetime import datetime
+import json
+from urllib import parse, request
+
+
+def print_solution(solution):
+ print('{departure} ({departure_datetime:%H:%M %d/%m/%Y}) - '
+ '{arrival} ({arrival_datetime:%H:%M %d/%m/%Y}) '
+ '({duration})'.format(**solution))
+
+ for train in solution['trains']:
+ print(' [{acronym}] {id}:\t'
+ '{departure_station} ({departure_datetime:%H:%M}) - '
+ '{arrival_station} ({arrival_datetime:%H:%M})'.format(**train))
+
+ for stop in train['stoplist']:
+ print(' . {station:14}\t'
+ '{arrival_datetime:%H:%M} - '
+ '{departure_datetime:%H:%M}'.format(**stop))
+
+
+def solutions(origin, destination, adate, atime, verbose=True):
+ url = 'https://www.lefrecce.it/msite/api/solutions?' \
+ + 'origin=' + parse.quote(origin) + '&' \
+ + 'destination=' + parse.quote(destination) + '&' \
+ + 'arflag=A' + '&' \
+ + 'adate=' + parse.quote(adate) + '&' \
+ + 'atime=' + parse.quote(atime) + '&' \
+ + 'adultno=1&childno=0&direction=A&frecce=false&onlyRegional=false'
+
+ res = ''
+ req = request.Request(url, headers={'Accept-Language': 'en-US'})
+ with request.urlopen(req) as r:
+ for l in r:
+ res += l.decode()
+ j = json.loads(res)
+
+ for solution in j:
+ s = {}
+ s['departure'] = solution['origin']
+ s['departure_datetime'] = datetime.fromtimestamp(solution['departuretime'] / 1000)
+ s['arrival'] = solution['destination']
+ s['arrival_datetime'] = datetime.fromtimestamp(solution['arrivaltime'] / 1000)
+ s['duration'] = solution['duration']
+ s['trains'] = []
+
+ if verbose:
+ trains_url = 'https://www.lefrecce.it/msite/api/solutions/' + parse.quote(solution['idsolution']) + '/info'
+ res = ''
+ req = request.Request(trains_url, headers={'Accept-Language': 'en-US'})
+ # XXX: Often the request trains information regarding the current
+ # XXX: solution just return an empty string... Recheck until we have
+ # XXX: something useful...
+ while res == '':
+ try:
+ r = request.urlopen(req)
+ for l in r:
+ res += l.decode()
+ except:
+ pass
+
+ trains = json.loads(res)
+
+ for train in trains:
+ stoplist = []
+ if 'stoplist' in train:
+ for stop in train['stoplist']:
+ if stop['departuretime'] == None:
+ stop['departuretime'] = stop['arrivaltime']
+ if stop['arrivaltime'] == None:
+ stop['arrivaltime'] = stop['departuretime']
+
+ stoplist.append({
+ 'departure_datetime': datetime.fromtimestamp(stop['departuretime'] / 1000),
+ 'arrival_datetime': datetime.fromtimestamp(stop['arrivaltime'] / 1000),
+ 'station': stop['stationname'].lower().capitalize(),
+ })
+
+ s['trains'].append({
+ 'acronym': train['trainacronym'],
+ 'id': train['trainidentifier'],
+ 'departure_station': train['departurestation'].lower().capitalize(),
+ 'departure_datetime': datetime.fromtimestamp(train['departuretime'] / 1000),
+ 'arrival_station': train['arrivalstation'].lower().capitalize(),
+ 'arrival_datetime': datetime.fromtimestamp(train['arrivaltime'] / 1000),
+ 'stoplist': stoplist,
+ })
+
+ yield s
+
+
+def search_stations(name):
+ url = 'https://www.lefrecce.it/msite/api/geolocations/locations?name=' + \
+ parse.quote(name)
+
+ res = ''
+ req = request.Request(url, headers={'Accept-Language': 'en-US'})
+ with request.urlopen(req) as r:
+ for l in r:
+ res += l.decode()
+ j = json.loads(res)
+
+ stations = []
+ for station in j:
+ stations.append(station['name'])
+
+ return stations
+
+
+if __name__ == '__main__':
+ import argparse
+ import sys
+
+ ap = argparse.ArgumentParser(description='Retrieve information from lefrecce.it')
+ ap.add_argument('-s', metavar='search_station', type=str)
+ ap.add_argument('-o', metavar='origin', type=str, \
+ help='origin station')
+ ap.add_argument('-d', metavar='destination', type=str, \
+ help='destination station')
+ ap.add_argument('-a', metavar='adate', type=str, \
+ help='arrival date')
+ ap.add_argument('-t', metavar='atime', type=str, \
+ help='arrival time')
+ ap.add_argument('-q', action='store_true', help='silent output')
+ args = ap.parse_args()
+
+ # Search stations and exit
+ if args.s:
+ for s in search_stations(args.s):
+ print(s)
+ sys.exit(0)
+
+ # Set current date and time if the user does not provide them
+ if not args.a:
+ args.a = datetime.today().strftime('%d/%m/%Y')
+ if not args.t:
+ args.t = datetime.today().strftime('%H')
+
+ # Check arguments
+ for a in args.o, args.d, args.a, args.t:
+ if not a:
+ ap.print_usage()
+ sys.exit(1)
+
+ origin, destination, adate, atime = args.o, args.d, args.a, args.t
+ for s in solutions(origin, destination, adate, atime, verbose=(not args.q)):
+ print_solution(s)