在Perl中从HTMl/XML标记中提取文本

在Perl中从HTMl/XML标记中提取文本,html,regex,xml,perl,Html,Regex,Xml,Perl,我有一个像这样的HTTPS响应 一些标题localconfig key name=“ssl\U默认值” 值SHA256/值 /钥匙 一些h2 一些文本: use XML::LibXML qw( ); my $xml_doc = XML::LibXML->new->parse_string($xml); for my $key_node ($xml_doc->findnodes("/localconfig/key")) { my $key = $key_node-&g

我有一个像这样的HTTPS响应


一些标题localconfig
key name=“ssl\U默认值”
值SHA256/值
/钥匙
一些h2
一些文本:
use XML::LibXML qw( );

my $xml_doc = XML::LibXML->new->parse_string($xml);

for my $key_node ($xml_doc->findnodes("/localconfig/key")) {
   my $key = $key_node->getAttribute("name");
   my $val = $key_node->findvalue("value/text()");
   say "$key: $val";
}
我需要提取键和值之间的键


抓住我

提取嵌入的XML文档后,应使用适当的XML解析器

my $html_doc = XML::LibXML->new( recover => 2 )->parse_html_fh($html);
my $xml = encode_utf8( $html_doc->findvalue('/html/body/pre/text()') =~ s/^[^<]*//r );

这就给我们留下了如何提取XML文档的问题

use warnings;
use strict;
use feature 'say';

use Marpa::HTML qw(html);
use HTML::Entities qw(decode_entities);    

my $input = do { local $/; <DATA> };    
my $html = decode_entities($input);

my (@attrs, @cont);

my $marpa_key = Marpa::HTML::html( 
    \$html,
    {
        'key' => sub {
            push @attrs, Marpa::HTML::attributes();
            push @cont, Marpa::HTML::contents();
        },
    }
);

for my $i (0..$#cont) {
    say "For attribute \"name=$attrs[$i]->{name}\" the <key> has: $cont[$i]"
}

__DATA__
...the same as in the first example, data from the question...
选项1:XML::LibXML

您可以使用XML::LibXML并简单地告诉它忽略错误(虚假的

标记)

my$html\u doc=XML::LibXML->new(recover=>2)->parse\u html\u fh($html);
我的$xml=encode_utf8($html_doc->findvalue('/html/body/pre/text()')=~s/^[^new($decoded_html));

我的$xml=encode\u utf8($html\u doc->at('html>body>pre')->text=~s/^[^这个问题的难点在于,呈现的文档混合了各种格式——它有一个有效的html结构,但也有一些类似xml的元素,这些元素看起来是“抛出的”没有特定的图案。有一些方法可以解开这些部分,即使它们不是防弹的,并且有权衡

在这种情况下,它可以完成整个工作,因为它可以处理坏数据,但请注意警告

它在解析时使用API收集元素
属性和
内容

原则上,它可能适合您的问题,因为它只接受
的语义作为一个元素。但是,这些并没有被视为XML,如果您的数据更多地依赖于XML,那么这可能是一个缺点。当然,这是一种有自己规则的不同方法

请注意,该模块的基本逻辑和用途是,每个coderef
返回
,该返回用于它触发的元素;其余文本保持不变。因此,更改文档的特定元素是很自然的

我在上面使用了不同的方法,只是为了收集关于“标签”的信息。代码打印出来

对于属性“name=ssl\u default”,具有:
sha256
对于属性“name=some variable”,具有:
1024

Try。它使用CSS规则遍历HTML。您是否有实体
(在代码中显示)或
(在文本中引用)?@zdim我在原始响应中有
value
。使用它转换成的decode_实体,我还没有吞下魔咒药丸——也就是说,我甚至还没有看过它——我更喜欢XPath选择器而不是CSS选择器,但我肯定会从Mojo::DOM开始。我知道的唯一其他lax解析器是HTML::parser,它是dated。(当然,我想你的意思是
XML::LibXML->new->parse_html_string
无法处理它)
my$XML=Mojo::DOM->new($html)->at('pre')->text
应该足够了(包括解码实体),如果有其他的
标记,CSS选择器将需要更加具体。使用Mojo::DOM解析XML的示例(如果这样做,最好从提取中对其进行解码):
对于我的$key\u节点(Mojo::DOM->new->XML(1)->parse($XML)->find('localconfig>key')->每个){my$key=$key=$key\u节点->{name};my$val=$key_node->children('value')->first->text;…}
在解析之前解码实体的方法(更不用说将XML和HTML混合在一起)将破坏一切!您应该按照前面所示分两步执行。@ikegami(1)是的,我知道存在问题,并发出警告。但这确实为(混合的!)提供了一些处理方法数据,这是棘手的部分——所以我提供它,考虑到它仍然有用(2)对于解码的实体,一个得到好的标记;这将如何打破东西?(3)所有这些都是为了(类似的)这个例子(4)总的来说,这有一些问题,但它给了他们一些可以处理的东西。(那就是“一旦你提取了”是“细节中的魔鬼”,因为没有干净的“嵌入式XML”。Mojo方法还需要一个人先手工破解它)@ikegami“更不用说将XML和HTML混合在一起”——这正是我发布这篇文章的原因。这是困难的部分,它是混合的,几乎是随机的。这是要付出代价的,另一个选择是regex(以及其他一些方法,如您所展示的)。我将编辑并使警告更可怕,并将展示一个
Marpa
…的示例。但我担心,通常没有干净的方法来解析在HTML中使用任意(类似XML)标记的文档。让我们来看看。
use Encode    qw( decode encode_utf8 );
use Mojo::DOM qw( );

my $decoded_html = decode($encoding, $html);
my $html_doc = Mojo::DOM->new($decoded_html);    
my $xml = encode_utf8( $html_doc->at('html > body > pre')->text =~ s/^[^<]*//r );
use warnings;
use strict;
use feature 'say';

use Encode qw(encode_utf8); 
use XML::LibXML;

my $html_doc = XML::LibXML->new(recover => 2)->parse_html_fh(\*DATA);
my $xml = encode_utf8( 
    $doc->findvalue('/html/body/pre/text()') =~ s/^[^<]*//r 
);
my $xml_doc = XML::LibXML->new->parse_string($xml);

say for $xml_doc->findnodes('//key');  # node object stringifies

__DATA__
<html>
    <head> 
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>Some tittle &lt;localconfig&gt;
  &lt;key name="ssl_default"&gt;
    &lt;value&gt;sha256&lt;/value&gt;
  &lt;/key&gt;

</title>
    </head>
    <body>
        <h2>Some h2</h2>
        <p>some text:

            <pre>    text &lt;localconfig&gt;
  &lt;key name="ssl_default"&gt;
    &lt;value&gt;sha256&lt;/value&gt;
  &lt;/key&gt;
  &lt;key name="some variable"&gt;
    &lt;value&gt;1024&lt;/value&gt;
  &lt;/key&gt;
&lt;/localconfig&gt;
</pre>
        </p>
        <hr>
        <i>
            <small>Some text</small>
        </i>
        <hr/>
    </body>
</html>
use warnings;
use strict;
use feature 'say';

use Marpa::HTML qw(html);
use HTML::Entities qw(decode_entities);    

my $input = do { local $/; <DATA> };    
my $html = decode_entities($input);

my (@attrs, @cont);

my $marpa_key = Marpa::HTML::html( 
    \$html,
    {
        'key' => sub {
            push @attrs, Marpa::HTML::attributes();
            push @cont, Marpa::HTML::contents();
        },
    }
);

for my $i (0..$#cont) {
    say "For attribute \"name=$attrs[$i]->{name}\" the <key> has: $cont[$i]"
}

__DATA__
...the same as in the first example, data from the question...