[couverture de Linux Magazine 80]

Perles de Mongueurs (20)

Article publié dans Linux Magazine 80, février 2006.

[+ del.icio.us] [+ Developers Zone] [+ Bookmarks.fr] [Digg this] [+ My Yahoo!]

Les perles de ce mois-ci ont toutes été rédigées par Philippe "BooK" Bruhat (book@mongueurs.net), de Lyon.pm et Paris.pm.

Chapeau

Dans la lignée des articles sur WWW::Mechanize parus dans Linux Magazine 75 et 77, voici deux petits robots créés pour fournir rapidement de petits services.

Un (autre) robot de traduction

Mise à jour avril 2007 : L'ordre des formulaires ayant changé, on s'appuie maintenant sur leur nom.

Nous avons déjà présenté dans Linux Mag 61 un traducteur automatique, qui allait chercher les traductions de Babelfish à l'aide d'un module CPAN. Voici aujourd'hui un rapide robot de traduction qui s'appuie cette fois sur le site FreeTranslation (http://www.freetranslation.com/).

Comme toujours, une fois trouvée la page contenant le formulaire adéquat, nous demandons à voir le formulaire dans ses moindres détails :

    $ mech-dump http://www.freetranslation.com/
    POST http://ets.freetranslation.com/ [frmTextTranslator]
      sequence=core                  (hidden readonly)
      mode=html                      (hidden readonly)
      charset=UTF-8                  (hidden readonly)
      template=results_en-us.htm     (hidden readonly)
      language=English/Spanish       (option)   [*English/Spanish/English to Spanish|...|Japanese/English/Japanese to English]
      srctext=Type or paste some text here. (textarea)
      HumanTranslation=<UNDEF>       (button)
      Submit=FREE Translation        (submit)

    POST http://www.freetranslation.com/web.asp [frmWebTranslator]
      sequence=core                  (hidden readonly)
      language=English/Spanish       (option)   [*English/Spanish/English to Spanish|...|Japanese/English/Japanese to English]
      url=Type or paste a website address here. (text)
      Submit=FREE Translation        (submit)
      username=freetranslation       (hidden readonly)
      password=xO0y3uwr              (hidden readonly)

C'est ici le premier formulaire qui nous intéresse, frmTextTranslator. Les noms des champs sont suffisamment parlants pour que nous identifiions rapidement les champs utiles : language et srctext. Un premier essai nous montre que la réponse est également dans un des champs du formulaire, le champ dsttext.

Le script est constitué d'une boucle simple qui lit l'entrée standard ligne à ligne, envoie chaque ligne au site de traduction et affiche le résultat, avant de re-présenter le prompt, pour recommencer :

    #!/usr/bin/perl
    use strict;
    use WWW::Mechanize;
    my $m = WWW::Mechanize->new();
    $|++;    # autoflush

    # charge la première page
    $m->get('http://www.freetranslation.com/');
    die $m->res()->status_line() . "\n" unless $m->success();

    print "? ";
    while (<>) {

        # sélectionne le formulaire voulu
        $m->form_name('frmTextTranslator');

        # ou 'French/English', 'English/German', 'Italian/English'
        $m->field( language => 'English/French' );

        $m->field( charset => 'iso-8859-1' );    # voir ci-dessous
        $m->field( srctext => $_ );
        $m->click();

        print $m->current_form()->value('dsttext');
        print "\n? ";
    }

Nos tests montrent rapidement qu'on peut également utiliser le champ charset si on préfère iso-8859-1 plutôt que le défaut UTF-8 (d'où la ligne supplémentaire dans mon script).

Et ça marche !

    ? programming language
    langage de programmation
    ? the three virtues of a programmer are impatience, lazyness and hubris
    les trois vertus d'un programmeur sont des impatiences, lazyness et la prétention

Enfin, aussi bien que peut marcher la traduction automatique... ;-)

Il s'agit d'un petit script rapide, mais c'est un bon point de départ pour écrire le module plus générique (par exemple Lingua::Translate::FreeTranslation).

Mesurer son débit avec l'aide de Free

Sur la page http://tdebit.proxad.net/debit/ le fournisseur d'accès Free fournit un test de débit pour mesurer les débits montants et descendants disponibles sur votre connexion.

Une fois la page téléchargée, on voit que le script est en fait chargé dans un <iframe> :

    <iframe align=center frameborder=0 WIDTH=100% HEIGHT=300 src="index.pl">

Nous utilisons mech-dump pour aller récupérer le formulaire directement et l'analyser :

    $ mech-dump http://tdebit.proxad.net/debit/index.pl
    POST http://tdebit.proxad.net/debit/debit.pl (multipart/form-data)
      ok=submit                      (image)
      up=010000001001000...100000010 (hidden readonly)
      dureeup=6.0342                 (hidden readonly)
      sizeup=679209                  (hidden readonly)

Le contenu du champ up est énorme : 79521 caractères ! Cela fait partie de l'algorithme de calcul : ces données vont être envoyées lors du POST effectué lorsque que nous cliquerons sur le bouton « Lancer le test de débit », afin de calculer un débit à l'aide du temps mis par le script de Free pour recevoir ces données (calcul du débit montant).

Les deux champs sizeup et dureeup, contrairement à ce que semblent indiquer leurs noms sont associés au calcul de débit descendant. Ils correspondent respectivement au volume de données reçues (cachées dans des commentaires HTML) lors de la réception du formulaire et au temps qu'il a fallu au script pour les envoyer à notre client.

Construire un script qui valide le formulaire et récupère la page HTML générée prend quelques lignes :

    #!/usr/bin/perl
    use WWW::Mechanize;
    my $m = WWW::Mechanize->new( autocheck => 1 );
    $m->get('http://tdebit.proxad.net/debit/index.pl');
    $m->click('ok');
    print $m->content;

Le contenu affiché contient toutes les informations souhaitées :

    <td class='SMALL'><p><b><font color='#61718A'><b>Débit descendant
    (download)</b></font></b><br>
    Taille du fichier 604,51 ko<br>
    Durée 5.426 secondes<br>
    <b>Débit 891,25 kbit/s</b>
    (111,41 ko/s)

    <br><br><img src='blank.gif' height=15 width=213.648043847452 align=center>
    891,25 kbit/s <br><img src='echelleup.gif'><br></p><p><b><font color='#61718A'>Débit montant (upload)</font></b><br>
    Taille du fichier 75,57 ko<br>
    Durée 2.236 secondes<br>
    <b>Débit 270,4 kbit/s</b>
    (33,8 ko/s)<br>

Et il ne nous reste plus qu'à les extraire.

    my @data = $m->content() =~ m{
            Taille\ du\ fichier\ (\d+(?:,\d+)?\ ko).*?
            Durée\ (\d+(?:\.\d+)?\ secondes).*?
            Débit\ (\d+(?:,\d+)?\ kbit/s).*?
            \((\d+(?:,\d+)?\ ko/s)\)
    }gsx;

Avec cette expression régulière, nous récupérons les 8 valeurs d'un seul coup dans notre tableau. Nous devons protéger les espaces contenus dans le texte (ou les remplacer par \s) à cause de l'utilisation de l'option /x pour l'expression régulière.

Nous avons également utilisé (?:...)? pour rendre optionnels les chiffres après la virgule (ou le point).

Une dernière remarque : à cause des accents dans l'expression régulière et de l'encodage des données reçues depuis le script de Free (iso-8859-1), il faut impérativement que le script soit encodé en iso-8859-1.

Le tableau obtenu à l'aide de cette expression régulière correspond à :

    @data = (
        # débit descendant
        '604,51 ko',         # taille du fichier
        '5.426 secondes',    # durée de transfert
        '891,25 kbit/s',     # débit en kbit/s
        '111,41 ko/s',       # débit en ko/s
        # débit montant
        '75,57 ko',          # taille du fichier
        '2.236 secondes',    # durée de transfert
        '270,4 kbit/s',      # débit en kbit/s
        '33,8 ko/s'          # débit en ko/s
    );

En ajoutant une petite boucle d'affichage, on obtient le script suivant :

    #!/usr/bin/perl
    use WWW::Mechanize;
    my $m = WWW::Mechanize->new( autocheck => 1 );

    # nécessaire pour éviter que Free filtre selon les navigateurs
    $m->agent_alias( 'Linux Mozilla' );

    $m->get('http://tdebit.proxad.net/debit/index.pl');
    $m->click('ok');

    my @data = $m->content() =~ m{
            Taille\ du\ fichier\ (\d+(?:,\d+)?\ ko).*?
            Durée\ (\d+(?:\.\d+)?\ secondes).*?
            Débit\ (\d+(?:,\d+)?\ kbit/s).*?
            \((\d+(?:,\d+)?\ ko/s)\)
    }gsx;

    my $i = 0;
    for (qw( descendant montant )) {
        print "Débit $_ :\n",
              "    $data[$i+3] ($data[$i+2])\n",
              "    $data[$i] en $data[$i+1]\n";
        $i += 4;
    }

Qui affiche chez moi (Télé2 1024) :

    Débit descendant :
        111,41 ko/s (891,25 kbit/s)
        604,51 ko en 5.426 secondes
    Débit montant :
        33,8 ko/s (270,4 kbit/s)
        75,57 ko en 2.236 secondes

Merci à DomiX d'avoir demandé un coup de main sur le canal IRC des mongueurs (#perlfr sur le serveur irc.mongueurs.net) lors du débogage de son propre script.

À vous !

Envoyez vos perles à perles@mongueurs.net, elles seront peut-être publiées dans un prochain numéro de Linux Magazine.

[IE7, par Dean Edwards] [Validation du HTML] [Validation du CSS]