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

使用Perl模块HTML::TreeBuilder::LibXML提取h2对应p文本并判断节点类型

这是一个很典型的HTML结构化提取需求,我来给你一步步拆解解决方案:

完整实现代码

use strict;
use warnings;
use HTML::TreeBuilder::LibXML;

# 你的HTML内容
my $html = <<'HTML';
<h2><a name="abbey">Abbey</a></h2>
<p>text paragraph 1</p>
<p>text paragraph 2</p>
<p>text paragraph 3</p>
<h2><a name="abbess">Abbess</a></h2>
<p>text paragraph 4</p>
<p>text paragraph 5</p>
<h2><a name="abbot">Abbot</a></h2>
<p>text paragraph 6</p>
<p>text paragraph 7</p>
<p>text paragraph 8</p>
HTML

# 初始化解析器并加载HTML
my $tree = HTML::TreeBuilder::LibXML->new();
$tree->parse($html);
$tree->eof();

my %title_to_paragraphs;
my $current_title;

# 按文档顺序遍历所有h2和p节点
foreach my $node ($tree->findnodes('//h2 | //p')) {
    # 获取当前节点的标签名(转小写避免大小写问题)
    my $tag = lc($node->nodeName());
    
    if ($tag eq 'h2') {
        # 提取h2内部a标签的文本作为当前标题
        my $a_element = $node->findnodes('./a')->shift;
        if ($a_element) {
            $current_title = $a_element->textContent();
            # 初始化数组(确保键存在)
            $title_to_paragraphs{$current_title} //= [];
        }
    } elsif ($tag eq 'p' && defined $current_title) {
        # 将p的文本追加到当前标题对应的列表中
        push @{$title_to_paragraphs{$current_title}}, $node->textContent();
    }
}

# 验证结果
foreach my $title (sort keys %title_to_paragraphs) {
    print "* $title: (" . join(', ', @{$title_to_paragraphs{$title}}) . ")\n";
}

# 清理资源
$tree->delete();

关键细节说明

1. 构建标题-段落哈希的逻辑

核心思路是按文档顺序跟踪当前标题:

  • 用XPath表达式//h2 | //p获取所有目标节点,保证遍历顺序和HTML中的出现顺序完全一致
  • 遇到<h2>节点时,提取其内部<a>标签的文本作为哈希的键,并更新$current_title变量
  • 遇到<p>节点且当前有活跃标题时,将段落文本追加到对应键的数组中

2. 判断节点类型的方法

在HTML::TreeBuilder::LibXML中,节点基于LibXML对象,判断标签类型有两种常用方式:

  • $node->nodeName(): 返回节点的标签名,建议转成小写后判断(lc($node->nodeName())),避免HTML中标签大小写不一致的问题
  • $node->tag(): 这是兼容传统HTML::TreeBuilder的方法,效果和nodeName()完全一致

如果需要确保节点是元素节点(排除文本、注释等非元素节点),可以先做类型判断:

use XML::LibXML qw(XML_ELEMENT_NODE);
if ($node->nodeType() == XML_ELEMENT_NODE) {
    # 处理元素节点的逻辑
}

额外优化建议

  • 文本清理:如果段落文本有多余的空格或换行,可以用正则清理:$node->textContent() =~ s/^\s+|\s+$//gr
  • 容错处理:如果<h2>下没有<a>标签,或者<a>没有文本,可以添加默认值或直接跳过该标题
  • 内存管理:记得调用$tree->delete()释放解析器占用的内存,避免长期运行出现内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:39:02