Tag: viaggiatreno

  • Viaggiatreno Ruby gem: version 1.0.5

    On the background of all my activities, I continued the developing of viaggiatreno, a Ruby gem to parse Italian railway real-time system information of the status of the various trains: location, delay, expected and real arrival time. Yesterday I released the version 1.0.5 of this gem, which improves the overall code quality of this gem (0 rubocops violations!):

    viaggiatreno gem source code is hosted on GitHub.

    Simple usage of this gem has been included in the README.

    Another interesting fact that I dealt while writing continuous integration test (with Travis) in the development of this gem: as it fetches and parses information from Internet URLs, one way of writing RSpec tests is to “mock” the remote web part.

    Using vcr gem, I mocked the response of the remote web server in order to write static test-cases (since the informations on train change over time, subsequent web requests did not fetch the same results).

  • viaggiatreno-scraper: una libreria Ruby per accedere a viaggiatreno/trenitalia

    Un po’ per divertimento e un po’ perché volevo approfondire la mia conoscenza di Ruby e delle regex, oltre che delle espressioni XPath, ho deciso di rilasciare una libreria opensource Ruby che ho creato. Permette infatti di accedere ai dati di viaggiatreno che espone gli orari dei treni di Trenitalia in tempo reale.

    Come funziona?

    Un paio di anni fa avevo scritto un parser analogo in Python, ma molto meno robusto [proprio perché non utilizzavo le espressioni XPath e le regex]. Il nuovo scraper, scritto in Ruby con l’ausilio di nokogiri, è molto semplice da utilizzare; un esempio:

    irb(main):004:0> require './src/Train.rb'
    irb(main):005:0> train = Train.new(5033) # numero identificativo del treno (vedi Trenitalia.it)                               
    => 5033 (REG 5033): Il treno e' arrivato con 8 minuti di ritardo 
    (state: FINISHED, delay: 8, lastUpdate: )
    irb(main):007:0> train.status
    => "Il treno e' arrivato con 8 minuti di ritardo"
    irb(main):008:0> train.delay
    => 8
    irb(main):009:0> train.lastStop
    => "[X] BERGAMO = SCHEDULED: 07:46 ACTUAL: 07:53\n"
    irb(main):010:0> train.trainStops
    => [[X] LECCO = SCHEDULED: 07:03 ACTUAL: 07:04
    , [X] VERCURAGO S.GIROLAMO = SCHEDULED: 07:08 ACTUAL: 07:08
    , [X] CALOLZIOCORTE OLGINATE = SCHEDULED: 07:11 ACTUAL: 07:11
    , [X] CISANO CAPRINO BERGAMASCO = SCHEDULED: 07:22 ACTUAL: 07:21
    , [X] PONTIDA = SCHEDULED: 07:26 ACTUAL: 07:32
    , [X] AMBIVERE MAPELLO = SCHEDULED: 07:31 ACTUAL: 07:36
    , [X] PONTE S.PIETRO = SCHEDULED: 07:38 ACTUAL: 07:43
    , [X] BERGAMO = SCHEDULED: 07:46 ACTUAL: 07:53
    ]
    

    Di conseguenza, un programma alert per venire avvisati via sms (tramite tinsms) solo quando il treno è in ritardo per più di 10 minuti, o quando il treno non è ancora partito (scioperi, malfunzionamenti, etc.), diventa:

    require_relative 'src/Train.rb'
    require_relative '../sms-utils/sendsms.rb'
    
    RECIPIENT = 'num_tel'
    log = Logger.new('log/viaggiatreno-alert.log')
    log.level = Logger::DEBUG
    
    train = Train.new(ARGV[0])
    
    if train.delay.to_i >= 10 or train.status == "Il treno non e' ancora partito"
       send_sms(RECIPIENT, train)
       log.info(train)
    end
    

    Ho rilasciato i sorgenti su GitHub: viaggiatreno-scraper – il codice ha licenza GPL, e di conseguenza siete liberi di dire la vostra e soprattutto apportare migliorie!

    Un altro esempio di cosa si potrebbe fare?
    Ogni giorno alle 11:59PM, si potrebbe raccogliere la situazione di tutti i treni circolati sulla rete ferroviaria; in questo modo, si potrebbero estrarre delle curiose statistiche sul ritardo/anticipo medio, e tanto altro. Scrivere un task MapReduce/Hadoop che fa tutto questo non è per niente complicato…

  • Trenitalia e Viaggiatreno: come implementare un servizio “fai da te” per avere le informazioni dello stato di un treno via SMS

    Da quando sono diventato un pendolare (per lavoro), ho iniziato a (ri)frequentare assiduamente le stazioni ferroviarie e i treni di Trenitalia.

    station.

    Dopo un paio di settimane passate sui treni, mi sono accorto di un servizio interessante: il sito Viaggiatreno: il sito contiene le informazioni sui treni (informazioni in tempo reale sullo stato di un treno come ritardo o anticipo, ora prevista di arrivo e fermate già effettuate).

    Esigenza

    Dopo aver provato il disagio di un treno soppresso (e quindi essermi svegliato un’ora prima per stare un’ora ad aspettare in stazione), mi sono reso conto di poter, perlomeno, arginare il problema se si fosse presentato in futuro; conoscere lo stato del treno direttamente sul telefonino mi permetterebbe, la mattina, di poter scegliere un mezzo alternativo senza recarmi in stazione nel caso in cui il treno sia in ritardo o soppresso. Oppure, se il treno è in anticipo, di accelerare i tempi.

    Soluzioni esistenti

    • Potrei controllare il sito Viaggiatreno accedendo il computer, connettendomi a Internet e andando sul sito Viaggiatreno. Contro: il tempo richiesto è troppo (~ 5 minuti. E la mattina anche 5 minuti sono preziosissimi).
    • Potrei installare su iPhone l’applicazione ProntoTreno, un’applicazione che fornisce lo stato di tutti i treni in tempo reale. Contro: il mio access point WIFI non è sempre attivo; non ho a disposizione la connessione 3G. Inoltre, se dovessi cambiare telefono per passare ad un telefono senza WIFI/3G, questa soluzione non è più applicabile.

    L’idea

    Il mezzo da utilizzare è sicuramente il mobile. L’incognita era semplicemente trovare il modo per raggiungere i telefoni, ed è stato individuato negli SMS, supportati da tutti i telefoni.

    L’altro fattore da tenere in considerazione è: come ottenere i dati da Viaggiatreno? Il sito utilizza Flash, ed estrarre informazioni testuali e puntuali da Flash penso sia infattibile. La soluzione è presto trovata: fortunatamente, Viaggiatreno offre anche una versione mobile, realizzata in (X)HTML, per la gioia dei parser.

    La realizzazione

    Per la realizzazione del servizio abbiamo bisogno di:

    • Un server Linux attivo e connesso a Internet durante il lasso di tempo in cui vogliamo essere avvisati via SMS. Inoltre, il server Linux deve avere installato crontab, l’interprete python e alcuni pacchetti python che vedremo più avanti.
    • Un servizio per mandare SMS gratuitamente: io mi appoggio a virgilio.it, che mi permette di ricevere via sms tutte le email ricevute all’indirizzo indirizzo@sms.tin.it [per i più impazienti: in questo modo per ricevere SMS è sufficiente mandare una mail]. Se invece non potete usare virgilio.it, vi raccomando di utilizzare MoioSMS per l’invio gratuito di SMS.
    • Un account GMail da cui mandare la mail del punto sopra (se siete degli smanettoni, non avete bisogno di questo e potrete usare il vostro SMTP, a patto di sostituirlo nel codice).
    • Un telefono mobile abilitato alla ricezione di SMS e attivo (ovviamente!)
    • Il numero del treno di nostro interesse: per conoscere il numero del treno, è sufficiente andare su TreniItalia, immettere partenza e arrivo e annotarsi il numero del treno. Il numero del treno è unico e non cambia.
    • Lo script python seguente, che ho scritto in Python utilizzando le librerie python-mechanize e python-beautifulsoup (installatele seguendo la guida per la vostra distribuzione. Per Ubuntu/Debian ho usato apt-get install python-mechanize python-beautifulsoup). Il codice è ancora immaturo, ma funziona (vedi screenshot):
      “`
      #! /usr/bin/python

      import BeautifulSoup
      import mechanize
      import smtplib
      import time
      import datetime
      from email.MIMEMultipart import MIMEMultipart
      from email.MIMEBase import MIMEBase
      from email.MIMEText import MIMEText
      from email import Encoders
      import os
      import sys

      gmail_user = "gmail username"
      gmail_pwd = "gmail pass"

      def mail(to, subject, text):
      msg = MIMEMultipart()

      msg['From'] = gmail_user
      msg['To'] = to
      msg['Subject'] = subject

      msg.attach(MIMEText(text))

      mailServer = smtplib.SMTP("smtp.gmail.com", 587)
      mailServer.ehlo()
      mailServer.starttls()
      mailServer.ehlo()
      mailServer.login(gmail_user, gmail_pwd)
      mailServer.sendmail(gmail_user, to, msg.as_string())
      mailServer.close()

      numtreno = sys.argv[1]
      stazione = sys.argv[2]

      tobeparsed = mechanize.urlopen(str(str('https://mobile.viaggiatreno.it/viaggiatreno/mobile/scheda?numeroTreno=') + str(numtreno) + str('&tipoRicerca=numero&lang=IT')))
      f = BeautifulSoup.BeautifulSoup(tobeparsed)
      f = f.prettify()
      f = f[f.find('<!– SITUAZIONE –>'):]
      f = f[:f.find('</div>')]
      s1 = f[f.find('<strong>')+len('<strong>'):f.find('<br />')]
      s2 = f[f.rfind('–>')+len('–>'):f.find('</strong>')]
      s1 = s1.replace(''',"'")
      s1 = s1.split()
      s2 = s2.split()
      tobeparsed = mechanize.urlopen(str(str('https://mobile.viaggiatreno.it/viaggiatreno/mobile/scheda?dettaglio=visualizza&numeroTreno=') + str(numtreno) + str('&tipoRicerca=numero&lang=IT')))
      f = BeautifulSoup.BeautifulSoup(tobeparsed)
      f = f.prettify()
      f = f[f.find(stazione):]
      f = f[:f.find("</div>")]
      arr1 = f[f.find('')+len('<p>'):f.find('<br />')]
      or1 = f[f.find('<strong>')+len('<strong>'):f.find('</strong>')]
      arr = f[f.rfind('<p>'):f.rfind('</p>')]
      arr2 = arr[arr.find('<p>')+len('<p>'):arr.find('<br />')]
      or2 = arr[arr.find('<strong>')+len('<strong>'):arr.find('</strong>')]
      arr1 = arr1.split()
      or1 = or1.split()
      arr2 = arr2.split()
      or2 = or2.split()
      arr1.extend(or1)
      arr2.extend(or2)

      L = [s1, s2, arr2]
      for i in xrange(len(L)):
      L[i] = ' '.join(L[i])
      message = '\n'.join(L)

      mail("indirizzo@sms.tin.it",
      sys.argv[1],
      message,
      )
      “`

      Il codice estrae le informazioni di interesse da Viaggiatreno mobile (come detto, per fare il parsing occore usare il sito in versione mobile) come lo stato corrente del treno (posizione ed eventuali minuti di ritardo o anticipo) e l’orario di arrivo previsto e manda queste informazioni all’indirizzo mail “speciale” che gira il messaggio al mio numero di cellulare via SMS [per l’invio della mail il servizio usa GMail]. Come detto, potreste usare MoioSMS (via pipe o python import) semplicemente sostituiendo la parte di invio della mail.

    Come si utilizza?

    • Lo script accetta due parametri da command-line: il numero di treno a cui siete interessati e la stazione di cui volete conoscere l’orario di arrivo stimato (es. “LECCO MAGGIANICO”).
    • Modificate, nello script le variabili gmail_user e gmail_password con le credenziali del vostro account GMail che useremo per spedire la mail verso l’indirizzo speciale che girerà le mail in SMS. Sempre nel codice, sostituite appunto indirizzo@sms.tin.it con il vostro indirizzo “speciale” che tramuta il messaggio e-mail in SMS.
    • Usando crontab, inserite una entry del tipo:
      08 07 * * 1-5 python /home/mbologna/parser.py 5033 “LECCO MAGGIANICO”
      Per avere un aggiornamento via SMS alle 07:08 di tutti i giorni feriali del treno 5033 specificando che deve fornirci l’orario di arrivo previsto alla stazione di “LECCO MAGGIANICO”.

    Risultati

    La mattina, prima di recarmi in stazione, controllo sul mio telefono e automaticamente ricevo 3 SMS gratuiti diversi contenenti lo stato del treno man mano che si avvicina alla stazione in cui io salgo sul treno. In questo modo, ancora prima di uscire di casa, posso sapere se il treno è in ritardo o se è stato soppresso.

    Qui accanto, la testimonianza di 2 degli SMS che ricevo quotidianamente.

    Sviluppi futuri

    • Miglioramento del codice di download/parsing
    • Integrazione con MoioSMS

    Curiosità