OVH Cloud OVH Cloud

Pzrser du HTMl: complètement largué!

4 réponses
Avatar
julien
Bonjour
Tout d'abord, merci à ceux qui m'ont répondu sur "vérifier et supprimer
une Regexp". Effectivement, utiliser les expressions régulières pour
cela n'est pas le mieux. De plus, mon but est d'analyser le code HTML
d'une page de façon plus globale. Je me suis donc penché sur les modules
HTML::TreeBuilder, HTML::Element, HTML::Parse et HTML::TokeParser. Mais
je ne comprends pas du tout comment les utiliser. J'ai lu les donc sur
cpan.org, mais il me faudrait plus d'exemples. Voici mes questions:

1/D'après ce que j'ai compris, j'ai le choix entre utiliser
HTML::TreeBuilder et ses "descendants" (Element et Parse), ou
TokeParser. Je ne sais pas lequel est le mieux adapter pour analyser des
pages HTML et XHTML. Lequel est le moins sensible au mauvais code, ou le
plus facile à utiliser?

2/Pour tous ces modules, les exemples que je vois sont pour chercher un
tag (balise) spécial. Sont-ils adaptés pour analyser *tous* les tags
d'une page.

3/Voici ce que j'ai compris de l'utilisation de HTML::TreeBuilder:
#1->paramétrer le parser
my $tree = HTML::TreeBuilder->new;
$tree->warn(1);
$tree->implicit_body_p_tag(1);

#2->construire l'arbre
$tree->parse($content); #content contient le code HTML téléchargé

#3->traiter l'arbre. C'est là que ça coince
$tree->tag();
my @temp=$tree->content();
print $temp[0]["_content"];
print "\n",

#4->libérer l'arbre
$tree = $tree->delete;

Pour ce programme, j'ai les warnings suivants:
* Argument "text" isn't numeric in array element
J'ai essayé $temp[0], $temp[0][0], $temp[0][_content] mais ce n'est pas bon
La doc de HTML::Element dit que chaque élément de l'arbre devrait être
de la forme:
element #1: _tag: 'html'
_parent: none
_content: [element #2, element #5]
lang: 'en-US'

* HTML::Element=HASH(0x8445348)
Cela doit correspondre à print $temp[0]["_content"] Je comprends que
$temp[0] est de type hash. Vrai?

4/Voici ce que j'ai compris de l'utilisation de HTML:TokeParser:
my $p = HTML::TokeParser->new( $content );
my @tab = $p->get_tag();

print $tab[0];

J'ai l'erreur: Can't call method "get_tag" on an undefined value
J'ai la même erreur pour my @tab = $p->get_token;


Bon, en résumé, je n'ai rien compris! Impossible de trouver plus de doc,
que ce soit sur internet ou dans des livres (je suis allé voir dans une
grande librairie). Tous les exemples montrent comment trouvé des
renseignements sur certaines balises (font, a, ...) mais bas comment
lire le code HTML élément par élément.

SI quelqu'un a des liens ou des exemples simples, cela m'aiderait beaucoup.

Merci
Julien

4 réponses

Avatar
julien
Manganneau Emmanuel wrote:
le Sat, 06 Sep 2003 13:38:41 +0000, julien a ecrit:
1/D'après ce que j'ai compris, j'ai le choix entre utiliser
HTML::TreeBuilder et ses "descendants" (Element et Parse), ou



Hum, on a pas lu la meme généalogie...
OK, ils sont en fait tous au même des niveaux, ce sont des descnednats

de HTML-Tree, c'est ça?


TokeParser. Je ne sais pas lequel est le mieux adapter pour analyser
des pages HTML et XHTML. Lequel est le moins sensible au mauvais code,
ou le plus facile à utiliser?



Pareils; ton probleme ne semble pas se situer à ce niveau.
C'était une question un peu à part, pour plus tard. Sur

http://author.handalak.com/archives/062003/000206, il est indiqué que
TokeParser est mieux adapté au code HTML erroné que TreeBuilder. JE
voulias avoir un autre avis

Je te conseille la lecture de la doc de Data::Dumper et perldoc perlref.
Tu aurais vu que pour accéder au _content du premier fils, il suffit de
faire :
my $ref_array = $p->[0]{_content}; # recupere les fils
for my $htmlElt (@{$ref_array}) { # pour tous les fils
Je débute, et je ne comprends pas bien ces 2 lignes: dans la première,

ref_array est un scalaire ($), dans la seconde, il est traité comme un
tableau (@). Comme $p->[0]{_content} contient plusieurs éléments, on ne
devrait pas écrire: my @ref_array = $p->[0]{_content}; ?

foreach my $item_r ($htmlElt->content_refs_list) {
if (ref $$item_r) { print "fils rencontrén"; next ; }
print "text du tag : ".$item_r."n";
}
}


Merci, mon programme devient donc, dans un premier essai simple:
my $tree = HTML::TreeBuilder->new; # empty tree
$tree->warn(1);
$tree->implicit_body_p_tag(1);
$tree->parse($content);

print $tree->[0]{_tag}; # affiche le tag

Mais j'ai l'erreur suivante, pour la dernière ligne: Not an Array
reference. Je ne comprends pas ce que cela signifie.

J'obtiens la même erreur en utilisant exactement le programme indiqué:
$tree->warn(1);
$tree->implicit_body_p_tag(1);
$tree->parse($content);

my $ref_array = $tree->[0]{_content}; # recupere les fils
for my $htmlElt (@{$ref_array}) { # pour tous les fils
foreach my $item_r ($htmlElt->content_refs_list) {
if (ref $$item_r) { print "fils rencontrén"; next ; }
print "text du tag : ".$item_r."n";
}
}


4/Voici ce que j'ai compris de l'utilisation de HTML:TokeParser:
my $p = HTML::TokeParser->new( $content );
my @tab = $p->get_tag();



**bip!** $p->get_tag renvoie le prochain tag ouvrant ou fermant, pas un
tableau


print $tab[0];

J'ai l'erreur: Can't call method "get_tag" on an undefined value
J'ai la même erreur pour my @tab = $p->get_token;


as tu mis use HTML::TokeParser ?
Oui, j'ai encore vérifié, et j'ai le même message d'erreur


Les docs que tu cites sont pleines de ces exemples. Tu devrais les
relire un peu mieux, mais surtout avant te familiariser avec les
references et les structures complexes de variables.
Je trouve dans la doc des exemples pour trouver une balise particulière,

mais pas pour commencer avec la première. Tous les exemples ne
contiennent que 2 balises différentes au maximum.

Encore merci
Julien


Avatar
Manganneau Emmanuel
le Sat, 06 Sep 2003 13:38:41 +0000, julien a ecrit:

[...]
d'analyser le code HTML d'une page de façon plus globale. Je me suis
donc penché sur les modules HTML::TreeBuilder, HTML::Element,
HTML::Parse et HTML::TokeParser. Mais je ne comprends pas du tout
comment les utiliser. J'ai lu les donc sur cpan.org, mais il me
faudrait plus d'exemples. Voici mes questions:

1/D'après ce que j'ai compris, j'ai le choix entre utiliser
HTML::TreeBuilder et ses "descendants" (Element et Parse), ou


Hum, on a pas lu la meme généalogie...

TokeParser. Je ne sais pas lequel est le mieux adapter pour analyser
des pages HTML et XHTML. Lequel est le moins sensible au mauvais code,
ou le plus facile à utiliser?


Pareils; ton probleme ne semble pas se situer à ce niveau.


2/Pour tous ces modules, les exemples que je vois sont pour chercher
un tag (balise) spécial. Sont-ils adaptés pour analyser *tous* les
tags d'une page.


Tu as mal lu la doc. Revoie également mon exemple avec HTML::Parser


3/Voici ce que j'ai compris de l'utilisation de HTML::TreeBuilder:
#1->paramétrer le parser
my $tree = HTML::TreeBuilder->new;
$tree->warn(1);
$tree->implicit_body_p_tag(1);

#2->construire l'arbre
$tree->parse($content); #content contient le code HTML téléchargé
ok


#3->traiter l'arbre. C'est là que ça coince
$tree->tag();
my @temp=$tree->content();
print $temp[0]["_content"];


**bip!** Comme le dit la doc, $tree contient maintenant bcp de choses :
_parent reference à l'objet parent
_tag le nom du tag
_content une ref de liste d'objets fils
'attr1'
'attr2' etc...

Je te conseille la lecture de la doc de Data::Dumper et perldoc perlref.
Tu aurais vu que pour accéder au _content du premier fils, il suffit de
faire :
my $ref_array = $p->[0]{_content}; # recupere les fils
for my $htmlElt (@{$ref_array}) { # pour tous les fils
foreach my $item_r ($htmlElt->content_refs_list) {
if (ref $$item_r) { print "fils rencontrén"; next ; }
print "text du tag : ".$item_r."n";
}
}

* HTML::Element=HASH(0x8445348)
Cela doit correspondre à print $temp[0]["_content"] Je comprends que
$temp[0] est de type hash. Vrai?


voire plus haut, perldoc perlref, et la doc de HTML::Element


4/Voici ce que j'ai compris de l'utilisation de HTML:TokeParser:
my $p = HTML::TokeParser->new( $content );
my @tab = $p->get_tag();


**bip!** $p->get_tag renvoie le prochain tag ouvrant ou fermant, pas un
tableau


print $tab[0];

J'ai l'erreur: Can't call method "get_tag" on an undefined value
J'ai la même erreur pour my @tab = $p->get_token;
as tu mis use HTML::TokeParser ?


Bon, en résumé, je n'ai rien compris! Impossible de trouver plus de
doc, que ce soit sur internet ou dans des livres (je suis allé voir
dans une grande librairie). Tous les exemples montrent comment trouvé
des renseignements sur certaines balises (font, a, ...) mais bas
comment lire le code HTML élément par élément.


Les docs que tu cites sont pleines de ces exemples. Tu devrais les
relire un peu mieux, mais surtout avant te familiariser avec les
references et les structures complexes de variables.

SI quelqu'un a des liens ou des exemples simples, cela m'aiderait
beaucoup.


#!/usr/bin/perl -w

use HTML::TreeBuilder;
use Data::Dumper;

my $p = HTML::TreeBuilder->new;
$p->parse_file("/var/www/index.html");

print Dumper $p;

$p->delete;

Merci
Avec plaisir,


--
| Manganneau Emmanuel | GestraNet SARL |
| | tel : 06 64 09 73 07 |
`--------------------------------------------------------'

Avatar
Manganneau Emmanuel
le Sat, 06 Sep 2003 16:16:19 +0000, julien a ecrit:

Manganneau Emmanuel wrote:
le Sat, 06 Sep 2003 13:38:41 +0000, julien a
ecrit:
1/D'après ce que j'ai compris, j'ai le choix entre utiliser
HTML::TreeBuilder et ses "descendants" (Element et Parse), ou
Hum, on a pas lu la meme généalogie...

OK, ils sont en fait tous au même des niveaux, ce sont des descnednats

de HTML-Tree, c'est ça?
et de HTML::Parser



Je te conseille la lecture de la doc de Data::Dumper et perldoc
perlref. Tu aurais vu que pour accéder au _content du premier fils,
il suffit de faire :
my $ref_array = $p->[0]{_content}; # recupere les fils
for my $htmlElt (@{$ref_array}) { # pour tous les fils
Je débute, et je ne comprends pas bien ces 2 lignes: dans la première,

ref_array est un scalaire ($), dans la seconde, il est traité comme un
tableau (@). Comme $p->[0]{_content} contient plusieurs éléments, on
ne devrait pas écrire: my @ref_array = $p->[0]{_content}; ?


perldoc perlref


foreach my $item_r ($htmlElt->content_refs_list) {
if (ref $$item_r) { print "fils rencontrén"; next ; }
print "text du tag : ".$item_r."n";
}
}


Merci, mon programme devient donc, dans un premier essai simple:
[...snip code...]

Mais j'ai l'erreur suivante, pour la dernière ligne: Not an Array
reference. Je ne comprends pas ce que cela signifie.


Il y avait une erreur dans mon code, c'était pour voir si tu suivais :)
Version plus mieux :

#!/usr/bin/perl -w

use HTML::TreeBuilder;
use strict;

my $tree = HTML::TreeBuilder->new;
$tree->implicit_body_p_tag(1);
$tree->parse_file("/home/manu/src/gestracompta/index.html");

my $ref_array = $tree->{_content}; # recupere les fils
for my $htmlElt (@{$ref_array}) { # pour tous les fils
print printHtmlElt($htmlElt);
}

sub printHtmlElt {
my $elt = shift;
my $ecart = shift || "";
print $ecart.$elt->{_tag}.":n";
foreach my $item ($elt->content_list) {
if (ref $item && ($item ne $elt->parent)) { # si c'est un
HTML::Element
print printHtmlElt($item,$ecart."t");
}
}
}

$tree->delete;
__END__

as tu mis use HTML::TokeParser ?
Oui, j'ai encore vérifié, et j'ai le même message d'erreur

Il peut réagir comme ca si tu as une erreur de syntaxe plus avant dans

la code (style un ; oublié)

Encore merci
Julien
Encore de rien :)


--
| Manganneau Emmanuel | GestraNet SARL |
| | tel : 06 64 09 73 07 |
`--------------------------------------------------------'



Avatar
Manganneau Emmanuel
le Sun, 07 Sep 2003 21:29:43 +0000, julien a ecrit:

Manganneau Emmanuel wrote:
Il y avait une erreur dans mon code, c'était pour voir si tu suivais
:) Version plus mieux :

Dans le programme donné, j'ai modifié quelques petites choses:

1/suppression du print devant printHtmlElt(). Je ne vois pas à quoi il
sert.


C'est une erreur de ma part : je l'ai écris trop vite. En fait il est
mieux que la fonction retourne une chaine et ne fasse pas le print elle
même.


2/ suppression de la condition ($item ne $elt->parent). Cela teste si
la référence n'est pas son propre parent? Sur du code HTML valide,
cette condition est toujours vrai. Il faudra que je teste sur du code
mauvais, mais je ne crois pas que cette condition puisse être fausse.
Pareil, un peu trop rapide de ma part.



3/ajout de if (ref $elt) { } en condition globale de l'exécution du
programme printHtmlElt. En effet, le père (HTML) contient les fils
BODY et HEAD, mais aussi du contenu texte (exemple: <html lang="fr">),
d'où l'erreur que j'évoquais.

[...snip...]


my $ref_array = $tree->{_content}; # recupere les fils de
html for my $htmlElt (@{$ref_array}) { # pour tous les fils
printHtmlElt($htmlElt); # print non nécessaire
}


J'ai mieux regardé la doc, et ils préconisent dans ce cas
d'utiliser $tree->content_list ou un truc comme ca.

Mais il y a encore plus propre :
$tree->elementify();
print printHtmlElt($tree);
$tree->delete();
__END__


J'ai juste cette fois? Cela marche sur du code HTML valide, il faudra
ensuite que je l'améliore pour traiter au mieux du code HTML erroné.
Ca marchera qd meme.


Merci pour l'aide, ça m'a bien avancé, et je n'aurais sans doute
jamais compris tout seul.
C'esst bien, ca m'a fait revoir les parsers html !


--
| Manganneau Emmanuel | GestraNet SARL |
| | tel : 06 64 09 73 07 |
`--------------------------------------------------------'