7

私の質問のタイトルはそれほど説明的ではないことはわかっていますが、ここで説明させてください。

HTML::TreeBuilder を使用して、指定されたhtml ドキュメントを解析しようとしています。このHTMLドキュメントの値5,1,ABC,DEFは、ユーザーが指定した値に対して検証され、その検証が成功した場合はhrefリンクを抽出する必要があります。

だから、私のコードは次のとおりです。

my @tag = $tree->look_down( _tag => 'tr', class => qr{\bepeven\scompleted\b} );
for (@tag) {

    query_element($_);
}

sub query_element {

    my @td_tag = $_[0]->look_down( _tag => 'td' );

    my $num1 = shift @td_tag; #Get the first td tag
    my $num2 = shift @td_tag; # Get the second td tag


    #Making sure first/second td tag has numeric value
    $num1 = $1 if $num1->as_text =~ m!(\d+)! or die "no match found";
    $num2 = $1 if $num2->as_text =~ m!(\d+)! or die "no match found";


    #Validating that above value's match the user provided value 5 and 1.
    if ( $num1 eq '5' && $num2 eq '1' ) { 
        say "hurray..!!";

        #Iterating over rest of the td tag to make sure we get the right link from it.
        for (@td_tag) {

            #Check if contains ABC and than procede to fetch the download href link.
            if ($_->look_down(_tag  => 'td', class => qr{[c]}, sub {
                        $_[0]->as_text eq 'ABC';} )
            )   
            {   
                my $text = $_->as_text;
                say "Current node text is: ", $text; #outputs ABC

                #Now from here how do I get the link I want to extract.
            }
        }
    }
}

さて、私のアプローチは、最初に値を抽出し、td tagsそれが成功した場合はユーザーが指定した値と照合し、別のユーザーが指定した値を探すよりもABC or DEF、私の場合はリンクのみを抽出するよりもABC一致した場合です。

現在、タグを含むタグABC or DEFの位置は固定されていませんが、5 and 1値を含むタグの下になります。それで、私$_[0]->as_text eq 'ABC';はタグがABCツリーに含まれていることを確認していました。現在、text nodeここからABCにいます。リンクhrefを抽出するにはどうすればよいですか。オブジェクトツリーを上に移動して値を抽出するにはどうすればよいですか。

PS: ここで xpath を試してみましたが、html 要素の位置が明確に定義されておらず、構造化されていません。

編集:

それで、私は試し$_->tag()て戻ってきtdましたが、次のコードが機能しない理由よりも td タグを使用している場合:

my $link_obj = $_->look_down(_tag => 'a') # It should look for `a` tag.
say $link_obj->as_text;

しかし、次のエラーが発生します。

Can't call method "as_text" on an undefined value.
4

3 に答える 3

4

以下(私自身のMarpa :: R2 :: HTMLを使用)がお役に立てば幸いです。HTML::TreeBuilderの回答は1つの回答しか見つけられないことに注意してください。以下のコードは2つを見つけますが、これは意図したものだと思います。

#!perl

use Marpa::R2::HTML qw(html);

use 5.010;
use strict;
use warnings;

my $answer = html(
    ( \join q{}, <DATA> ),
    {   td => sub { return Marpa::R2::HTML::contents() },
        a  => sub {
            my $href = Marpa::R2::HTML::attributes()->{href};
            return undef if not defined $href;
            return [ link => $href ];
        },
        'td.c' => sub {
            my @values = @{ Marpa::R2::HTML::values() };
            if ( ref $values[0] eq 'ARRAY' ) { return $values[0] }
            return [ test => 'OK' ] if Marpa::R2::HTML::contents eq 'ABC';
            return [ test => 'OK' ] if Marpa::R2::HTML::contents eq 'DEF';
            return [ test => '' ];
        },
        tr => sub {
            my @cells = @{ Marpa::R2::HTML::values() };
            return undef if shift @cells != 5;
            return undef if shift @cells != 1;
            my $ok = 0;
            my $link;
            for my $cell (@cells) {
                my ( $type, $value ) = @{$cell};
                $ok = 1 if $type eq 'test' and $value eq 'OK';
                $link = $value if $type eq 'link';
            }
            return $link if $ok;
            return undef;
        },
        ':TOP' => sub { return Marpa::R2::HTML::values(); }
    }
);

die "No parse" if not defined $answer;
say join "\n", @{$answer};

__DATA__
<table>
    <tbody>

        <tr class="epeven completed">
            <td>5</td>
            <td>1</td>
            <td class="c">ABC</td>
            <td class="c">satus</td>
            <td class="c"><a href="/path/link">Download</a></td>
        </tr>
        <tr class="epeven completed">
            <td>5</td>
            <td>1</td>
            <td class="c">status</td>
            <td class="c">DEF</td>
            <td class="c"><a href="/path2/link">Download</a></td>
        </tr>


    </table>
于 2012-09-18T02:27:01.803 に答える
2

あなたが何をしようとしているのかよくわかりませんが、これらの線に沿った何かはありますか? look_down を使用して、必要なものを記述します。ツリーをナビゲートする必要はありません。それは壊れやすいでしょう。

use strict;
use warnings;
use HTML::TreeBuilder 5 -weak;
use 5.014;

my $tree = HTML::TreeBuilder->new_from_content(<DATA>);


for my $e ($tree->look_down( _tag => 'a',
                             sub { my $e = $_[0];
                                   my $tr = $e->parent->parent; ### Could also use ->lineage to search up through the 
                                                                ### containing elements
                                   return unless $tr->attr('_tag') eq 'tr' and $tr->attr('class') eq 'epeven completed';
                                   return (     $tr->look_down( _tag => 'td', sub { $_[0]->as_text eq '1'; })
                                            and $tr->look_down( _tag => 'td', sub { $_[0]->as_text eq '5'; })
                                            and $tr->look_down( _tag => 'td', class => 'c', sub { $_[0]->as_text eq 'ABC'; })
                                          );
                                 }
                           )
          ) {
    say $e->attr('href');
}


__DATA__

<table>
    <tbody>

        <tr class="epeven completed">
            <td>5</td>
            <td>1</td>
            <td class="c">ABC</td>
            <td class="c">satus</td>
            <td class="c"><a href="/path/link">Download</a></td>
        </tr>
        <tr class="epeven completed">
            <td>5</td>
            <td>1</td>
            <td class="c">status</td>
            <td class="c">DEF</td>
            <td class="c"><a href="/path2/link">Download</a></td>
        </tr>


    </table>

出力:

/path/link
于 2012-09-13T17:50:30.920 に答える
0

HTML::TreeBuilder を忘れることができる場合は、次のように解析できます。

for my $r ($content =~ m{<tr class="epeven completed">(.*?)</tr>}gs) {
    my ($n1, $n2) = $r =~ m{<td>(\d+)</td>\s*<td>(\d+)</td>}g;
    next if $n1 != 5 || $n2 != 1;
    next if $r !~ m{<td class="c">ABC</td>}g;
    my ($link) = $r =~ m{<a href="(.*?)">Download</a>}g;
    say $link;
}
于 2012-09-13T17:51:57.370 に答える