Problema con HTMLAgilityPack analizando HTML usando C #

c# html-agility-pack xpath

Pregunta

Solo estoy tratando de aprender sobre HTMLAgilityPack y XPath, estoy tratando de obtener una lista de compañías (Enlaces HTML) del sitio web de NASDAQ;

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

Actualmente tengo el siguiente código;

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();

He usado un complemento XPath para Chrome para obtener el XPath de;

//*table[@id='indu_table']/tbody/tr[*]/td/b/a

Cuando ejecuto mi proyecto, recibo una excepción no controlada de xpath acerca de que es un token no válido.

Estoy un poco inseguro de lo que está mal, he intentado poner un número en la sección tr [*] de arriba, pero sigo recibiendo el mismo error.

He estado mirando esto durante la última hora, ¿es algo simple?

Gracias

Respuesta aceptada

Dado que los datos provienen de javascript, debe analizar el javascript y no el html, por lo que Agility Pack no ayuda mucho, pero hace las cosas un poco más fáciles. Lo siguiente es cómo se podría hacer usando Agility Pack y Newtonsoft JSON.Net para analizar el 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());
  }
}

Para explicar un poco más en detalle, los datos provienen de una gran matriz de javascript en la página var table_body = [... Cada stock es un elemento de la matriz y es una matriz en sí misma.

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

Entonces, al analizar la matriz y tomar el primer elemento y agregar la url de corrección obtenemos el mismo resultado que el javascript.


Respuesta popular

Si observa la fuente de la página para esa URL, en realidad no hay un elemento con id=indu_table . Parece que se genera dinámicamente (es decir, en javascript); el html que obtiene al cargar directamente desde el servidor no reflejará nada que haya cambiado el script del cliente. Probablemente es por eso que no funciona.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué