Mojo::DOM - 如何从 dom 对象中解析数据集?

Posted

技术标签:

【中文标题】Mojo::DOM - 如何从 dom 对象中解析数据集?【英文标题】:Mojo::DOM - How to parse sets of data out of a dom object? 【发布时间】:2021-06-23 18:53:32 【问题描述】:

我在 html 结果页面中有数据,我想迭代地解析出其中的数据集。在一般的“结果页”格式中,有一个主要的结果部分(div),其中包含一堆子部分(sub divs),这些子部分又包含带有结果数据的各种标签。

Faux, pseudo, not-real code

$file = Mojo::File->new('BigData.htm');         # Read in some file
$dom  = Mojo::DOM->new($file->slurp);           # Slurp the dom out of it
                                                # 
$rs = $dom->at('div.resultsSection');           # Find the beginning of the results section
                                                # 
for my $ss ($rs->at('div.subSection')          # Start looping through the subsections
                                                # 
    $cs = $ss->find('p.coolStuff');             # Find correlating data
    $is = $ss->find('div.importantStuff');      # 
                                                # 
    if(! defined $is)                          # Make decisions based on data availability
        $is = $ss->find('div.differentClass');  #      and data quality
                                               # 
    push (@array, "$cs\t$is\n");                # Reformat it for my purposes
                                               # 

显然,上面的虚假、伪、非真实代码在任何意义上都是完全虚假的,除了以下内容: 这是我正在尝试做的事情的逻辑表示。 "->at()" 应该返回一个 dom 对象,该对象以第一次出现的给定标签开始。 “->find()”返回匹配标签的集合。我理解使用 css 选择器(和其他方法)我可以将两种方法的结果限制为唯一的项目(我确实这样做了)。但是,我的知识到此为止。

我能够一次找到一种类型的所有标签。但数据很复杂,事后无法关联结果。

我还能够抓取一个小节,并收集我需要的数据集,但我不知道如何创建一个遍历所有小节的循环。

这一切都错了吗?

【问题讨论】:

【参考方案1】:

我想出了一个可行的解决方案。我不知道这是否是最好的解决方案,但它直截了当且简单,这肯定是正确的方向。

下面的 html 段以主“容器”开头,并包含一个搜索结果行:(我应该将其包含在我原来的问题中 - 抱歉)

<div class="container">
    <div class="row searchResultRow">
        <div class="col-sm-12">
            <div class="row">
                <div class="col-md-12">
                    <p class="searchResultTitle">Some Data Here</p>
                </div>
            </div>
            <div class="row">
                <div class="col-sm-7 col-md-8">
                    <div class="row">
                        <div class="col-md-2">
                            <div class="clearfix"> <img  class="searchResultImg" src='/images/image.png' /> </div>
                            <p> <a class="bodyLink" href="description.html">View Details</a> </p>
                        </div>
                        <div class="col-sm-5 col-md-4">
                            <p> <span class="gridTxtLbl br-responsive-sm">Type</span> <span class="gridDataItem br-responsive-sm">Organic</span> </p>
                        </div>
                        <div class="col-sm-3 col-md-3">
                            <p> <span class="gridTxtLbl br-responsive-sm">Year</span> <span class="gridDataItem br-responsive-sm">1955</span> </p>
                        </div>
                        <div class="col-sm-4 col-md-3"> </div>
                    </div>
                    <div class="row">
                        <div class="col-md-12"> </div>
                    </div>
                </div>
                <div class="col-sm-5 col-md-4">
                    <p class="gridTxtLbl">Origin</p>
                    <div class="">
                        <div class="mapIconDiv">
                            <a href="/Maps/ShowMap" id="res_thx-1138"> 
                                <span class="iconWithText">
                                    <span class="fa fa-home" aria-hidden="true"></span>
                                    <br />Map 
                                </span>
                            </a>
                            <script>
                                $(function() 
                                    $('#res_' + thx-1138).click(function(e) 
                                        e.preventDefault();
                                        var url = $(this).attr('href');
                                        $.ajax(
                                            url: url,
                                            success: function(html) 
                                                $('#mapModal').html(html);
                                                $('#mapModal').modal();
                                                initialize(40.7856211, -76.5780298, 'Secret Location<br/>Lincoln County, NV', '2');
                                            
                                        );
                                    );
                                );
                            </script>
                        </div>
                        <div class="searchResultAddress">
                            <br />Lincoln County, NV</div>
                    </div>
                </div>
            </div>
        </div>
    </div>

下面的代码循环遍历数据并抓取什么:

use Mojo::UserAgent;
use Mojo::File;
use feature 'say';

$infile = 'searchResults.htm';

unless( -e $infile )                                                       # Did I already save this data?
    $ua = Mojo::UserAgent->new;                                             # No? Then go get it
    $tx = $ua->get( 'https://www.someurl.com/BigDataResults.html' );        # URL hardcoded here to simplify this post
    unless( $tx->result->is_success )  
        die "Doh!!!  ", $tx->result->code
    

    $tx->result->save_to( $searchResults.htm );                                


$data = Mojo::File->new( $infile )->slurp;
$dom  = Mojo::DOM->new( $data );

$c = $dom->at('div.container');                                             # Return the dom from the beginning of the results data section
                                                                            #    in my case, this "div.class" is unique
for $row ($c->find('div.searchResultRow')->compact->each)                   # Return a collection of each subsection (row)
                                                                           #    
    $data1 = $row->at('div > div > div > div > p')->text;                   # Use css direct child selectors to navigate paths into nested tag structures
    $data2 = $row->at('div > div > div > div > div > div > script')->text;  # <-- There was some lat/long data in this script I needed to parse out
    $data3 = $row->at('div > div > div > p > span')->text;                  # <-- More data in another nested tag structure
                                                                            #
    # A Lot of massaging and formatting code was here #                     
                                                                            
    push (@array, "$cs\t$is\n");                                            # wrap up the data for later

这是运行的实际代码,尽管我摆脱了所有使主逻辑混乱的东西。

给其他试图找到此问题答案的人的说明:

虽然直接子选择器“>”类似于硬编码路径,因此是一个脆弱的解决方案,但对我而言,它的优势在于长 css 选择器路径是唯一的。

【讨论】:

以上是关于Mojo::DOM - 如何从 dom 对象中解析数据集?的主要内容,如果未能解决你的问题,请参考以下文章

如何解析<IMG SRC =";值QUOT;从这个XML使用DOM

XML数据如何进行解析呢,方式有哪些?

js中如何判断一个DOM对象是不是存在?

克隆 dom.Document 对象

如何解析 DOM(反应)

XML 解析---dom解析和sax解析