Tag Archives: linq

Extract data from HTML page with XPath and Linq

As developer, we usually need to extract data from a html web page in our projects, but most of the time we try to find another solution due to the complexity of the task. Indeed, the classical approach would be to use regex or similar and try to find out our informations in the page structure. But there’s something really helpfull, the HTMLAgilityPack. I’ll give you 2 example, the first one for a basic overview of the HTMLAgilityPack and a second one with much more details about the process I follow for that kind of tasks.

So, HTMLAgilityPack allow us to download a webpage and then consult the content with his methods or with the provided XPath API. To install it, just download the NuGet package from VS2010 >= or grab the project from the codeplex page.

Once done, you can use it to parse and extract data from html page.

using HtmlAgilityPack;

Then you can use it to download the page :

string url = "http://www.simpleweb.org/";
HtmlWeb web = new HtmlWeb();
HtmlDocument doc = web.Load(url);

Or you can use LoadHtml(string htmlCode) on the HtmlDocument object to work on raw html code contained in memory.

Once done, you can write XPath query to retreive data. For this example, I want to retreive the url of the wiki (second link in the left menu).
According to the google chrome debugger, the quicker and optimzed XPath to this property is : (thank you chrome :p)

//*[@id="top_option"]/div[2]/span/a

For those not familiar with XPath, it’s really simple. This query just mean, from the root (//) all tags (*) with id attribute set to “top option” ([@id=”top_option”]) then select the second div (div[2]) then select span and within the span select link (/span/a). That give us the following Linq query :

var result = from link in htmlDoc.DocumentNode.SelectNodes("//*[@id='top_option']/div[2]/span/a")
                         select link.Attributes["href"].Value;

The intellisense will be once again your best friends as this assembly is really well designed and intuitive. So here I select all the nodes who match the XPath query and then select the href attribute value.

Let’s take another example, I want to get an object tree which represent the whole menu. Just before that, I would like to mention something about XPath. This is a great query language… if you know it ! I mean, you can write really powerful but complex query using it, and I always think about the next one who’ll need to understand and/or update the query. So I usually prefer if I have to share it or in a collaborative context to write multiple steps/subqueries to make it more “developer friendly”. Even some simple query can seems really complex for someone not familiar with it. That said, let’s write the query to rebuild the full menu tree of the same page. This time I’ll also share the steps I follow for that kind of task.

First, analyze the page structure. We can see that the menu is contained within a td (/html/body/table/tbody/tr[3]/td/table/tbody/tr/td[1]). This td contain 7 div, but only the 3 first one interest us. To know that, I use the Chrome debugger, when you place your move hover a tag, Chrome will highlight in the page the corresponding area.

<div style="float:left;" id="top_option" class="aTopLink">
	<div>
		<span><a class="aTopLink" href="/">Home</a></span>
	</div>
	<div>
		<span><a class="aTopLink" href="/wiki/">Wiki</a></span>
	</div>
</div>
<div style="float:left;" id="my_menu" class="sdmenu">
    <div class="collapsed">
        <span>MIBs</span>
		<a href="/ietf/mibs/">Browser</a>
                <a href="/ietf/mibs/validate/">MIB Validation</a>
                <a href="/ietf/mibs/byEncoding?encoding=txt">Plain text</a>
                <a href="/ietf/mibs/byEncoding?encoding=highlighting">Syntax Highlighting</a>
                <a href="/ietf/mibs/byEncoding?encoding=html">HTML encoding</a>
		<a href="/ietf/enterprise/">Vendor MIBs</a>
		<a href="/ietf/mibs/search/">Search</a>
            </div>
	    <div class="collapsed">
		<span>RFCs</span>
		<a href="/ietf/rfcs/rfcbynumber.php" class="current">By Number</a>
		<a href="/ietf/rfcs/rfcbytopic.php">By Topic</a>
		<a href="/ietf/rfcs/rfcbystatus.php">By Status</a>
		<a href="/ietf/rfcs/rfcbymodule.php">By Module</a>
                <a href="/ietf/rfcs/complete/">Complete</a>
		<a href="/ietf/rfcs/">Search</a>
	    </div>
            <div class="collapsed">
                <span>Software</span>
                <a href="/software/select_obj.php?orderBy=package&amp;oldorderBy=package&amp;orderDir=asc&amp;free=free">Freely available</a>
                <a href="/software/select_obj.php?orderBy=package&amp;oldorderBy=package&amp;orderDir=asc&amp;com=com">Commercial</a>
                <a href="/software/">Search</a>
            </div>
            <div class="collapsed">
                <span>CFP/Conferences</span>
                <a href="/wiki/Events">Conferences</a>
                <a href="/wiki/Cfp">Call for Papers</a>
            </div>
            <div class="collapsed">
                <span>Bibliography</span>
                <a href="/wiki/Books">Books</a>
                <a href="/wiki/Journals">Journals</a>
                <a href="/wiki/Theses">Theses</a>
            </div>
            <div class="collapsed">
                <span>Tutorials</span>
                <a href="/wiki/Internet_Management_Tutorials">Slides</a>
                <a href="/wiki/Video_tutorials_on_Internet_management">Podcasts</a>
                <a href="/wiki/Exercises_in_Internet_Management">Exercises</a>
                <a href="/wiki/Other_tutorials">Other tutorials</a>
		<a href="/tutorials/demo/snmp/v1/">SNMPv1 demo</a>
		<a href="/tutorials/demo/snmp/v2c/">SNMPv2c demo</a>
		<a href="/tutorials/demo/snmp/v3/">SNMPv3 demo</a>
    </div>
</div>
<div style="float:left;" id="bottom_option" class="aTopLink">
    <div>
        <span><a class="aTopLink" href="/wiki/Podcasts">Podcasts</a></span>
    </div>
    <div>
        <span><a class="aTopLink" href="http://www.simpleweb.org/wiki/Traces">Traffic Traces</a></span>
    </div>
    <div>
        <span><a class="aTopLink" href="/ifip/">IFIP WG6.6</a></span>
    </div>
    <div>
        <span><a class="aTopLink" href="mailto:simpleweb@simpleweb.org">Contact</a></span>
    </div>
</div>

To represent it we will have the following object model in C# :

public class Node
{
    public List<Node> Childs { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }
}

And the query will be the following :

var result = (from topNode in htmlDoc.DocumentNode.SelectNodes("//div[@id='top_option']/div/span/a")
                select new Node()
                            {
                                Name = topNode.InnerText,
                                Url = topNode.Attributes["href"].Value
                            })
                            .Union(
                from bottomNode in htmlDoc.DocumentNode.SelectNodes("//div[@id='bottom_option']/div/span/a")
                select new Node()
                        {
                            Name = bottomNode.InnerText,
                            Url = bottomNode.Attributes["href"].Value
                        })
                        .Union(
            from groupNode in htmlDoc.DocumentNode.SelectNodes("//*[@id='my_menu']/div[*]")
            let groupChilds = (from nodes in groupNode.SelectNodes("a")
                                select new Node()
                                            {
                                                Name = nodes.InnerText,
                                                Url = nodes.Attributes["href"].Value
                                            })
            select new Node()
                        {
                            Name = groupNode.SelectSingleNode("span").InnerText,
                            Childs = groupChilds.ToList()
                        });
                                    
DisplayMenu(result.ToList());

We use 3 query with union. As said, I tried to decompose a bit the query, the two first are the same, select the links and create nodes with the innerText of the a tag and the href attribute. Then we have the centre of the menu with hierarchy. For this, we select each div representing a group, then we create a first list of node like for the two first request based on the link contained within the div, and we create the node object with the list we’ve just created as child’s object list and the span content as Name.

As you can see, we can easily write complex requests in no time (this one took me about 30minutes to write, test and include in this article). HTMLAgilityPack is a great tool that allow us to use XPath and finally address a great answer to the critical html data parsing issue !

See you next time and keep it bug free ! 🙂

Twitter, OAuth & LinqToTwitter for dummies

Un petit post qui explique basiquement comment fonctionne l’authentification d’une application twitter.

Le souci très vite rencontré c’est OAuth. Tout comme OData et tous les Oxxx, la documentation est hyper fournie, voir trop fournie… ce qui fait que l’on perd vite pied dans des détails techniques. Ce que je propose ici ce n’est pas de savoir comment fonctionne OAuth et twitter mais de savoir pratiquement comment authentifier son appli.

Tout d’abord un tout petit peu de théorie sur ce que l’on va faire. On partira de l’application que je développe actuellement, TwittLook, intégrant Twitter à OutLook 2010.

On a deux scénarios, « first connection » et « daily connection ».

First Connection

– L’application TwittLook possède deux clefs sur le principe de clefs privĂ©/publique. Ce qui est cool, c’est que Ă  part le fait que l’on devra garder la seconde « secrète », la seul chose que l’on fera avec, c’est les renseigner dans deux propriĂ©tĂ©s, LinqToTwitter s’occupe du reste (sans jeux de mots ^^).

– Ensuite notre application renverra l’utilisateur vers twitter directement afin qu’il valide l’accès de notre application Ă  son compte.

– Si l’utilisateur accepte, il recevra un code PIN que l’on utilisera pour gĂ©nĂ©rer deux nouvelles clefs. Ces deux clefs seront stockĂ©es et nous permettrons les fois suivante de directement se connecter au compte de l’utilisateur.

Daily Connection

– Idem que le point 1 de First Connection

– On renseigne les tokens obtenue au point 3 de First Connection

– Enjoy 🙂

Et c’est tout… Sur ces deux scénarios sont résumé tout ce qu’il est nécessaire de connaitre pour developper une appli twitter ! Plus leger que les 120pages de RFC OAuth n’est-ce pas ?

Maintenant, comment fait-on concrètement ?

Premièrement, si ce n’est déjà fait, rendez-vous sur la partie développeur de twitter et enregistrez votre application. C’est gratuit et sans validation, le seul requirement c’est un compte valide. Cette authentification nous permettra d’obtenir les deux clefs. La première peut être public, la seconde doit rester privée (et donc protégée).

Les deux clefs dans le notepad, direction l’onglet settings dans la section « Application Type ». Nous allons là définir les droits d’accès de notre application. Libre à vous de prendre l’option qui vous convient selon vos besoins, la suite ne changera pas, mais de base les applications sont en Read-Only.

Les keys obtenue, nous allons créer un objet de type PinAuthorizer. Dans cet objet nous allons définir notre ConsumerKey, ConsumerSecret, Action à utiliser lorsque l’on se rend sur la page d’autorisation et une fonction à exécuter pour récupérer le code PIN. Dans mon cas j’ai stocké les key dans un fichier settings. Voici donc le code pour initialiser notre objet :

var auth = new PinAuthorizer
{
    Credentials = new InMemoryCredentials
    {
        ConsumerKey = keys.Default.ConsumerKey,
        ConsumerSecret = keys.Default.ConsumerSecret
    },
    UseCompression = true,
    GoToTwitterAuthorization = pageLink => Process.Start(pageLink),
    GetPin = () =>
    {
        Console.WriteLine("Enter the PIN Number : \n"); 
        return Console.ReadLine();
    }
};

Ensuite, si les tokens n’existent pas, cela signifie que l’application n’est pas authentifiée, nous appelons la méthode Authorize(). Ceci exécutera la méthode GoToTwitterAuthorization suivi de GetPin(). Ensuite dans notre code il nous suffit de récupéré dans la propriété Credentials les deux tokens (OAuthToken et AccessToken) que nous stockerons. Ainsi les fois suivante l’appel d’Authorize ne sera plus nécessaire. Et c’est tout ^^

Voici le code complet :

var auth = new PinAuthorizer
{
    Credentials = new InMemoryCredentials
    {
        ConsumerKey = keys.Default.ConsumerKey,
        ConsumerSecret = keys.Default.ConsumerSecret
    },
    UseCompression = true,
    GoToTwitterAuthorization = pageLink => Process.Start(pageLink),
    GetPin = () =>
    {
        Console.WriteLine("Enter the PIN Number : \n"); 
        return Console.ReadLine();
    }
};

if (keys.Default.OAuthToken.Trim() != "" && keys.Default.AccessToken.Trim() != "")
{
    auth.Credentials = new InMemoryCredentials
    {
        ConsumerKey = keys.Default.ConsumerKey,
        ConsumerSecret = keys.Default.ConsumerSecret,
        OAuthToken =  keys.Default.OAuthToken,
        AccessToken = keys.Default.AccessToken
    };
}
else
{
    auth.Authorize();
    keys.Default.OAuthToken = auth.Credentials.OAuthToken;
    keys.Default.AccessToken = auth.Credentials.AccessToken;
    keys.Default.Save();
}

if (auth.IsAuthorized)
{
    using (var twitterCtx = new TwitterContext(auth, "https://api.twitter.com/1/", "https://search.twitter.com/"))
    {
        //Log
        twitterCtx.Log = Console.Out;
        var message = twitterCtx.NewDirectMessage("TchoyTchoy", "Direct Message Test - " + DateTime.Now);
    }
}

L’API OAuth va beaucoup plus loin, notamment sur des scénarios très complexe, mais la plupart du temps, ceci devrais suffire ^^

Linq : DiffĂ©rence de performance entre la syntaxe Linq et la syntaxe de Method

Salut a tous, aujourd’hui un article sur la différence de performance entre deux syntaxe pour écrire des requêtes Linq avec a la fin un spécial winner ^^

Alors, tout d’abord, voici ce qu’est une syntaxe linq :

var x = from t in test
             where t != 0
             select t;

Et voici une syntaxe de méthode :

var x = test.Where(i =&gt; i != 0)
                 .Select(i =&gt; i);

Pour ma part, du fait que la syntaxe Linq faisait appel a une interprétation a la compilation j’ai toujours pensé qu’elle était plus lente que la syntaxe en méthode. Mais nous allons voir que finalement, pas du tout.

Voici les deux méthodes que nous allons comparer :

        static void MethodSyntax()
        {
            List test = new List();
            test.Add(0);
            var x = test.Where(i =&gt; i != 0).Select(i =&gt; i);
        }

        static void LinqSyntax()
        {
            List test = new List();
            test.Add(0);
            var x = from t in test
                    where t != 0
                    select t;
        }

Et voici le Code IL généré :

Première Method :

.method private hidebysig static void  MethodSyntax() cil managed
{
  // Code size       90 (0x5a)
  .maxstack  4
  .locals init ([0] class [mscorlib]System.Collections.Generic.List`1 test,
           [1] class [mscorlib]System.Collections.Generic.IEnumerable`1 x)
  IL_0000:  nop
  IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4.0
  IL_0009:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0)
  IL_000e:  nop
  IL_000f:  ldloc.0
  IL_0010:  ldsfld     class [mscorlib]System.Func`2 Linq.Program::'CS$&lt;&gt;9__CachedAnonymousMethodDelegate2'
  IL_0015:  brtrue.s   IL_002a
  IL_0017:  ldnull
  IL_0018:  ldftn      bool Linq.Program::'b__0'(int32)
  IL_001e:  newobj     instance void class [mscorlib]System.Func`2::.ctor(object,
                                                                                      native int)
  IL_0023:  stsfld     class [mscorlib]System.Func`2 Linq.Program::'CS$&lt;&gt;9__CachedAnonymousMethodDelegate2'
  IL_0028:  br.s       IL_002a
  IL_002a:  ldsfld     class [mscorlib]System.Func`2 Linq.Program::'CS$&lt;&gt;9__CachedAnonymousMethodDelegate2'
  IL_002f:  call       class [mscorlib]System.Collections.Generic.IEnumerable`1 [System.Core]System.Linq.Enumerable::Where(class [mscorlib]System.Collections.Generic.IEnumerable`1,
                                                                                                                                       class [mscorlib]System.Func`2)
  IL_0034:  ldsfld     class [mscorlib]System.Func`2 Linq.Program::'CS$&lt;&gt;9__CachedAnonymousMethodDelegate3'
  IL_0039:  brtrue.s   IL_004e
  IL_003b:  ldnull
  IL_003c:  ldftn      int32 Linq.Program::'b__1'(int32)
  IL_0042:  newobj     instance void class [mscorlib]System.Func`2::.ctor(object,
                                                                                       native int)
  IL_0047:  stsfld     class [mscorlib]System.Func`2 Linq.Program::'CS$&lt;&gt;9__CachedAnonymousMethodDelegate3'
  IL_004c:  br.s       IL_004e
  IL_004e:  ldsfld     class [mscorlib]System.Func`2 Linq.Program::'CS$&lt;&gt;9__CachedAnonymousMethodDelegate3'
  IL_0053:  call       class [mscorlib]System.Collections.Generic.IEnumerable`1 [System.Core]System.Linq.Enumerable::Select(class [mscorlib]System.Collections.Generic.IEnumerable`1,
                                                                                                                                              class [mscorlib]System.Func`2)
  IL_0058:  stloc.1
  IL_0059:  ret
} // end of method Program::MethodSyntax

Avec Linq :

.method private hidebysig static void  LinqSyntax() cil managed
{
  // Code size       54 (0x36)
  .maxstack  4
  .locals init ([0] class [mscorlib]System.Collections.Generic.List`1 test,
           [1] class [mscorlib]System.Collections.Generic.IEnumerable`1 x)
  IL_0000:  nop
  IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4.0
  IL_0009:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1::Add(!0)
  IL_000e:  nop
  IL_000f:  ldloc.0
  IL_0010:  ldsfld     class [mscorlib]System.Func`2 Linq.Program::'CS$&lt;&gt;9__CachedAnonymousMethodDelegate5'
  IL_0015:  brtrue.s   IL_002a
  IL_0017:  ldnull
  IL_0018:  ldftn      bool Linq.Program::'b__4'(int32)
  IL_001e:  newobj     instance void class [mscorlib]System.Func`2::.ctor(object,
                                                                                      native int)
  IL_0023:  stsfld     class [mscorlib]System.Func`2 Linq.Program::'CS$&lt;&gt;9__CachedAnonymousMethodDelegate5'
  IL_0028:  br.s       IL_002a
  IL_002a:  ldsfld     class [mscorlib]System.Func`2 Linq.Program::'CS$&lt;&gt;9__CachedAnonymousMethodDelegate5'
  IL_002f:  call       class [mscorlib]System.Collections.Generic.IEnumerable`1 [System.Core]System.Linq.Enumerable::Where(class [mscorlib]System.Collections.Generic.IEnumerable`1,
                                                                                                                                       class [mscorlib]System.Func`2)
  IL_0034:  stloc.1
  IL_0035:  ret
} // end of method Program::LinqSyntax

A ma plus grand surprise on peut voir que le code IL est plus lourd sur les méthode que sur la syntaxe.  En effet, si l’on observe le code on voit que Linq appel un delegate alors que Method en appel deux. Si l’on s’y penche d’un peu plus près on voit que le delegate appelé par Linq et le premier appelé par Methode est le même bien qu’étant stocké deux fois sous des noms différent.

Que font ces delegate :

.method private hidebysig static bool  'b__4'(int32 t) cil managed
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
  .maxstack  2
  .locals init ([0] bool CS$1$0000)
  IL_0000:  ldarg.0                     // Load l'arguments 0
  IL_0001:  ldc.i4.0			// Met 0 sur la stack
  IL_0002:  ceq				// Equivalent a un if equal
  IL_0004:  ldc.i4.0			// Met 0 sur la stack
  IL_0005:  ceq				// Equivalent a un if equal
  IL_0007:  stloc.0			// Pop le premier élément stack de la stack et la store dans local 0
  IL_0008:  br.s       IL_000a		// se branche sur l'instruction 000a
  IL_000a:  ldloc.0			// Charge sur l'evaluation stack la variable a l'index 0
  IL_000b:  ret				// retour
}

.method private hidebysig static int32  'b__1'(int32 i) cil managed
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( 01 00 00 00 )
  // Code size       6 (0x6)
  .maxstack  1
  .locals init ([0] int32 CS$1$0000)
  IL_0000:  ldarg.0			// Charge l'argument 0
  IL_0001:  stloc.0			// Pop le premier élément stack de la stack et la store dans local 0
  IL_0002:  br.s       IL_0004		// se branche sur l'instruction 0004
  IL_0004:  ldloc.0			// Charge sur l'evaluation stack la variable a l'index 0
  IL_0005:  ret				// Charge
}

On comprend donc facilement qu’il s’agit pour le premier du where.

Et en fait, dans le code MSIL des deux méthodes, tout ce qui est dans la version Linq se trouve dans la version Method. Method exécute juste plus de code, c’est-à-dire de IL_0034 a IL 0053 dans lequel le delegate spécifique a Method est appelé.

Regardons au final les perfs. Sur un tableau de 1 000 000 000 (un milliard) d’integer ou on veut selectionner tous les int diffĂ©rents de 0. L’indice est exprimĂ© en clock thick et se base sur 100 expĂ©riences par mĂ©thode dans lesquels on a exclus le premier et dernier dĂ©cile (c’est a dire les extrĂŞmes, considĂ©rĂ©e comme anomalies). Si vous voulez les nombres obtenus complets les voici : http://pastebin.com/TVy7F4Xq

(Effectué sur un portable monocore 2.8Ghz avec 4Go de ram)

Temp moyen avec Linq en thicks Temp moyen avec Method en thicks
9 214 21 506

On voit donc que, en moyenne, le code généré par une requête en syntaxe Linq sera 2,33 fois plus rapide que le code généré par une syntaxe Method.

Vous pouvez donc meller code lisible et perfs sans trop de soucis a présent ^^
Inform@tiquement
Manu404