Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
3047 connectés 

  FORUM HardWare.fr
  Programmation
  Perl

  [Résolu] HTML::Parser, balises avec attribut

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

[Résolu] HTML::Parser, balises avec attribut

n°2084200
Gavrinis
Open your mind
Posté le 23-06-2011 à 13:50:07  profilanswer
 

Bonjour,
 
Je dois parser un fichier HTML afin de récupérer les valeurs entre <td>, mais seulement quand le td est suivi de l'attribut align="left" --> <td align="left">.
J'ai récupéré sur le web un code utilisant HTML::Parser et tenté de l'adapter mais en vain.
Il me retourne le contenu de tous les td et pas seulement ceux contenant l'attribut left.
 
Voici une partie du code :

Code :
  1. #!$(which perl) -w
  2. use HTML::Parser;
  3. sub parsing {
  4.    my $state = '';
  5.    # @personnes = ( [nom,adresse,tel,apb], [nom,adresse,tel,apb] );
  6.    my @personnes = ();
  7.    # ("nom", "adresse", "tel", "apb" )
  8.    my @personne = ();
  9.    # "nom"
  10.    my $item = '';
  11.    # Initialisation du parser.
  12.    my $p = HTML::Parser->new(api_version => 3);
  13.    # Ouverture d'une balise.
  14.    $p->handler(
  15.       start => sub {
  16.          my ($tag, $args) = shift;
  17.          $state = 'TABLE' if $tag eq 'table';
  18.          $state = 'TR' if $tag eq 'tr';
  19.          $state = 'TD' if $tag eq 'td';
  20.          if ($state eq 'TD' and defined($args->{align}) and $args->{align} eq 'left')
  21.          {
  22.             $item .= shift;
  23.          }
  24.       }, "tagname,text"
  25.    );
  26.    $p->handler(
  27.       default => sub {
  28.          $item .= shift if $state eq 'TD';
  29.       }, "text"
  30.    );
  31.    # Fermeture d'une balise.
  32.    $p->handler(
  33.       end => sub {
  34.          my $tag = shift;
  35.          $state = '' if $tag eq 'table';
  36.          if ($tag eq 'td')
  37.          {
  38.             $state = 'TR';
  39.             push @personne, $item;
  40.             $item = '';
  41.          }
  42.          if ($tag eq 'tr')
  43.          {
  44.             $state = 'TABLE';
  45.             push @personnes, [@personne];
  46.             @personne = ();
  47.          }
  48.       }, "tagname"
  49.    );
  50.    # Recupere le code HTML passe en parametre.
  51.    undef $/;
  52.    my $data = $_[0];
  53.    ## parse it (this calls each handler as necessary)
  54.    $p->parse($data);
  55.    ## now dump out the Perl structures
  56.    use Data::Dumper;
  57.    for my $row (@personnes)
  58.    {
  59.       print Dumper($row);
  60.    }
  61. }
  62. &parsing();


 
L'HTML :

Code :
  1. <table border="0">
  2. <tr>
  3. <td>
  4.  <div id="title" align="center">
  5.    <h2><b>Garde</b></h2>
  6.  </div>
  7.  <div id="info"></div>
  8.    <div id="map" style="width: 730px; height: 550px">
  9.    </div>
  10.   </td>
  11. </tr>
  12. <tr>
  13. <td align="center">
  14.   <div id="directions"></div>
  15. <table><tr><td height="1" class="LineGrey"></td></tr><tr><td align="left"><br /><span class="styleGreen">garde&nbsp;</span><br /><br /><b>Tata</b>&nbsp;(Tata)&nbsp;&nbsp;&nbsp;&nbsp;Chaussée de Tata 41&nbsp;&nbsp;&nbsp;&nbsp;1360 TxxxxxxxxS&nbsp;<br /><b>Tel. :</b> xxx/xxxxxx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>Numéro :</b> xxxxxx<br /><br /></td></tr><tr><td height="1" class="LineGrey"></td></tr><tr><td align="left"><br /><span class="styleGreen">&nbsp;garde&nbsp;</span><br /><br /><b>Tbtb (Tbtb)</b>&nbsp;(Tbtb)&nbsp;&nbsp;&nbsp;&nbsp;Rue Tbtb 43&nbsp;&nbsp;&nbsp;&nbsp;5020 Txxxxxx&nbsp;<br /><b>Tel. :</b> xxxxxxxxx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>Numéro :</b> xxxxxx<br /><br /></td></tr><tr><td height="1" class="LineGrey"></td></tr><tr><td align="left"><br /><span class="styleGreen">&nbsp;garde&nbsp;</span><br /><br /><b>Tctc</b>&nbsp;(Tctc)&nbsp;&nbsp;&nbsp;&nbsp;Rue Tctc 22&nbsp;&nbsp;&nbsp;&nbsp;1450 Cxxxxxxx&nbsp;<br /><b>Tel. :</b> xxxxxxxxx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>Numéro :</b> xxxxxx<br /><br /></td></tr><tr><td height="1" class="LineGrey"></td></tr><tr><td align="left"><br /><span class="styleGreen">&nbsp;garde&nbsp;</span><br /><br /><b>Tdtd</b>&nbsp;(Tdtd)&nbsp;&nbsp;&nbsp;&nbsp;Chaussée Tdtd 40&nbsp;&nbsp;&nbsp;&nbsp;5140 Sxxxxxxxxx&nbsp;<br /><b>Tel. :</b> xxxxxxxxx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>Numéro :</b> xxxxxx<br /><br /></td></tr><tr><td height="1" class="LineGrey"></td></tr><tr><td align="left"><br /><span class="styleGreen">&nbsp;garde&nbsp;</span><br /><br /><b>Tete</b>&nbsp;(Tete)&nbsp;&nbsp;&nbsp;&nbsp;Rue Tete 30&nbsp;&nbsp;&nbsp;&nbsp;5020 Vxxxxxxxxxxx&nbsp;<br /><b>Tel. :</b> xxxxxxxxx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>Numéro :</b> xxxxxx<br /><br /></td></tr><tr><td height="1" class="LineGrey"></td></tr><tr><td height="1" class="LineGrey"></td></tr></table><br /><br />
  16.   <script>
  17.      document.getElementById('directions').style.display = 'none'
  18.   </script>
  19. </td>
  20. </tr>
  21. </table>


 
Pouvez-vous m'aider s'il vous plait ?
Merci :jap:


Message édité par Gavrinis le 28-06-2011 à 10:22:52
mood
Publicité
Posté le 23-06-2011 à 13:50:07  profilanswer
 

n°2084314
gilou
Modérateur
Modzilla
Posté le 23-06-2011 à 16:50:06  profilanswer
 

Bon, j'ai fait des modifs et un test rapide:

Code :
  1. #!$(which perl) -w
  2. use HTML::Parser;
  3.  
  4. sub parsing {
  5.   my $state = '';
  6.   # @personnes = ( [nom,adresse,tel,apb], [nom,adresse,tel,apb] );
  7.   my @personnes = ();
  8.   # ("nom", "adresse", "tel", "apb" )
  9.   my @personne = ();
  10.   # "nom"
  11.   my $item = '';
  12.   # Initialisation du parser.
  13.   my $p = HTML::Parser->new(api_version => 3);
  14.   # Ouverture d'une balise.
  15.   $p->handler(
  16.      start => sub {
  17.         my $tag = shift;
  18.         my $args = shift;
  19.         $state = 'TABLE' if $tag eq 'table';
  20.         $state = 'TR' if $tag eq 'tr';
  21.         $state = 'TD' if $tag eq 'td';
  22.         if ($state eq 'TD' and defined($args->{align}) and $args->{align} eq 'left')
  23.         {
  24.         $state = 'TD1';
  25.         }
  26.      }, "tagname, attr"
  27.   );
  28.   $p->handler(
  29.      default => sub {
  30.         $item .= shift if $state eq 'TD1';
  31.      }, "text"
  32.   );
  33.   # Fermeture d'une balise.
  34.   $p->handler(
  35.      end => sub {
  36.         my $tag = shift;
  37.         $state = '' if $tag eq 'table';
  38.         if ($tag eq 'td')
  39.         {
  40.         if ($state eq 'TD1') {push @personne, $item;}
  41.            $state = 'TR';
  42.            $item = '';
  43.         }
  44.         if ($tag eq 'tr')
  45.         {
  46.            $state = 'TABLE';
  47.         if (@personne+0) {
  48.           push @personnes, [@personne];
  49.         }
  50.            @personne = ();
  51.         }
  52.      }, "tagname"
  53.   );
  54.   # Recupere le code HTML passe en parametre.
  55.   undef $/;
  56.   my $data = $_[0];
  57.   ## parse it (this calls each handler as necessary)
  58.   $p->parse($data);
  59.   ## now dump out the Perl structures
  60.   use Data::Dumper;
  61.   for my $row (@personnes)
  62.   {
  63.      print Dumper($row);
  64.   }
  65. }
  66. &parsing();
 

1) Si tu voulais les attributs, il fallait passer  "tagname, attr" au handler de start.
2) Faut faire un shift pour chacun de tes arguments, un (a, b) = shift ne devrait remplir que a a priori je crois.
3) Faut ajouter un cas particulier quand tu as le TD avec l'attribut voulu pour detecter ça et accumuler le texte dans le handler par défaut (ici: TD1)

 

Il y a peut être d'autres moyens de faire ça avec ce module, mais je ne le connais pas bien.

 

Bon, il te reste plus qu'à parser correctement chaque ligne de @personnes pour en extraire les champs.

 

A+,

 


Message édité par gilou le 23-06-2011 à 16:56:23

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2084380
gueuledang​e
Smokin chroniı̸̸̸̸̸̸̸̸̸̸̸̸̸̸̸̸̸̸̨̨̨̨̨̨c
Posté le 23-06-2011 à 21:43:54  profilanswer
 

Ce serait pas plus simple avec un sed, awk ou autre?

n°2084392
gilou
Modérateur
Modzilla
Posté le 23-06-2011 à 22:11:00  profilanswer
 

On voit bien que tu n'y connais rien.  
Perl est beaucoup plus puissant et pratique que sed awk et autres (le jours ou j'ai découvert Perl, il y a plus de 20 ans, j'ai pu réécrire en un seul fichier simple une usine à gaz en script, sed, awk et autres dont plein de fichiers temporaires, que je faisais pour l'INRIA).
Pour parser du texte structuré ou pas, et la, c'est ce qu'il fait, il y a pas plus pratique que Perl.
A+,

Message cité 1 fois
Message édité par gilou le 23-06-2011 à 22:15:52

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2084399
gueuledang​e
Smokin chroniı̸̸̸̸̸̸̸̸̸̸̸̸̸̸̸̸̸̸̨̨̨̨̨̨c
Posté le 23-06-2011 à 22:21:58  profilanswer
 

gilou a écrit :

On voit bien que tu n'y connais rien.  
Perl est beaucoup plus puissant et pratique que sed awk et autres (le jours ou j'ai découvert Perl, il y a plus de 20 ans, j'ai pu réécrire en un seul fichier simple une usine à gaz en script, sed, awk et autres dont plein de fichiers temporaires, que je faisais pour l'INRIA).
Pour parser du texte structuré ou pas, et la, c'est ce qu'il fait, il y a pas plus pratique que Perl.
A+,


 
Hmm pas la peine de le prendre personnellement... Je posais juste une question.
 
Et puis c'est normal qu'avec un "vrai langage" on ait plus de fonctionnalité et d'alternative qu'avec une simple commande  (ou du sh) :) Mais dans beaucoup de cas un sed suffit, pas besoin de re-coder un parser a la main.


Message édité par gueuledange le 23-06-2011 à 22:28:57
n°2084405
gilou
Modérateur
Modzilla
Posté le 23-06-2011 à 22:40:35  profilanswer
 

Ah désolé si c'était juste une question. Je pensais que c'était une remarque sur un ton ironique.
 
Mais la il ne recode pas un parser, il en utilise un tout fait (use HTML::Parser) il associe juste quelques actions certains tokens reconnus par le parser.
 
Et dans les cas ou appeler sed suffit, bien souvent, c'est plus facile a coder en perl sur une ligne et a appeler comme on ferait pour sed. :D
 
 
A+,


Message édité par gilou le 23-06-2011 à 22:44:03

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2084546
Gavrinis
Open your mind
Posté le 24-06-2011 à 12:49:12  profilanswer
 

Merci pour ton aide et tes explications Gilou, je n'en demandais pas autant, ça fonctionne parfaitement.

n°2084561
gilou
Modérateur
Modzilla
Posté le 24-06-2011 à 13:42:54  profilanswer
 

Juste un point de détail, évites d'appeler une routine perl avec &f();
f() est la manière moderne (et a moins que tu utilises un perl préhistorique, ça doit marcher), et l'appel &f(); désactive certaines fonctionnalités (la vérification des types des paramètre passés si la routine a un prototype à sa déclaration par exemple).
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
n°2084579
Gavrinis
Open your mind
Posté le 24-06-2011 à 14:09:04  profilanswer
 

Ok merci :jap:.
 
J'ai encore un soucis ... j'aimerais supprimer tous les &nbsp des éléments de mon tableau.
J'ai essayé ceci mais cela ne va pas :(.

Code :
  1. @personne = map { $_ =~ s/\&nbsp//g; $_ } @personne;

n°2084602
gilou
Modérateur
Modzilla
Posté le 24-06-2011 à 14:35:01  profilanswer
 

Chez moi, ça marche, donc ton pb est ailleurs.

Code :
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4.  
  5. my @personne;
  6. $personne[0] = '<b>Tata</b>&nbsp;(Tata)&nbsp;&nbsp;&nbsp;&nbsp;Chaussée de Tata 41&nbsp;';
  7. $personne[1] = "40&nbsp;&nbsp;&nbsp;&nbsp;5140 ";
  8.  
  9. @personne = map { s/\&nbsp;//g; $_} @personne; # pas besoin du $_ =~ ici
  10.  
  11. print $personne[0], "\n\n", $personne[1];


Fais aussi attention au fait que ta transformation va transformer 40&nbsp;&nbsp;&nbsp;&nbsp;5140 en 405140, ce qui n'est peut être pas ce que tu désires.
s/\&nbsp;(\&nbsp;)*/ /g; serait peut être plus adapté.
A+,


Message édité par gilou le 24-06-2011 à 14:39:58

---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
mood
Publicité
Posté le 24-06-2011 à 14:35:01  profilanswer
 

n°2084605
Gavrinis
Open your mind
Posté le 24-06-2011 à 14:47:42  profilanswer
 

Encore merci, c'était tout bêtement une faute de frappe.
Pas de problème pour la transformation, car je supprime les &nbsp (pas le ; qui me servira de délimiteur).


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  Perl

  [Résolu] HTML::Parser, balises avec attribut

 

Sujets relatifs
[ActiveState]Comment executer les commandes perl sous ActiveStateMacro Excel pour transformer les cellules enrichis en html
Afficher résultats base mysql -> tableau html horizontalFabriquer un email en HTML
JPGRAPH ET HTMLAide HTML/PHP/ SQL ( Urgent pour BAC:! )
Mail HTML super lent sous Outlook 2010[HTML/CSS/Javascript] Problème d'affichage avec ie
bouton play, pause, java, htmlScript, Dossier + Sous Dossier + "publication" page HTML
Plus de sujets relatifs à : [Résolu] HTML::Parser, balises avec attribut


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR