0

テーブルから値を取得しようとしていますが、適切に取得する方法について少し混乱しています。次のページからStrike/Symbol / Bid / Askを取得したい:http: //finance.yahoo.com/q/op?s = MSFT& m = 2012-09

私のコードでは、さまざまなことを試しましたが、Xpathの利用方法を正しく理解していない可能性があります。

private void optionchainButton_Click(object sender, EventArgs e)
        {
            string URL = "http://finance.yahoo.com/q/op?s=" + tickerEditBox.Text;
            string HtmlFile = @".\localfile.html";

            using (WebClient client = new WebClient ()) // WebClient class inherits IDisposable
            {
                client.Proxy = null;
                //client.DownloadFile(URL, @".\localfile.html");
                HtmlWeb hw = new HtmlWeb();
                HtmlAgilityPack.HtmlDocument htmlDoc = hw.Load(URL);
                if (htmlDoc.DocumentNode != null)
                {
                    foreach (HtmlNode text in htmlDoc.DocumentNode.SelectNodes("//table/tbody/tr/td/text()"))
                    {
                        Console.WriteLine(text.InnerText);
                    }
                }

            }

        }
4

1 に答える 1

1

HtmlAgilityPackの代わりにCsQuery(nugetでは「CsQuery」として)を試してみてください。CSSセレクターとjQuery APIを使用すると、使い慣れたものになり、この種の解析を簡単に実行できます。これがCsQueryでそれを行う方法です:

string URL = "http://finance.yahoo.com/q/op?s=MSFT&m=2012-09";

CQ doc = CQ.CreateFromUrl(URL);

// The two tables have a class "yfnc_datamodoutline1", but wrap an inner table 
// too.
// This selector gets the rows of the child table where the actual data lies

var rows = doc.Select(".yfnc_datamodoutline1 table tr");

// Each th header has the class ".yfnc_tablehead1" - figure out which column 
// to use for the four parts you are interested in by finding the appropriate
// header column based on the title, and grabbing it's index

var headers = rows.First().Find(".yfnc_tablehead1");

int strikeIndex = headers.Filter(":contains('Strike')").Index();
int symbolIndex = headers.Filter(":contains('Symbol')").Index();
int bidIndex = headers.Filter(":contains('Bid')").Index();
int askIndex = headers.Filter(":contains('Ask')").Index();

// iterate over all rows, except the header one (the "has" excludes the header 
// row)

foreach (var row in rows.Has("td")) {
    CQ cells = row.Cq().Find("td");

    string output = String.Format("Strike: {0} Symbol: {1} Bid: {2} Ask: {3}",
        cells[strikeIndex].Cq().Text(),
        cells[symbolIndex].Cq().Text(),
        cells[bidIndex].Cq().Text(),
        cells[askIndex].Cq().Text());

     Console.WriteLine(output);
}

Cq()CSSとjQueryに精通している場合は、最後のループのメソッドを除いて、メソッドとセレクターが理にかなっているはずです。これは要素をオブジェクトとしてラップするだけなCQので、jQueryAPIをオブジェクトに対して使用できます。$(row)これは、DOM要素をラップするためにjQueryで行うのとまったく同じです。つまり、jQueryオブジェクトを反復処理すると、jQueryオブジェクトではなく、実際のDOM要素が取得されるため、ループ内の各要素に対してjQuery APIを使用する場合は、それらをjQueryで再度ラップする必要があります。これは、CsQueryでそれを行う方法です。jQueryの同じループは次のようにコーディングされます。

rows.Has("td").each(function(i,row) {
    var cells = $(row).find("td"); 
    ..
});

私はこのコードをテストしました、そしてそれは次のように動作して出力を返します:

Strike: 20.00 Symbol: MSFT120922C00020000 Bid: N/A Ask: N/A
Strike: 21.00 Symbol: MSFT120922C00021000 Bid: N/A Ask: N/A
Strike: 22.00 Symbol: MSFT120922C00022000 Bid: N/A Ask: N/A
Strike: 23.00 Symbol: MSFT120922C00023000 Bid: N/A Ask: N/A
Strike: 24.00 Symbol: MSFT120922C00024000 Bid: N/A Ask: N/A
Strike: 25.00 Symbol: MSFT120922C00025000 Bid: N/A Ask: N/A

..。

于 2012-08-20T12:38:06.297 に答える