Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

Python Requests POST sur un formulaire géré par javascript

+3 votes

Droit au but : j'essaye de parser les résultats de http://www.voyages-sncf.com/billet-train/ pour récupérer la liste des prix pour le jour indiqué. J'utilise requests et BeautifulSoup (enfin j'aimerais) le seul hic c'est que l'envoi du formulaire semble géré par un script, et du coup ça plante quand je fais mon requests.post.

Ce que j'ai essayé:
- Sérialiser le tout en JSON et l'envoyer directement sur l'adresse
fournie dans l'action du formulaire.

  • Regardé du côté de Selenium (mais manifestement c'est pas top pour ce
    que je voudrais faire)

  • Regardé si j'avais bien fourni toutes les valeurs obligatoires (ville
    de départ, arrivée, date, ...) et pas fait d'erreur de typos.

    • Regardé si la sncf avait une api (et elle en a une ! https://data.sncf.com/ mais pas encore de jeu de données pour les tgv qui est ce que je voudrais obtenir)

Ce que j'obtiens à chaque fois :

  • La page d'erreur canonique de la sncf.

Apparemment ils utilisent angular (je ne pense pas que ça change quelque chose mais qui sait ?) le formulaire utilise l'encoding x-www-urlencoded, mais c'est géré par requests ça non ? Autre chose, le process se fait en deux appels : après avoir envoyé le formulaire, l'url d'action est appelé et un id ('hid') est généré dans l'url, puis l'utilisateur est redirigé vers la page de résultats avec ce même id dans l'url. Requests prend e charge les redirections d'après ce que j'ai compris, mais je dois mal comprendre puisque àa ne marche pas.

Le code que j'ai pour le moment:

  1 # -*- coding: utf-8 -*-
  2 import requests
  5 
  6 url = 'http://www.voyages-sncf.com/billet-train/'
  7 formData = {
  8         'ORIGIN_CITY': 'PARIS',
  9         'DESTINATION_CITY': 'LYON',
 10         'OUTWARD_DATE': '29/04/2015',
 11         'TRAVEL_TYPE': 'AS',
 12         'OUTWARD_SCHEDULE_TYPE': 'DEPARTURE_FROM',
 13         'OUTWARD_TIME': '8'
 14         }
 15 headers = {'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36'}
 16 
 17 session = requests.Session()
 18 r = session.post(url, headers=headers, data=formData)
 19 
 20 if r.status_code == 200:
 21     print "ok"
 22     # Looking for prices
 23     with open('output.txt', 'w') as f:
 24         f.write(r.content)

Du coup je comprends pas grand chose avec mes modestes neurones et je me demandais comment vous gériez ça vous ?

demandé 23-Avr-2015 par betepoilue (144 points)
edité 23-Avr-2015 par max

1 Réponse

+3 votes
 
Meilleure réponse

J'ai un peu regardé le truc avec un proxy (Burp) pour voir ce qui passait.

La requête pour valider le formulaire est en GET, donc je te conseille de commencer par là pour essayer de comprendre le mécanisme. Plus précisément tu fais la première recherche sur l'URL suivante :

http:/www.voyages-sncf.com/vsc/train-ticket/directSearchTravel

Ensuite cela te redirige sur la page :

billet-train/recherche-en-cours?hid=<id>

puis finalement sur

billet-train/resultat?hid=<id_bis>

Donc en détail si tu regardes ta réponse (statut code 302) pour la première requête tu as une redirection comme tu le disais et le header Location qui va te pointer vers une URL du genre /billet-train/recherche-en-cours?hid=ID. Tu as juste à reproduire une requête vers cette URL.

Si on se penche sur requests ; requests réalise les redirections automatiquement et tu peux voir l'historique de redirection avec r.history (détail ici). Donc ce qu'il va falloir que tu gères c'est le passage entre l'étape 2 et 3 qui correspond à la jolie barre d'attente quand tu es sur le site de voyages-scnf.

Du coup, je ne sais pas précisément comment tu peux gérer l'attente entre l'étape 2 et la 3, mais ça fonctionne la même manière, je pense que la manière brute fonctionne : envoyer une première requête pour dire que tu veux les résultats puis tu attends un peu, puis tu redemandes pour voir si la réponse est une 302.

J'espère que je suis clair. Sinon pour ce genre de truc je pense que Scrapy pourrai t'aider énormément, notamment pour le crawling ensuite.

répondu 23-Avr-2015 par Hawke (466 points)
sélectionné 23-Avr-2015 par betepoilue

Merci pour ta réponse ! Je vais regarder du côté de scrapy alors et retenter le tout avec un GET. Et merci pour Burp, je connaissais pas mais ça a l'air plutôt cool.

...