Problema con HTMLAgilityPack che analizza l'HTML utilizzando C #

c# html-agility-pack xpath

Domanda

Sto solo cercando di conoscere HTMLAgilityPack e XPath, sto tentando di ottenere un elenco di aziende (collegamenti HTML) dal sito Web NASDAQ;

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

Al momento ho il seguente codice;

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

Ho usato un addon XPath per Chrome per ottenere l'XPath di;

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

Quando eseguo il mio progetto, ottengo un'eccezione non gestita da xpath in quanto è un token non valido.

Sono un po 'insicuro di cosa c'è che non va, ho provato a mettere un numero nella sezione tr [*] sopra, ma ho ancora lo stesso errore.

L'ho guardato per l'ultima ora, è tutto semplice?

Grazie

Risposta accettata

Dal momento che i dati provengono da javascript devi analizzare il javascript e non l'html, quindi l'Agility Pack non aiuta molto, ma rende le cose un po 'più semplici. Quanto segue è come potrebbe essere fatto usando Agility Pack e Newtonsoft JSON.Net per analizzare il 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());
  }
}

Per spiegare un po 'più in dettaglio, i dati provengono da un grande array javascript sulla pagina var table_body = [... Ogni stock è un elemento dell'array ed è una matrice stessa.

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

Quindi analizzando l'array e prendendo il primo elemento e aggiungendo l'url della correzione otteniamo lo stesso risultato del javascript.


Risposta popolare

Se guardi il sorgente della pagina per id=indu_table realtà non esiste un elemento con id=indu_table . Sembra essere generato dinamicamente (cioè in javascript); l'html che si ottiene quando si carica direttamente dal server non riflette nulla che è stato modificato dallo script del client. Questo è probabilmente il motivo per cui non funziona.




Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché