You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用HtmlAgilityPack更好地解析同级内容?

解决方案

问题根源

paragraphNode.NextSibling无法获取UL节点,是因为HTML中P和UL之间存在空白文本节点(换行、空格这类无意义节点),直接调用会拿到空白节点而非目标UL。另外原代码仅遍历P节点,会遗漏UL这类关联内容。

核心思路

  1. 跳过HTML中的空白文本节点,避免干扰节点遍历。
  2. 以包含<strong>的P节点作为内容块起始,后续非P节点(如UL)归入该块,直到遇到下一个P节点。
  3. 普通P节点单独作为一个内容块。

具体代码实现

public static void Parse(string html)
{
    var document = new HtmlDocument();
    document.LoadHtml(html);
    var contentBlocks = new List<string>();
    StringBuilder currentBlock = new StringBuilder();

    // 遍历body下的所有直接子节点
    foreach (var node in document.DocumentNode.SelectSingleNode("//body").ChildNodes)
    {
        // 跳过空白文本节点
        if (node.NodeType == HtmlNodeType.Text && string.IsNullOrWhiteSpace(node.InnerText))
        {
            continue;
        }

        // 处理P节点
        if (node.Name.Equals("p", StringComparison.OrdinalIgnoreCase))
        {
            // 保存已有的内容块
            if (currentBlock.Length > 0)
            {
                contentBlocks.Add(currentBlock.ToString().Trim());
                currentBlock.Clear();
            }
            // 添加当前P的文本到块中
            currentBlock.AppendLine(node.InnerText.Trim());

            // 如果当前P包含标题(strong标签),收集后续关联节点
            if (node.SelectSingleNode("./strong") != null)
            {
                var nextNode = node.NextSibling;
                // 遍历后续兄弟节点,直到遇到下一个P或无节点
                while (nextNode != null)
                {
                    // 跳过空白节点
                    if (nextNode.NodeType == HtmlNodeType.Text && string.IsNullOrWhiteSpace(nextNode.InnerText))
                    {
                        nextNode = nextNode.NextSibling;
                        continue;
                    }
                    // 遇到下一个P则停止收集
                    if (nextNode.Name.Equals("p", StringComparison.OrdinalIgnoreCase))
                    {
                        break;
                    }
                    // 处理UL节点,提取LI内容
                    if (nextNode.Name.Equals("ul", StringComparison.OrdinalIgnoreCase))
                    {
                        foreach (var li in nextNode.SelectNodes("./li"))
                        {
                            currentBlock.AppendLine($"  - {li.InnerText.Trim()}");
                        }
                    }
                    // 可扩展处理其他节点类型(如OL、DIV等)
                    nextNode = nextNode.NextSibling;
                }
            }
        }
    }

    // 保存最后一个内容块
    if (currentBlock.Length > 0)
    {
        contentBlocks.Add(currentBlock.ToString().Trim());
    }

    // 按需处理内容块,此处示例为控制台输出
    foreach (var block in contentBlocks)
    {
        Console.WriteLine(block);
        Console.WriteLine("---");
    }
}

效果说明

运行后会生成符合需求的内容块:

  • 前四个普通P各为独立块
  • 包含Heading 1的P和后续UL合并为一个块,UL的LI以列表形式呈现
  • 包含Heading 2的P为独立块

内容的提问来源于stack exchange,提问作者monkeySeeMonkeyDo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 18:15:27