在格式良好的HTML中使用Perl和Mojo::DOM定位HTML中的各个元素



使用Perl的相对Beginer,这里有我的第一个问题,尝试以下内容:

我试图从一个大型在线数据集(Eur-Lex)中检索某些信息,其中每个HTML文档都是格式良好的HTML,具有常量元素。每个HTML文件都由其Celex编号标识,该编号作为脚本的参数提供(请参阅下面的Perl代码)。HTML数据如下(只显示我感兴趣的部分):

<!-- 
<blahblah>
< lots of stuff here, before the interesting part>
--> 
<div id="PPClass_Contents" class="panel-collapse collapse in" role="tabpanel"
aria-labelledby="PP_Class">
<div class="panel-body">
<dl class="NMetadata">
<dt xmlns="http://www.w3.org/1999/xhtml">EUROVOC descriptor: </dt>
<dd xmlns="http://www.w3.org/1999/xhtml">
<ul>
<li>
<a href="./../../../search.html?type=advanced&amp;DTS_DOM=ALL&amp;DTS_SUBDOM=ALL_ALL&amp;SUBDOM_INIT=ALL_ALL&amp;DC_CODED=341&amp;lang=en">
<span lang="en">descriptor_1</span>
</a>
</li>
<li>
<a href="./../../../search.html?type=advanced&amp;DTS_DOM=ALL&amp;DTS_SUBDOM=ALL_ALL&amp;SUBDOM_INIT=ALL_ALL&amp;DC_CODED=5158&amp;lang=en">
<span lang="en">descriptor_2</span>
</a>
</li>
<li>
<a href="./../../../search.html?type=advanced&amp;DTS_DOM=ALL&amp;DTS_SUBDOM=ALL_ALL&amp;SUBDOM_INIT=ALL_ALL&amp;DC_CODED=7983&amp;lang=en">
<span lang="en">descriptor_3</span>
</a>
</li>
<li>
<a href="./../../../search.html?type=advanced&amp;DTS_DOM=ALL&amp;DTS_SUBDOM=ALL_ALL&amp;SUBDOM_INIT=ALL_ALL&amp;DC_CODED=933&amp;lang=en">
<span lang="en">descriptor_4</span>
</a>
</li>
</ul>
</dd>
<dt xmlns="http://www.w3.org/1999/xhtml">Subject matter: </dt>
<dd xmlns="http://www.w3.org/1999/xhtml">
<ul>
<li>
<a href="./../../../search.html?type=advanced&amp;DTS_DOM=ALL&amp;DTS_SUBDOM=ALL_ALL&amp;SUBDOM_INIT=ALL_ALL&amp;CT_CODED=BUDG&amp;lang=en">
<span lang="en">Subject_1</span>
</a>
</li>
</ul>
</dd>
<dt xmlns="http://www.w3.org/1999/xhtml">Directory code: </dt>
<dd xmlns="http://www.w3.org/1999/xhtml">
<ul>
<li>01.60.20.00 <a href="./../../../search.html?type=advanced&amp;DTS_DOM=ALL&amp;DTS_SUBDOM=ALL_ALL&amp;SUBDOM_INIT=ALL_ALL&amp;CC_1_CODED=01&amp;lang=en">
<span lang="en">Designation_level_1</span>
</a> / <a href="./../../../search.html?type=advanced&amp;DTS_DOM=ALL&amp;DTS_SUBDOM=ALL_ALL&amp;SUBDOM_INIT=ALL_ALL&amp;CC_2_CODED=0160&amp;lang=en">
<span lang="en">Designation_level_2</span>
</a> / <a href="./../../../search.html?type=advanced&amp;DTS_DOM=ALL&amp;DTS_SUBDOM=ALL_ALL&amp;SUBDOM_INIT=ALL_ALL&amp;CC_3_CODED=016020&amp;lang=en">
<span lang="en">Designation_level_3</span>
</a>
</li>
</ul>
</dd>
</dl>
</div>
</div>
</div>
<!-- 
<still more stuff here>
--> 

我对"PPClass_Contents"div id中包含的信息感兴趣,它由3个元素组成:

-EUROVOC描述符:-主题:-目录代码:

基于上面的HTML,我想使用Perl和Mojo获得这3个主要元素的子元素,得到类似的结果(单行文本文件,3个由制表符分隔的组,grup中的多个子元素由管道字符分隔,类似于这样:

CELEX_No"TAB"描述符_1|描述符_2|描述符_3|描述符_4||描述符_ n"TAB"主题_1||Subject_n"TAB"Designation_level_1|Designation_llevel_2|Designation_level_3||Designation_level_n

"描述符"、"主题"one_answers"Designation_levels"元素(这三个主要组的子组)可以是从1到"n",数量不是固定的,并且事先不知道。

我有以下代码,它确实打印出了有趣部分的纯文本,但我需要处理各个元素,并将它们打印在一个新文件中,如上所述:

#/usr/bin/perl#返回给定CELEX和语言的"分类"描述符严格使用;使用警告;使用Mojo::UserAgent;if($#ARGV ne"1"){print"参数数量错误!\n";print"语法:clookup.pl Lang_ID celex_No.\n";出口-1;}my$lang=$ARGV[0];my$celex=$ARGV[1];my$lclang=lc$lang;#获取eurlex页面my$ua=Mojo::UserAgent->new;我的$dom=$ua->get("https://eur-lex.europa.eu/legal-content/$lang/ALL/?uri=CELEX:$CELEX")->res->dom;################让我们提取一些有趣的部分:my$text=$dom->at('#PPClass_Contents')->all_text;打印"$text\n">
  • lang_code("DE"、"EN"、"IT"等)

  • 芹菜编号(例如:E2014C030352015BP22152015BP0930(48)52015BP09 30(36)52015BP 0930(41)E2014C0302 E2014C0301 E2014C0271 E2014C0134)。

例如(如果您将我的脚本命名为"clookup.pl"):$ perl clookup.pl EN E2014C0303

那么,我如何使用Mojo::DOM如上所述寻址单个元素(数量未知)呢?

或者,有没有更简单或更快的东西(使用Perl)?

你走在了正确的轨道上。首先,您需要了解#PPClass_Contents中的HTML。每一组东西都在一个定义列表中。由于您只关心定义文本,因此可以直接搜索<dd>元素。

$dom->at('#PPClass_Contents')->find('dd')

这将为您提供一个Mojo::Collection,您可以使用->each对其进行迭代。我们传递一个匿名函数,非常像回调。

$dom->at('#PPClass_Contents')->find('dd')->each(sub {
$_; # this is the current element
});

每个元素都将传递给该子元素,并且可以使用主题变量$_进行引用。里面有一个<ul>,每个<li>都包含一个带有所需文本的<span>元素。让我们找到这些。

$_->find('span')

在这个阶段,我们可以直接在您的输出中构建列。让我们使用->each的另一种形式,它将从->find返回的Mojo::Collection转换为一个普通的Perl列表。然后,我们可以使用常规的map操作将每个<span>的文本节点和join抓取到一个字符串中。

join '|', map { $_->text } $_->find('span')->each

为了将所有这些联系在一起,我们在这个构造之外声明一个数组,并将$celex数字粘贴在其中作为第一列。

my @columns = ($celex);
$dom->at('#PPClass_Contents')->find('dd')->each(sub {
push @columns, join '|', map { $_->text } $_->find('span')->each;
});

现在,生成最终的选项卡分隔输出是微不足道的。

print join "t", @columns;

我已经用EN作为语言和$celex编号3206L0121完成了这项工作,搜索在其示例工具提示中使用了该编号。结果是:

32006L0121营销标准|化学产品|法律近似值|危险物质|科学报告|包装|欧洲化学品管理局|标签内部市场-原则|法律近似|技术壁垒|环境|消费者保护行业政策和内部市场|内部市场:法律近似值|危险物质

相关内容

  • 没有找到相关文章

最新更新