在Perl中从HTMl/XML标记中提取文本
我有一个像这样的HTTPS响应在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
一些标题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 <localconfig>
<key name="ssl_default">
<value>sha256</value>
</key>
</title>
</head>
<body>
<h2>Some h2</h2>
<p>some text:
<pre> text <localconfig>
<key name="ssl_default">
<value>sha256</value>
</key>
<key name="some variable">
<value>1024</value>
</key>
</localconfig>
</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...