C#从网站获取数据

时间:2014-10-24 13:11:30

标签: c# http web-scraping screen-scraping html-agility-pack

我想从this website获取数据并将它们放入字典中。

基本上这些是某些金融工具的价格和数量。

我有这个页面的源代码(这里只是整个文本的摘录):

<tr>
   <td class="quotesMaxTime1414148558" id="notation115602071"><span>4,000.00</span></td>
   <td><span>0</span></td>
   <td class="icon red"><span id="domhandler:8.consumer:VALUE-2CCLASS.comp:PREV.gt:green.eq:ZERO.lt:red.resetLt:.resetGt:.resetEq:ZERO.mdgObj:prices-2Fquote-3FVERSION-3D2-26CODE_SELECTOR_PREVIOUS_LAST-3DLATEST-26ID_TYPE_PERFORMANCE-3D7-26ID_TYPE_PRICE-3D1-26ID_QUALITY_PRICE-3D5-26ID_NOTATION-3D115602071.attr:PERFORMANCE_PCT.wtkm:options_options_snapshot_1">-3.87%</span></td>
   <td><span id="domhandler:9.consumer:VALUE-2CCLASS.comp:PREV.gt:green.eq:ZERO.lt:red.resetLt:.resetGt:.resetEq:ZERO.mdgObj:prices-2Fquote-3FVERSION-3D2-26CODE_SELECTOR_PREVIOUS_LAST-3DLATEST-26ID_TYPE_PERFORMANCE-3D7-26ID_TYPE_PRICE-3D1-26ID_QUALITY_PRICE-3D5-26ID_NOTATION-3D115602071.attr:PRICE.wtkm:options_options_snapshot_1">960.40</span></td>       
</tr>

现在我想提供以下信息:

  1. 价值&#34; 4000&#34;来自第二行;
  2. 价值&#34; -3.87%&#34;从第四行开始;
  3. 价值&#34; 960.40&#34;从第五行开始。
  4. 我尝试使用以下内容来提取第一个信息(值4000):

            string url = "http://www.eurexchange.com/action/exchange-en/4744-19066/19068/quotesSingleViewOption.do?callPut=Put&maturityDate=201411";
    
            var webGet = new HtmlWeb();
            var document = webGet.Load(url);
    
            var firstData = from x in document.DocumentNode.Descendants()
                         where x.Name == "td" && x.Attributes.Contains("class")
                         select x.InnerText;
    

    但firstData不包含我想要的信息(值4000)但是:

    System.Linq.Enumerable+WhereSelectEnumerableIterator`2[HtmlAgilityPack.HtmlNode,System.String]
    

    我如何获取这些数据?我还需要多次重复此任务,因为在页面中有多行包含类似信息。 HTML Agility Pack在这种情况下有用吗?谢谢。

5 个答案:

答案 0 :(得分:1)

那是因为您的LINQ没有执行。如果您检查调试器中的Results View并运行查询,您将获得所有项目,第一项是您要查找的值。

所以,这会让你4,000.00

var firstData = (from x in document.DocumentNode.Descendants()
                 where x.Name == "td" && x.Attributes.Contains("class")
                 select x.InnerText).First();

如果您想要全部,请拨打ToList()而不是First()

答案 1 :(得分:1)

如果您打开使用CSQuery ..然后尝试这个。

 static void Main()
{
        CsQuery.CQ cq = CsQuery.CQ.CreateFromUrl("http://www.eurexchange.com/action/exchange-en/4744-19066/19068/quotesSingleViewOption.do?callPut=Put&maturityDate=201411");
        string str = cq["#notation115602071 span"].Text();

}

答案 2 :(得分:1)

您可以使用HtmlAgility Pack。与XmlDocument或XDocument不同,Html Agility包可以容忍格式错误的HTML(它存在于整个互联网上,可能存在于您尝试解析的网站上)。

并非所有HTML页面都可以被认为是有效的XML。

使用HTMLAgility包,您可以加载页面并使用XPath或类似于System.Xml的对象模型对其进行解析。

Html Agility Pack

或者,您可以使用PDF到文本转换器并以更高的准确度解析文本文件,因为您链接的网站提供了相同数据的PDF导出,

PDF Export Link

Convert PDF to Text

答案 3 :(得分:1)

几年前我们做了一个类似的项目蜘蛛所有主要的在线博彩网站,并创建一个比较工具,以获得每种类型的事件的最佳价格,例如。以最佳回报的顺序显示所有主要博彩公司的特定足球比赛的赔率。

原来是一个完整的噩梦 - 网站的渲染html输出几乎每天都在变化,并且经常会生成格式不佳的html,有时会使蜘蛛守护程序崩溃,因此我们必须不断维护系统以保持其正常工作

通过这些类型的东西,订阅数据源通常是经济的,这需要更少的维护和更容易的集成。

答案 4 :(得分:1)

这可能有点难看,但它很快被抛到一起,可能会被大大清理,但它会从该页面上的价格/行情表中返回您要查找的所有值。希望它有所帮助。

 var url = "http://www.eurexchange.com/action/exchange-en/4744-19066/19068/quotesSingleViewOption.do?callPut=Put&maturityDate=201411";

        var webGet = new HtmlWeb();
        var document = webGet.Load(url);


        var pricesAndQuotesDataTable =
            (from elem in
                document.DocumentNode.Descendants()
                    .Where(
                        d =>
                            d.Attributes["class"] != null && d.Attributes["class"].Value == "toggleTitle" &&
                            d.ChildNodes.Any(h => h.InnerText != null && h.InnerText == "Prices/Quotes"))
                select
                    elem.Descendants()
                        .FirstOrDefault(
                            d => d.Attributes["class"] != null && d.Attributes["class"].Value == "dataTable")).FirstOrDefault();
        if (pricesAndQuotesDataTable != null)
        {
            var dataRows = from elem in pricesAndQuotesDataTable.Descendants()
                where elem.Name == "tr" && elem.ParentNode.Name == "tbody"
                select elem;

            var dataPoints = new List<object>();
            foreach (var row in dataRows)
            {
                var dataColumns = (from col in row.ChildNodes.Where(n => n.Name == "td")
                    select col).ToList();

                dataPoints.Add(
                    new
                    {
                        StrikePrice = dataColumns[0].InnerText,
                        DifferenceToPreviousDay = dataColumns[9].InnerText,
                        LastPrice = dataColumns[10].InnerText
                    });
            }
        }

enter image description here