使用C#從HTML表中解析單個數據元素?

c# html-agility-pack web-scraping

我在我的main函數中有這個代碼,我只想解析表格的第一行(例如2017年11月7日73.78 74.00 72.32 72.71 17,245,947)。

我創建了一個只結束第一行的節點,但是當我開始調試時,節點值為null。如何解析這些數據並將其存儲在例如字符串或單個變量中。有辦法嗎?

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

一般承認的答案

您的選擇XPath字符串似乎有錯誤。由於tbody是生成的節點,因此它不應包含在路徑中:

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

雖然這應該讀取值HtmlAgilityPack遇到另一個問題malformed html 。解析文本中的所有<tr><td>節點都沒有相應的</tr></td>結束標記,並且HtmlAgitilityPack無法從包含格式錯誤的行的表中選擇值。因此,有必要在第一步中選擇整個表:

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

在下一步中,通過添加</tr></td>關閉標籤來清理HTML並使用更正的表重複解析或使用提取的字符串手工解析它 - 只需從表字符串中提取第10行到第15行並將它們拆分>字符。原始解析如下所示。代碼經過測試和運行。

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]}");
        }
    }
}


Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow