Pour le premier post de ce blog, je vais vous parler d’un projet que j’avais commencé, puis mis de coté il y a quelques temps.
Fréquemment soumis à diverses problématiques concernant le scraping, aussi bien pour des projets professionnels que personnels (oui je l’avoue je scrap des liens megaupload), je me suis décidé à développer un petit outil me facilitant la vie.
Mon parseur de HTML préféré étant HtmlAgilityPack, je n’avais pas d’autre choix que d’utiliser du XPATH ou du Linq.
Ayant l’habitude de faire beaucoup de développements d’applications WEB, j’étais profondément frustré de ne pas pouvoir utiliser une syntaxe de type “Css Selector” pour parcourir le DOM des pages scrapées (comme en JQuery par exemple).
J’ai donc entrepris d’ajouter à ScrapySharp qui jusqu’ici ne contenait qu’un ScrapingBrowser servant à simuler un navigateur, une extension nommée”HtmlAgilityCssQueryExtensions” permettant d’utilser un syntaxe similaire à celle utilisée en CSS ou JQuery.
Le projet est disponible ici: https://bitbucket.org/rflechner/scrapysharp
Comme le démontrent les tests unitaires, on peut matcher des éléments en utilisant la syntaxe CSS de manière relativement complète:
Tout d’abord, chargeons une ficher HTML gràce à HtmlAgilityPack:
var htmlDocument = new HtmlDocument();
htmlDocument.Load(@"Html/Page1.htm");
html = htmlDocument.DocumentNode;
Pour matcher des éléments de la page, on par exemple utiliser :
var divs = html.CssSelect("div"); //pour tous les div
var nodes = html.CssSelect("div.content"); //div de style content
var nodes = html.CssSelect("div.widget.monthlist"); // le div doit avoir les deux classes
var nodes = html.CssSelect("#postPaging"); //nodes ayant l’id postPaging
var nodes = html.CssSelect("div#postPaging.testClass"); //nodes ayant l’id postPaging et la classe testClass
var nodes = html.CssSelect("div.content > p.para"); //les p de style para étant descendants directs d’un div de style content
var nodes = html.CssSelect("input[type=text].login"); // textbox avec la classe login …
Et pourquoi pas pouvoir parcourir le DOM à l’envers ?!
Dans certains cas, on doit partir d’un élément enfant puis remonter jusqu’à un parent pour fragmenter un container par exemple.
Plus clairement, il y a des cas ou on peut partir d’un DIV par exemple, pour remonter à un TR le contenant puis construire implémenter une logique de parsing quelconque.
La résolution de ce genre de problème ce solde souvent par un code peu lisible et plus long qu’il ne le devrait.
ScrapySharp donne ainsi la possibilité de parcourir le DOM de manière inverse.
Ainsi, dans le code suivant:
var nodes = html.CssSelect("p.para").CssSelectAncestors("div.content > div.widget");
On par de l’enfant “p.para”, puis on parcours le DOM en sens inverse pour matcher le parent “div.widget” à condition que ce dernier soit le parent direct d’un “div.content”