La bibliothèque Html Agility est cœur du fonctionnement de mon application pour récupérer et traiter le contenu des forums. Voici une série d’études de cas montrant de quelle façon cette bibliothèque s’utilise.
Présentation
Html Agility est un parser permettant de manipuler une page html. Il se présente sous la forme d’une bibliothèque .NET.
Installation de la bibliothèque
Il faut bien sur commencer par télécharger le Html Agility Pack. Cela peut se faire sur la page CodePlex de la bibliothèque. (1) Le fichier récupéré est en réalité une archive contenant différente édition de la bibliothèque. Il vous faut alors choisir l’édition qui convient à votre situation. Dans le cas du développement d’une application pour Windows Phone, j’ai utilisé l’édition située dans le dossier sl3-wp. Celle intitulée sl4-windowsphone71 a générée une erreur sous Visual Studio.
Une fois que vous avez récupérez les fichiers, vous pouvez extraire de l’archive l’édition de la bibliothèque qui vous convient. Vous pouvez alors l’utiliser dans Visual Studio en y ajoutant une référence en passant par l’éditeur de solutions de votre projet. (clique-droit sur Références, Ajouter une référence…, Parcourir)
Chargement de la page web
Avant toute manipulation avec Html Agility, il faut charger le code html de la page à parser dans un objet HtmlAgilityPack.HtmlDocument. (ici htmlPage est une chaine de caractère contenant le code de la page étudiée)
// Charge la page web dans une instance de HtmlAgility
HtmlAgilityPack.HtmlDocument document = new HtmlAgilityPack.HtmlDocument();
document.LoadHtml(htmlPage);
Il ne vous restera alors plus qu’à manipuler l’objet document.
Voir une page web comme un arbre
Voyez votre page web comme un arbre aux nombreuses branches. La première balise <html> représente le tronc de l’arbre. Celui est séparé en deux branches principales par <head> et <body>. Les balises <meta> sont comme des feuilles accrochées à la branche <head>. Comprenez que chaque couple de balises structurant la page web (<div>, <p>, <h#>, <a>, …) vient rajouter un embranchement sur leur branche mère. Html Agility permet de naviguer au sein de cet arbre en passant de nœuds en nœuds. Pour accéder à un élément particulier de la page web, il faut avancer progressivement à travers toutes les ramifications jusqu’à cet élément.
Prenons un exemple. Supposons que l’on cherche à examiner la page suivante :
<html>
<head>
<titre>Page perso</title>
</head>
<body>
<h1>Bienvenue à tous !</h1>
<p>Venez découvrir mes <a href="passion.html">passions
</a> et mes sites <a href="sites.html">préférés</a>.</p>
<p>D’autres paragraphes.</p>
<p class="footer">page perso de FooBar</p>
<a href="foo.html">Lien</a>
<p>D’autres paragraphes.</p>
</body>
</html>
Première approche
Une première façon d’accéder à un élément de la page web est d’y accéder par les balises qui encadre directement cet élément. Par exemple, le couple de balise <title> est sensé être unique sur une page web. On peut donc y faire référence et récupérer ce qu’elles encadre sans risque d’erreurs. On utilise alors :
title = document.DocumentNode.Descendants("title").First().InnerText;
On accède à l’ensemble des nœuds du documents par document.DocumentNode. La méthode Descendants() avec le paramètre “title” permet d’accéder à l’ensemble des nœuds correspondant à un couple de balise <title> (Html Agility ne sait pas que dans le cas des balises <title>, le couple est unique, situé dans l’en-tête du document html). Notez que Decendants() va chercher dans les descendants directes et indirectes du nœud de référence tous les nœuds correspondants au nom de la balise donné (notez le ‘s’ à la fin de Descendants()). Comme cette méthode peut renvoyer plusieurs résultats, on ne sélectionne que le premier à l’aide de First(). Cette méthode peut prendre des paramètres que l’on étudiera ensuite. Maintenant que le nœud correspondant exactement au couple de balises <title> est sélectionné, on extrait le texte compris entre ces balises par la propriété InnerText.
Finalement, après cette commande, la variable title contient la valeur “Page perso”.
Exercice : quelle commande utiliser pour récupérer le texte entre les balises <h1> ?
Deuxième approche
Imaginons que l’on cherche désormais à récupérer le texte contenu dans le paragraphe de class footer. On pourrait utiliser la même approche que précédemment mais il faut en plus préciser que la balise <p> recherchée possède un attribut particulier. Cela va se faire en ajoutant un paramètre à First().
title = document.DocumentNode.Descendants("p")
.First(x => x.Attributes["class"] == "footer").InnerText;
Exercice : quelle commande utiliser pour récupérer le texte entre le couple de balises <a> pointant sur la page foo.html ?
Troisième approche
Maintenant, on cherche à récupérer les url des deux liens hypertextes situés dans le premier paragraphe. Pour obtenir ces url, ils faut commencer par sélectionner les nœuds correspondant aux balises <a>. Or, elles ne possèdent pas d’attribut particulier pour les distinguer de la dernière balise <a> ; il faut donc préciser que ce sont des balises enfants d’un premier couple de balise <p>.
listeNode_a = document.DocumentNode.Descendants("p")
.First().Descendants("a");
On récupère alors cette liste de liens de la façon suivante :
var liens_brut = (from node in listeNode_a
select (string)node.Attributes["href"]);
liens = liens_brut.ToList();
Après exécution de cette commande, liens contient : [“passion.html”, “sites.html”]. (remarquez que vous pouvez rendre ce morceau de code plus compacte en remplaçant dans la deuxième partie listeNode_a par sa définition, mais l’on perd en clarté)
Voila quelque outils qui devraient vous servir si vous décidez d’utiliser Html Agility !
~xaaml
(1) : http://htmlagilitypack.codeplex.com/1