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

时间:2019-01-11 16:25:38

标签: perl mojo-dom

Perl的相对入门者,这里是我的第一个问题,请尝试以下操作:

我正在尝试从大型在线数据集(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中包含的信息感兴趣,该ID由3个元素组成:


    - EUROVOC descriptor:
    - Subject matter:
    - Directory code:

基于上述HTML,我想使用Perl和Mojo来获得这3个主要元素的子元素,得到的结果与此类似(单行文本文件,由制表符分隔的3组,组由竖线字符分隔,如下所示:


    CELEX_No "TAB" descriptor_1|descriptor_2|descriptor_3|descriptor_4|..|descriptor_n "TAB" Subject_1|..|Subject_n "TAB" Designation_level_1|Designation_level_2|Designation_level_3|..|Designation_level_n

“ descriptors”,“ Subjects”和“ Designation_levels”元素(这3个主要组的子级)的元素可以是1到“ n”,其数目不是固定的,并且事先未知。

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


    #!/usr/bin/perl
    # returns "Classification" descriptors for given CELEX and Language

    use strict;
    use warnings;

    use Mojo::UserAgent;

    if ($#ARGV ne "1") {
        print "Wrong number of arguments!\n";
        print "Syntax: clookup.pl Lang_ID celex_No.\n";
        exit -1;
    }

    my $lang = $ARGV[0];   
    my $celex = $ARGV[1];
    my $lclang = lc $lang;

    # fetch the eurlex page

    my $ua = Mojo::UserAgent->new;
    my $dom = $ua->get("https://eur-lex.europa.eu/legal-content/$lang/ALL/?uri=CELEX:$celex")->res->dom;


    ################ let's extract interesting parts:


    my $text = $dom->at('#PPClass_Contents')->all_text;
    print "$text\n";

编辑(添加): 您可以使用两个参数尝试我的Perl脚本:

  • 语言代码(“ DE”,“ EN”,“ IT”等)

  • Celex编号(例如:E2014C0303、52015BP2212、52015BP0930(48),52015BP0930(36),52015BP0930(41),E2014C0302,E2014C0301,E2014C0271,E2014C0134)。

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

那么,如何使用Mojo :: DOM处理上述单个元素(数量未知)?

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

1 个答案:

答案 0 :(得分:1)

您处在正确的轨道上。首先,您需要了解#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 operation来抓取每个<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数字 32006L0121 来完成此操作,该搜索在其示例工具提示中使用了该数字。结果是这样的:

  

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