Problème avec HTMLAgilityPack lors de l'analyse de HTML à l'aide de C #

c# html-agility-pack xpath

Question

J'essaie simplement de connaître HTMLAgilityPack et XPath. J'essaie d'obtenir une liste d'entreprises (liens HTML) sur le site Web de NASDAQ.

http://www.nasdaq.com/quotes/nasdaq-100-stocks.aspx

J'ai actuellement le code suivant;

HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();

        // Create a request for the URL.        
        WebRequest request = WebRequest.Create("http://www.nasdaq.com/quotes/nasdaq-100-stocks.aspx");
        // Get the response.
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        // Get the stream containing content returned by the server.
        Stream dataStream = response.GetResponseStream();
        // Open the stream using a StreamReader for easy access.
        StreamReader reader = new StreamReader(dataStream);
        // Read the content.
        string responseFromServer = reader.ReadToEnd();
        // Read into a HTML store read for HAP
        htmlDoc.LoadHtml(responseFromServer);

        HtmlNodeCollection tl = htmlDoc.DocumentNode.SelectNodes("//*[@id='indu_table']/tbody/tr[*]/td/b/a");
        foreach (HtmlAgilityPack.HtmlNode node in tl)
        {
            Debug.Write(node.InnerText);
        }            

        // Cleanup the streams and the response.
        reader.Close();
        dataStream.Close();
        response.Close();

J'ai utilisé un addon XPath pour Chrome pour obtenir le XPath de;

HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();

        // Create a request for the URL.        
        WebRequest request = WebRequest.Create("http://www.nasdaq.com/quotes/nasdaq-100-stocks.aspx");
        // Get the response.
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        // Get the stream containing content returned by the server.
        Stream dataStream = response.GetResponseStream();
        // Open the stream using a StreamReader for easy access.
        StreamReader reader = new StreamReader(dataStream);
        // Read the content.
        string responseFromServer = reader.ReadToEnd();
        // Read into a HTML store read for HAP
        htmlDoc.LoadHtml(responseFromServer);

        HtmlNodeCollection tl = htmlDoc.DocumentNode.SelectNodes("//*[@id='indu_table']/tbody/tr[*]/td/b/a");
        foreach (HtmlAgilityPack.HtmlNode node in tl)
        {
            Debug.Write(node.InnerText);
        }            

        // Cleanup the streams and the response.
        reader.Close();
        dataStream.Close();
        response.Close();

Lors de l'exécution de mon projet, une exception xpath non gérée m'indique qu'il s'agit d'un jeton non valide.

Je suis un peu incertain de ce qui ne va pas, j'ai essayé de mettre un numéro dans la section tr [*] ci-dessus, mais j'ai toujours la même erreur.

Je regarde ça depuis une heure, est-ce simple?

Merci

Réponse acceptée

Comme les données proviennent de javascript, vous devez analyser le javascript et non le html. Le pack Agility n'aide donc pas beaucoup, mais rend les choses un peu plus faciles. Voici comment cela pourrait être fait en utilisant Agility Pack et Newtonsoft JSON.Net pour analyser le code Javascript.

HtmlDocument htmlDoc = new HtmlDocument();
htmlDoc.Load(new WebClient().OpenRead("http://www.nasdaq.com/quotes/nasdaq-100-stocks.aspx"));
List<string> listStocks = new List<string>();
HtmlNode scriptNode = htmlDoc.DocumentNode.SelectSingleNode("//script[contains(text(),'var table_body =')]");
if (scriptNode != null)
{
  //Using Regex here to get just the array we're interested in...
  string stockArray = Regex.Match(scriptNode.InnerText, "table_body = (?<Array>\\[.+?\\]);").Groups["Array"].Value;
  JArray jArray = JArray.Parse(stockArray);
  foreach (JToken token in jArray.Children())
  {
    listStocks.Add("http://www.nasdaq.com/symbol/" + token.First.Value<string>().ToLower());
  }
}

Pour expliquer un peu plus en détail, les données proviennent d'un grand tableau javascript de la page var table_body = [... Chaque stock est un élément dans le tableau et est un tableau lui-même.

["ATVI", "Activision Blizzard, Inc", 11.75, 0.06, 0.51, 3058125, 0.06, "N", "N"]

Donc, en analysant le tableau et en prenant le premier élément et en ajoutant l'URL du correctif, nous obtenons le même résultat que le javascript.


Réponse populaire

Si vous regardez la source de la page pour cette URL, il n'y a pas réellement d'élément avec id=indu_table . Il semble avoir été généré dynamiquement (c.-à-d. En javascript); le code HTML que vous obtenez lors du chargement directement à partir du serveur ne reflétera pas les modifications apportées par le script client. C'est probablement pourquoi cela ne fonctionne pas.




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi