Vous êtes ici

I, Robot

Portrait de ivan
Mon petit frère m'a récemment demandé un petit coup de main. Il a l'intention de faire de l'intérim cet été pour gagner un peu d'argent, et pour cela, il s'est inscrit sur un site que nous appellerons pudiquement Womanpower afin de conserver son anonymat. Détail important, les CVs des candidats sont remis sur le dessus de la pile lorsqu'ils se connectent sur le site, afin, je suppose, de favoriser les gens en recherche active.

Mais lorsqu'on a 21 ans, une vie sociale, et qu'on est en juillet, on a pas forcément envie d'aller sur un site toutes les deux heures juste pour trouver du travail. On a même pas forcément internet.

Comme souvent, la solution maline, c'est de scripter, et de laisser aux ordinateurs les tâches répétitives pendant qu'on mange des glaces sous la pluie battante de notre été pourri. Voici donc un petit script Python basé sur la bibliothèque mechanize, qui est censée simuler le comportement d'un navigateur web. Malheureusement, celle-ci souffre d'une documentation atroce, et il aura fallu tâtonner un peu avant d'arriver à mes fins.

L'idée du script est extrêmement simple : on possède une liste d'identifiants, et pour chacun d'entre eux, on veut se connecter une fois toutes les deux heures.

CREDENTIALS = [
                { 'login': "login1", 'password': "pass1", 'name': "Name LASTNAME" },
                { 'login': "login2", 'password': "pass2", 'name': "Another NAME" }
              ]
 
def main():
    while True:
        for cred in CREDENTIALS:
            connect_to_womanpower(cred)
        time.sleep(7205) # Two hours = 7200 seconds
Jusque là, rien de bien sorcier. On renseigne juste le nom de l'utilisateur, puisqu'il apparaît sur la page une fois identifié. Cela nous permet de nous assurer qu'on a bien atteint la page web que l'on voulait.

Le travail commence vraiment dans la partie suivante. La philosophie de mechanize est d'émuler un utilisateur qui suivrait les liens hypertextes de la page. On commence donc en se connectant sur le site visé, et on peut ensuite utiliser tout un ensemble de fonctions pour trouver le lien voulu dans la page (en cherchant dans l'URL ou le texte du lien). Par exemple, pour accéder à la page d'identification depuis la page d'accueil, on cliquerait sur le lien "Accédez à votre compte". Ceci se fait en deux lignes de code :

br.open("http://www.womanpower.fr/")
br.follow_link(text_regex = r'votre compte')
Le texte "votre compte" étant contenu dans "Accédez à votre compte", mechanize choisit le bon lien et le suit. Pour le suivant, les choses se compliquent : la partie de la page chargée de la saisie des identifiants est incluse depuis une iframe, afin que celle-ci se fasse en HTTPS (le reste de la page étant en HTTP). Les utilisateurs ne sont pas rassurés par le petit cadenas dans la barre d'adresse, mais au moins, les identifiants transitent de manière chiffrée.

Problème, mechanize n'inclut pas automatiquement les iframes dans la page. Pour y accéder, il faut les suivre comme un lien, ce qui est relativement contre-intuitif. On peut alors sélectionner le formulaire, et mettre les bonnes données dans les champs identifiant et mot de passe. Pour trouver le nom du formulaire dans la page, pas de secret : il faut en consulter le code source. Enfin, on soumet le formulaire, et nous voila identifiés !

# Put the credentials and submit.
br.select_form(name="formulaire")
br["identifiant"] = credentials["login"]
br["passwd"] = credentials["password"]
response = br.submit()
Enfin, presque. On n'obtient malheureusement pas immédiatement la page finale, car en cas d'authentification réussie, une redirection JavaScript est retournée, que mechanize n'est (heureusement) pas capable d'interpréter. On peut donc récupérer l'URL soi-même dans la page à l'aide d'une expression régulière à s'arracher les yeux, et la suivre - et cette fois, le tour est joué.

La facilité avec laquelle on peut automatiser ce genre de tâches laisse cependant rêveur quant à la fiabilité des nombreux sondages réalisés sur internet. On pourrait sans aucun mal enrichir ce script en le branchant sur un petit VPN qui lui permettrait de changer d'adresse IP entre chaque connexion, juste pour le plaisir de se faire élire personne la plus influente de l'année par le magazine Time.

Une solution facile et beaucoup moins rigolote aurait été de se connecter une fois avec Internet Explorer pour obtenir le cookie d'identification, et d'utiliser le Task Scheduler de Windows (si vous connaissez cron, vous n'avez probablement pas besoin de ce script) pour se connecter sur la bonne URL à intervalles réguliers.

Pour archive, voici le script final. N'oubliez pas que ces approches peu élégantes, dites de scraping, sont susceptibles de cesser de fonctionner à tout changement sur le site cible !


"""
 (c) 2012 Ivan Kwiatkowski
 
 This is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 This source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this source code. If not, see http://www.gnu.org/licenses/.
"""
from datetime import datetime
import os
import sys
import re
import time
import mechanize
 
URL_REGEXP = "(https?:((//)|(\\\\))+[\w\d:#@%/;$()~_?\+-=\\\.&]*)" # Don't even try.
 
CREDENTIALS = [
                { 'login': "login1", 'password': "pass1", 'name': "Name LASTNAME" },
                { 'login': "login2", 'password': "pass2", 'name': "Another NAME" }
              ]
 
def main():
    while True:
        try:
            for cred in CREDENTIALS:
                connect_to_womanpower(cred)
            time.sleep(7205) # Two hours = 7200 seconds
        except KeyboardInterrupt:
            print "[*] Thank you for using this script :)"
            break
 
 
def connect_to_womanpower(credentials):
    """
    Connects to the Womanpower website using the given credentials.
    """
    try:
        br = mechanize.Browser()
        br.addheaders = [('User-agent', 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)')] # Use a standard user-agent
 
        br.open("http://www.womanpower.fr/")
        br.follow_link(text_regex = r'votre compte')
        br.follow_link(url_regex = r'connexionInterimaire')
 
        # Put the credentials and submit.
        br.select_form(name="formulaire")
        br["identifiant"] = credentials["login"]
        br["passwd"] = credentials["password"]
        response = br.submit()
 
        # This step needs a little handiwork since the JavaScript redirection is not supported by mechanize.
        redirect_url = re.search(URL_REGEXP, response.read()).group(0)
        final_page = br.open(redirect_url)
 
        # Check that the name of the user is in the final page (just to make sure everything went well).
        if credentials["name"] in final_page.read():
            print "[*] %s: %s logged in successfully!" % (datetime.now(), credentials["name"])
        else:
            print "[!] %s: could not log %s in!" % (datetime.now(), credentials["name"])
    except Exception:
        print "[!] %s: Exception while logging in %s!\n    Please report this to Ivan." % (datetime.now(), credentials["name"])
 
if __name__ == "__main__":
    main()