【问题标题】:Perl: Remove list <ul> from paragraph. HTML parsingPerl:从段落中删除列表 <ul>。 HTML解析
【发布时间】:2012-04-20 17:34:46
【问题描述】:

我有一堆 html 文件,我需要从中提取文本,而不是列表的内容。 html就像

<html>

    <Head>
        <title>intranet mycompany</title>
    </head>

    <body>
        <div>blah</div>
        <p>the text i need to extract
            <br>
            <ul>
                <li>stuff i don't want.</li>
                <li>more stuff i don't want.</li>
            </ul>More text i need to exctract.</p>
    </body>

</html>

我真的想要一些关于如何从段落中获取文本而不是从列表中获取文本的建议。任何建议都会被采纳。

问候, 乔博。

【问题讨论】:

  • 顺便说一句,这不是 HTML。在 HTML 中,UL 元素不能出现在 P 元素内部。
  • @casperOne - 当您(作为版主)删除其他答案时,请非常友好并以确切的理由对该答案添加评论。谢谢!

标签: html perl parsing


【解决方案1】:
use strictures;
use HTML::TreeBuilder::XPath qw();
my $dom = HTML::TreeBuilder::XPath->new_from_content(q(<html> … </body>));
my ($ul) = $dom->findnodes('//ul');
$ul->delete;
my $extract = $dom->findvalue('//p');
# " the text i need to extract  More text i need to exctract. "

【讨论】:

    【解决方案2】:

    看看HTML Parsers的CPAN,你会得到很好的解析器,比如HTML::TreeBuilder、HTML::Parser等等。

    【讨论】:

    • 感谢您的评论。任何人都可以提供一些示例代码吗?我能够得到段落的内容。但列表仍会在其中。
    • @user1343861 - 只需搜索(右上角)“[perl] HTML parser”,您会在 stackoverflow 上找到很多信息
    【解决方案3】:

    这是一种摆脱&lt;ul&gt; 数据的方法。由于 HTML::Parser 在调用文本处理程序时不知道它在文档中的哪个位置,因此您必须找到某种方法来提供该信息。

    只需告诉为每个起始元素调用的start_handler 记录关于开放端&lt;ul&gt; 的注释并让end_handler 删除该注释。然后,您可以利用 text_handler 中的信息,这样它就可以跳过 &lt;ul&gt;s 中的文本节点。

    #!/usr/bin/perl -w
    use strict;
    use HTML::Parser;
    
    my $text = '';
    my $parser = HTML::Parser->new(
      start_h => [ \&start_handler, "self,tagname" ],
      end_h   => [ \&end_handler,   "self,tagname" ],
      text_h  => [ \&text_handler,  "self,dtext" ],
    );
    
    sub start_handler {
      my ($self, $tag) = @_;
      $self->{_private}->{'ul'} = 1 if ( $tag eq 'ul' ); # make a note
    }
    
    sub end_handler {
      my ($self, $tag) = @_;
      $self->{_private}->{'ul'} = 0 if ( $tag eq 'ul' ); # remove the note
    }
    
    sub text_handler {
      my ($self, $dtext) = @_;
      unless ($self->{_private}->{'ul'}) {
        # only if we're not inside the <ul>
        $text .= $dtext;
      }
    }
    $parser->parse_file('test.html');
    print $text;
    

    【讨论】:

    • 嵌套 ul 怎么样??我只需将“= 1”和“= 0”更改为“++”和“--”
    • 你是对的。我忘记了。它应该是$self-&gt;{_private}-&gt;{'ul'}++ if ( $tag eq 'ul' ); 和 ``$self->{_private}->{'ul'}-- if ($tag eq 'ul');`。谢谢。
    【解决方案4】:

    最难的一点是数据跨越多行。如果你要将所有的行加入一个大字符串,一个简单的正则表达式,如

    s/<ul>.*<\/ul>//g
    

    应该这样做。

    【讨论】:

    • 这不是使用正则表达式解析 HTML 的好建议。使用现有的 CPAN 模块。
    • 永远不要使用正则表达式解析 XML/HTML/CSV 文件。使用现有的模块,它们通常是成熟、稳定且经过良好测试的。
    • @briandfoy:如果您按照“如果要将所有行合并成一个大字符串” 中的说明进行操作,那么它非常适用于示例。 (不过,在单行模式下,它也能正常工作:codepad.org/Wy2iKg5x)
    • 我同意如果你想解析 HTML,正则表达式不是最好的选择,但是如果你需要一种快速而肮脏的方法来摆脱文件的某些部分,学习一个 HTML 解析器可能无法有效利用时间。
    • @minitech 如果数据中有多个 ul,那么您将删除第一个开头和最后一个结尾之间的所有内容。所以它确实适用于提供的示例,它只有 1 ul,但它很可能不适用于真实数据(请注意,帖子的开头说明了“列表的内容”,我在这里看到足够多的复数来暗示确实有可能列出超过 1 个列表 ;--)。
    猜你喜欢
    • 2017-01-10
    • 2020-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-12
    相关资源
    最近更新 更多