Il vous arrive de rechercher des billets de train, et ne pas être capable d’ajouter tous les critères et filtres qui vous intéressent ?
Ça m’arrive très souvent.
Par exemple, je cherche des billets de train pour :
- Toulouse → Paris
- 2 adultes + 1 enfant avec une carte Enfant+
- 3 vélos
- pendant les vacances de la Toussaint
- le moins cher
- le plus court
Un vrai casse-tête en utilisant les sites traditionnels.
Vous ne pourrez pas obtenir l’ensemble des billets disponibles sur une période donnée par exemple. C’est dommage si vous n’avez pas de contrainte sur la date de départ…
Au mieux, vous aurez un calendrier de prix, avec le meilleur prix pour chaque jour du mois.
Malheureusement, ce calendrier n’est disponible que pour les trajets les plus courants. Si vous sortez des cas prévus, gare à l’erreur :
De même, il n’est pas possible d’obtenir le calendrier des prix en prenant en compte une carte de réduction Enfant+, ou de réserver un emplacement vélo 😞
L’autre solution, c’est de :
- rechercher les billets de train à partir de la date de départ,
- de cliquer sur la recherche des trains suivants,
- de cliquer sur la recherche des trains suivants,
- de cliquer sur la recherche des trains suivants,
- …
- jusqu’à la date de fin.
Bref, une tâche longue et pénible…
Ce sont justement mes critères pour démarrer un nouveau projet !
Le choix du service
Pour obtenir les tarifs de billets de train en France, deux solutions existent : le portail officiel Oui.sncf (anciennement Voyage-sncf) et Trainline (anciennement Capitaine Train).
Au-delà du site web, chacun propose une application mobile.
C’est de ce côté que je regarde pour créer un module Python.
En effet, contrairement à leurs sites web, l’application mobile fait des appels “en clair” à leurs API internes. Il suffit d’utiliser l’application, et d’espionner les échanges avec leurs serveurs. J’utilise pour ce type d’analyse le logiciel Charles, mais il existe également mitmproxy.
Vous pouvez en savoir plus en lisant l’article sur le reverse engineering de l’application mobile ING Direct.
Bref, après avoir regardé les possibilités des deux applications, mon choix s’est orienté sur Trainline.
L’application mobile de Oui.sncf ne permet pas de réserver des billets de train avec emplacement vélo… C’est rédibitoire pour moi :)
Un module Python
La suite du projet consiste alors à analyser les requêtes entre l’application et les serveurs de Trainline. On regarde :
- les URL (exemple : https://api.serveur.com/rechercher_trains)
- les paramètres d’entrée et leur format (exemple : {“gare_depart”: “Toulouse”, “gare_arrivee”: “Bordeaux”})
- la logique des échanges (quelle requête est exécutée après telle autre…)
- les réponses (exemple : {[“heure_depart”: “8:58”, “heure_arrivee”: “10:57”, “prix”: 15.0}])
Ensuite, on développe un module Python qui va permettre d’envoyer ces requêtes à partir de fonctions. Ce module masque complétement le contenu des requêtes et le format de l’API.
En suivant cette logique (et après quelques heures de développement), le module trainline est né !
Voici un exemple d’utilisation :
# -*- coding: utf-8 -*-
import trainline
resultats = trainline.search(
departure_station="Toulouse",
arrival_station="Bordeaux",
from_date="15/10/2018 08:00",
to_date="15/10/2018 21:00")
print(resultats.csv())
On obtient alors :
departure_date;arrival_date;duration;number_of_segments;price;currency;transportation_mean;bicycle_reservation
15/10/2018 08:00;15/10/2018 10:55;02h55;1;5,0;EUR;coach;unavailable
15/10/2018 08:00;15/10/2018 10:50;02h50;1;4,99;EUR;coach;unavailable
15/10/2018 08:19;15/10/2018 10:26;02h07;1;20,5;EUR;train;10,0
15/10/2018 08:19;15/10/2018 10:26;02h07;1;65,0;EUR;train;unavailable
Beaucoup plus simple que de composer les requêtes HTTP à la main, non?
Testons le module sur un exemple
Reprenons l’exemple de l’introduction :
- Toulouse → Paris
- 2 adultes + 1 enfant avec une carte Enfant+
- 3 vélos
- pendant les vacances de la Toussaint
- le moins cher
- le plus court
Le module va nous aider dans cette recherche.
Les vacances de la Toussaint 2018 vont du samedi 20 octobre au lundi 5 novembre.
# -*- coding: utf-8 -*-
import trainline
Papa = trainline.Passenger(birthdate="01/01/1986")
Maman = trainline.Passenger(birthdate="01/01/1987")
Enfant = trainline.Passenger(birthdate="01/01/2012",
cards=[trainline.ENFANT_PLUS])
resultats = trainline.search(
passengers=[Papa, Maman, Enfant],
departure_station="Toulouse",
arrival_station="Paris",
from_date="20/10/2018 08:00",
to_date="15/11/2018 21:00",
bicycle_with_or_without_reservation=True)
print(resultats.csv())
On obtient alors tous les trains possibles pendant cette période au format csv.
Il suffit alors de récupérer ces résultats et les ouvrir sur un tableur pour les trier, et obtenir le billet le moins cher.
Nota : J’ai ajouté la colonne prix_total, correspondant au prix des billets de train + le prix de la réservation des emplacements vélos. Soit : price + bicycle_reservation
Bilan : deux dates intéressantes, le 23 et 24 octobre, avec un prix total de 35€ pour nous 3 et nos vélos ! (le prix maximum étant de 301,50€…)
Une fois le billet repéré, rendez-vous sur Trainline pour le réserver.
Une commande dans le terminal
Le module Python Trainline est pratique, mais il nécessite de développer ou d’adapter un petit programme pour chaque recherche.
Il doit y avoir plus simple…
En complément du module, j’ai donc créé l’utilitaire trainline_cli.py
, avec une interface en ligne de commande (CLI).
Cela s’utilise donc dans le terminal, comme un ls
ou un grep
.
Si je recherche les billets de train de Toulouse à Bordeaux pour les 2 prochaines heures, je tape dans le terminal :
trainline_cli.py --departure="Toulouse" --arrival="Bordeaux" --next=2hours
Ou encore plus court (une fois que vous serez habitués) :
trainline_cli.py -d Toulouse -a Bordeaux -n 2h
Vous obtiendrez les résultats au format csv.
Rendez-vous sur la page Github du projet Trainline pour plus de détails sur le module Python et l’outil (installation, exemples d’utilisation).
Si vous ne voulez manquer aucun article, soyez notifié directement dans votre boite mail en vous inscrivant à la newsletter