【问题标题】:C# extract html values to list using linqC# 使用 linq 提取 html 值以列出
【发布时间】:2017-07-13 23:48:11
【问题描述】:

我绝对是 C# 的新手,尤其是 HtmlAgilityPack 和 linq,但我正在尝试组合一个 linq 语句来从特定字段中的 html 页面中检索特定值。这是我正在使用的链接声明:

List<testClass> Results = (from div in doc1.DocumentNode.Descendants("div")                                      
                                   from c in div.Descendants("class")
                                   select new testClass(
                                              c.Attributes["hdp-fact-ataglance-heading"].Value,
                                              c.Attributes["hdp-fact-ataglance-value"].Value
                                              )).ToList();

它不能正常工作,我不知道为什么,我希望它把值放到一个我可以在屏幕上读取的列表中。不幸的是,我得到一个 0 值的空白列表。 linq 在调试器中读取为正确,我得到 0 个错误。我要做的主要事情是避免出于性能目的使用任何循环。我相信我没有选择正确的节点或没有正确地将 linq 放在一起。这是 HTML 的 sn-p:

    <div class="hdp-fact-category">Bedrooms</div>
    <ul class="zsg-sm-1-1 hdp-fact-list" id="yui_3_18_1_2_1499723568429_1169">
        <li class="" id="yui_3_18_1_2_1499723568429_1168">
            <span class="hdp-fact-name">Beds: </span>
            <span class="hdp-fact-value" id="yui_3_18_1_2_1499723568429_1167">4</span>
        </li>
    </ul>
</div>
<div class="hdp-fact-container" id="yui_3_18_1_2_1499723568429_2392">
    <div class="hdp-fact-category">Heating and Cooling</div>
    <ul class="zsg-sm-1-1 hdp-fact-list" id="yui_3_18_1_2_1499723568429_2391">
        <li class="">
            <span class="hdp-fact-name">Heating: </span>
            <span class="hdp-fact-value">Forced air</span>
        </li>
        <li class="" id="yui_3_18_1_2_1499723568429_2390">
            <span class="hdp-fact-name">Cooling: </span>
            <span class="hdp-fact-value">Central</span>
        </li>
    </ul>
</div>
<div class="hdp-fact-container">
    <div class="hdp-fact-category">Basement</div>
    <ul class="zsg-sm-1-1 hdp-fact-list">
        <li class="">
            <span class="hdp-fact-value">Unfinished basement</span>
        </li>
    </ul>
</div>

我最终尝试使用通常的循环和 console.writeline(list[i]) 来获得这样的控制台输出: 床位:4

加热:强制通风

等等。我只想使用这个特定的循环来检查循环内容(它不是永久性的)

到目前为止,我正在使用它来提取我的数据.... 至少可以说这需要很长时间。这就是我尝试使用 linq 的原因,因为我认为它可能会更快?我不知道任何建议的最佳方法。

public string searchSCH(string content, string starttag, string endtag, int count)
    {
        string contentsub;
        int location1, location2;
        location1 = location2 = 0;
        if (content.Contains(starttag))
        {
            do
            {
                location1 = content.IndexOf(starttag, location1 + 1);
                if (location1 == -1)
                    return null;

                count--;
            } while (count > 0);

            location2 = content.IndexOf(endtag, location1 + 1);
            if (location2 == -1)
                return null;

            location1 += starttag.Length;
            contentsub = content.Substring(location1, location2 - location1);

            contentsub = Regex.Replace(contentsub, @"<[^>]+>|&nbsp;", string.Empty).Trim();
            contentsub = Regex.Replace(contentsub, "\".*>", string.Empty).Trim();
            contentsub = Regex.Replace(contentsub, "  ", "%");
            contentsub = Regex.Replace(contentsub, "\n", string.Empty);
            contentsub = Regex.Replace(contentsub, "\r", string.Empty);
            contentsub = Regex.Replace(contentsub, "\">", string.Empty);
            contentsub = Regex.Replace(contentsub, "\"%.*>", string.Empty);
            contentsub = Regex.Replace(contentsub, @"%+", "|");
            return contentsub;
        }
        else
        {
            return "fail";
        }

    }

【问题讨论】:

  • 您不能只说“它工作不正常”并期望我们知道如何解决它...告诉我们它是如何工作的...。您是否收到错误消息?没有预期的结果?如果没有 - 你会得到什么结果?
  • 抱歉,调试中没有错误。我在列表中没有任何值。
  • 不确定是否可以通过使用不是标记而是属性的类来过滤子项 div.Descendants("class")

标签: c# html list linq web


【解决方案1】:

将你的逻辑分解成更小的部分:

//This should give you a list of all the containers
var nodes = doc1.DocumentNode.SelectNodes("//div[contains(@class, 'hdp-fact-container')]");

//Then loop through each container to grab the category ("hdp-fact-category")
//and the facts list ("hdp-fact-list")
foreach(var item in nodes)
{
    var categoryNode = item.SelectNode("//div[contains(@class, 'hdp-fact-category']");
    var factsList = item.SelectNodes("//ul[contains(@class, 'hdp-fact-list')]/li");

    //Then do whatever with those nodes
}

我的回答是基于您也想要“类别”的假设。如果您不这样做,则只需排除该表达式。

【讨论】:

  • 您知道避免使用循环提取所需数据的方法吗?我正在处理大约 140 万个 html 文件。
  • @Wes 您最初的解决方案是使用 LINQ,您认为其中一些操作员在内部做什么?您是否尝试过我的解决方案以查看它如何处理您的数据?在解析 HTML/XML 时,您无法进行大量优化,您完全受制于文档大小。
  • 我很抱歉,我并不是要暗示 linq 没有循环。我只是想知道您是否知道一种在不涉及循环的情况下提取所需数据的方法,因为您比我知识渊博。不幸的是,我无法使上面的代码正常工作。
  • 嗯,您有多个需要处理的项目,这正是循环的设计目的。你对使用循环有什么顾虑?另外,我的代码有什么特别不工作的地方?
  • 我收到此错误 System.Xml.XPath.XPathException: ''//div[contains(@class, 'hdp-fact-list']' has an invalid token.' 我不熟悉XPath,我应该注意使用 XPath 的某些限制吗?
猜你喜欢
  • 1970-01-01
  • 2021-08-12
  • 1970-01-01
  • 2015-10-11
  • 1970-01-01
  • 1970-01-01
  • 2012-10-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多