3

HTMLAgilityPack と XPath について学習しようとしています。NASDAQ Web サイトから (HTML リンク) 企業のリストを取得しようとしています。

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

現在、次のコードがあります。

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

Chrome 用の XPath アドオンを使用して XPath を取得しました。

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

プロジェクトを実行すると、無効なトークンであるという xpath 未処理の例外が発生します。

何が問題なのか少しわかりません。上記の tr[*] セクションに数値を入力しようとしましたが、それでも同じエラーが発生します。

私はこれを過去1時間見てきましたが、何か簡単ですか?

ありがとう

4

3 に答える 3

3

データはjavascriptから取得されるため、htmlではなくjavascriptを解析する必要があります。そのため、Agility Packはそれほど役に立ちませんが、少し簡単になります。以下は、AgilityPackとNewtonsoftJSON.Netを使用して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());
  }
}

もう少し詳しく説明すると、データはページ上の1つの大きなJavaScript配列から取得されますvar table_body = [...。各ストックは配列内の1つの要素であり、配列自体です。

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

したがって、配列を解析して最初の要素を取得し、修正URLを追加することで、javascriptと同じ結果が得られます。

于 2012-06-13T17:53:47.663 に答える
0

どうしてDescendants("a")メソッドだけを使わないのですか?それははるかに単純で、よりオブジェクト指向です。たくさんのオブジェクトを取得できます。これらのオブジェクトから「href」属性を取得できます。

サンプルコード:

htmlDoc.DocumentNode.Descendants("a").Attributes["href"].Value

特定のWebページからのリンクのリストが必要な場合は、この方法で問題ありません。

于 2012-06-13T15:11:21.000 に答える
0

その URL のページ ソースを見ると、実際にはid=indu_table. 動的に生成されているように見えます(つまり、JavaScriptで)。サーバーから直接ロードするときに取得する html には、クライアント スクリプトによって変更された内容は反映されません。これがおそらく機能しない理由です。

于 2012-06-13T15:24:56.357 に答える