Article publié dans Linux Magazine 80, février 2006.
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.
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.
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
).
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.
Envoyez vos perles à perles@mongueurs.net
, elles seront peut-être
publiées dans un prochain numéro de Linux Magazine.
Copyright © Les Mongueurs de Perl, 2001-2011
pour le site.
Les auteurs conservent le copyright de leurs articles.