【问题标题】:Parse single data elements from HTML tables with C#?用 C# 解析 HTML 表中的单个数据元素?
【发布时间】:2017-11-09 00:10:55
【问题描述】:

我的 main 函数中有这段代码,我只想解析表的第一行(例如 Nov 7, 2017 73.78 74.00 72.32 72.71 17,245,947)。

我创建了一个仅结束第一行的节点,但是当我开始调试时,节点值为空。如何解析这些数据并将它们存储在例如字符串或单个变量中。有办法吗?

WebClient web = new WebClient();

        string page = web.DownloadString("https://finance.google.com/finance/historical?q=NYSE:C&ei=7O4nV9GdJcHomAG02L_wCw");

        HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
        doc.LoadHtml(page);

        var node = doc.DocumentNode.SelectSingleNode("//*[@id=\"prices\"]/table/tbody/tr[2]");

  List<List<string>> node = doc.DocumentNode.SelectSingleNode("//*[@id=\"prices\"]/table").Descendants("tr").Skip(1).Where(tr => tr.Elements("td").Count() > 1).Select(tr => tr.Elements("td").Select(td=>td.InnerText.Trim()).ToList()).ToList() ;

【问题讨论】:

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


    【解决方案1】:

    您的选择 XPath 字符串似乎有错误。由于tbody 是生成的节点,因此不应将其包含在路径中:

    //*[@id=\"prices\"]/table/tr[2]
    

    虽然这应该读取值 HtmlAgilityPack 遇到另一个问题malformed html。解析文本中的所有&lt;tr&gt;&lt;td&gt; 节点都没有对应的&lt;/tr&gt;&lt;/td&gt; 结束标记,并且HtmlAgitilityPack 无法从具有错误行的表中选择值。因此,有必要在第一步中选择整个表:

    //*[@id=\"prices\"]/table
    

    在下一步中,要么通过添加 &lt;/tr&gt;&lt;/td&gt; 结束标记来清理 HTML,并使用更正的表格重复解析,或者使用提取的字符串手动解析它 - 只需从表格字符串中提取第 10 到 15 行并将它们拆分&gt; 字符。原始解析如下所示。代码已经过测试并且可以运行。

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    
    namespace GoogleFinanceDataScraper
    {
        class Program
        {
            static void Main(string[] args)
            {
                WebClient web = new WebClient();
    
                string page = web.DownloadString("https://finance.google.com/finance/historical?q=NYSE:C&ei=7O4nV9GdJcHomAG02L_wCw");
    
                HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
                doc.LoadHtml(page);
    
                var node = doc.DocumentNode.SelectSingleNode("//div[@id='prices']/table");
    
                string outerHtml = node.OuterHtml;
                List<String> data = new List<string>();
                using(StringReader reader = new StringReader(outerHtml))
                {
                    for(int i = 0; ; i++)
                    {
                        var line = reader.ReadLine();
                        if (i < 9) continue;
                        else if (i < 15)
                        {
                            var dataRawArray = line.Split(new char[] { '>' });
                            var value = dataRawArray[1];
                            data.Add(value);
                        }
                        else break;
                    }
                }
    
                Console.WriteLine($"{data[0]}, {data[1]}, {data[2]}, {data[3]}, {data[4]}, {data[5]}");
            }
        }
    }
    

    【讨论】:

    • 我发现这篇文章link 并尝试按照您的建议实施;它没有用。 PS我在我的代码中发布了它。节点仍然为空
    • 我也实现了它,就我而言,一切都按预期工作。将整个代码粘贴到答案中
    • 伙计,我不知道该怎么感谢你!终于完美运行了!!!你知道任何关于使用 c# 和,或 html 敏捷性进行网页报废的材料吗??
    • 并非如此。使用 python 等脚本语言进行抓取有很多内容。
    • 顺便说一句,如果您发现我的答案正确,您可以将其标记为您的问题的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-27
    • 1970-01-01
    • 2018-05-01
    • 2017-04-14
    • 1970-01-01
    • 2020-12-17
    相关资源
    最近更新 更多