使用HTMLAgilityPack按分隔线解析HTML

时间:2013-10-31 15:30:29

标签: c# parsing html-agility-pack

我正在尝试解析一个特定的HTML字符串,以便我可以提取一组由<br/>分隔线分隔的行。输入HTML如下所示:

<div class="PlainText">
  DATE: 2013-10-28 20:00:43 -0500 <br/>
  Item 1: Text1 <br/>
  Item 1: Text1 <br/>
  Item 1: Text1 <br/>
  Item 1: Text1 <br/>
  <br/> //Notice this has two break lines, i would like to stop after seeing two consecutive break lines.
</div>

在更大的html文档中使用此div,我能够获得HTML ChildNodes

List<HtmlNode> nodes = htmlDoc.DocumentNode
                                    .Descendants("div")
                                    .Where(x => x.Attributes.Contains("class") &&
                                            x.Attributes["class"].Value.Contains("PlainText")).ToList();

我不完全确定从哪里开始,我想阅读所有文字,直到我看到两个分隔线并停止?

修改

我在Visual Studio运行时检查器中查看了childNodes nodes并注意到实际上没有两条连续的<br/>行,而是一条断行和一个#text标记,其innerHTMl为\n一个换行符。

enter image description here

2 个答案:

答案 0 :(得分:1)

您可以使用XPath //div[@class='PlainText']来获取所需的div节点。您还可以在从div获取子节点时检查下一个兄弟节点:

HtmlDocument doc = new HtmlDocument();
doc.Load("index.html");
Func<HtmlNode, bool> notTwoBrakes = 
    n => (n.Name != "br" || n.NextSibling != null && n.NextSibling.Name != "br");
var nodes = doc.DocumentNode.SelectNodes("//div[@class='PlainText']")
               .Select(div => div.ChildNodes.TakeWhile(notTwoBrakes));

为了便于阅读,我不使用内联lambda。条件是这样的:

  • 检查下一个节点是否为空,如果为空,则采用当前节点
  • 检查下一个节点是br节点,如果不是 - 采用当前节点
  • 检查当前节点是否为br节点,如果不是 - 采用当前节点
  • 否则停止接收子节点

结果:

enter image description here

答案 1 :(得分:0)

这样的事情应该有效

[Test]
public void Test()
{
    var x = ReadTillTwoBr(GetDivClass()).ToList();
}

public HtmlNode GetDivClass()
{
    var html = @"<html><div class=""PlainText"">
            DATE: 2013-10-28 20:00:43 -0500 <br/>
            Item 1: Text1 <br/>
            Item 1: Text1 <br/>
            Item 1: Text1 <br/>
            Item 1: Text1 <br/>
            <br   /> //Notice this has two break lines, i would like to stop after seeing two consecutive break lines.
            Item 3
        </div></html>";
    var doc = new HtmlDocument();
    doc.LoadHtml(html);

    return doc.DocumentNode
                .Descendants("div").First(x => x.Attributes.Contains("class") &&
                                                x.Attributes["class"].Value.Contains("PlainText"));

}

public IEnumerable<string> ReadTillTwoBr(HtmlNode node)
{
    var nonEmptyNodes =
        node.ChildNodes.Except(node.ChildNodes.Where(f => f.Name == "#text" && String.IsNullOrWhiteSpace(f.InnerHtml)))
            .ToList();

    foreach (var n in nonEmptyNodes)
    {
        if (IsBr(n) && IsBr(n.NextSibling))
        {
            yield break;
        }

        if (n.Name == "#text")
        {
            yield return n.InnerText.Trim();
        }
    }
}

public bool IsBr(HtmlNode n)
{
    return n != null && n.NodeType == HtmlNodeType.Element && n.Name == "br";
}

返回

enter image description here

注意在两个br的

之后它没有返回评论

编辑:

我删除了空的#text值,因为当您在最后两个br代码之间有换行符时,您实际上会获得带有换行符的#text标记。我认为这就是新行混淆的地方。