我正在尝试从表中获取值,但对如何正确执行它有点困惑。我想从以下页面检索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);
}
}
}
}
答案 0 :(得分: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);
}
如果您熟悉CSS& jQuery的方法&选择器应该有意义,除了最后一个循环中的Cq()
方法。这只是将一个元素包装为CQ
对象,因此您可以使用jQuery API。这与使用$(row)
封装DOM元素的jQuery中的操作完全相同。也就是说,当你遍历一个jQuery对象时,你得到的是实际的DOM元素,而不是更多的jQuery对象,所以如果你想对循环中的每个元素使用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
...