Больше проблем с моим руководством по Perl

Спасибо всем, кто помог мне зайти так далеко.

Теперь моя новая проблема. Я работаю с книгой, которая была написана в 2003 году, и в учебном пособии делается попытка обработать страницу, которая изменилась.

Исходный адрес: "http://www.oreilly.com/catalog/prdindex.html "этой страницы больше нет, но она перенаправляет на новую страницу:" http://oreilly.com/store/complete.html "

Проблема «Я думаю» в том, что код HTML изменился за 7 лет. Код был примерно таким:

<tr bgcolor="#ffffff">
<td valign="top">
<a href="http://oreilly.com/catalog/googlehks">Google Hacks</a><br />
</td>
<td valign="top" nowrap="nowrap">0-596-00447-8</td>
<td valign="top" align="right">$24.95</td>
<td valign="top" nowrap="nowrap" align="center"> 
<a href="http://safari.oreilly.com/0596004478">Read it on Safari</a>
</td>
<td valign="top" nowrap="nowrap">
<a href="http://examples.oreilly.com/googlehks">Get examples</a>
</td>
</tr>

Так или иначе, HTML изменился. Вы можете посмотреть его, просмотрев исходный код в своем браузере.

Когда я запускаю скрипт, я получаю такую ​​ошибку:

Использование неинициализированного значения в записи подпрограммы в /usr/lib/perl5/site_perl/5.8.8/HTML/TreeBuilder.pm, строка 93. Невозможно вызвать метод "as_HTML" для неопределенного значения в ./SpiderTutorial_19_09.pl, строка 67. Есть 0 книг по Perl и 0 книг по Java. 0 больше Java, чем Perl.

Вот код, который я пытаюсь запустить.

#!/usr/bin/perl -w
use strict;
use LWP::Simple;
use HTML::TreeBuilder;

my $url = 'http://oreilly.com/store/complete.html';
my $page = get( $url ) or die $!;
my $p = HTML::TreeBuilder->new_from_content( $page );
my($book);
my($edition);

my @links = $p->look_down(
        _tag => 'a',
        href => qr{^ \Qhttp://oreilly.com/complete/\E \w+ 

$}x
);

my @rows = map { $_->parent->parent } @links;

my @books;
for my $row (@rows) {
        my %book;
        my @cells = $row->look_down( _tag => 'td' );
        $book{title}    =$cells[0]->as_trimmed_text;
        $book{price}    =$cells[2]->as_trimmed_text;
        $book{price} =~ s/^\$//;

        $book{url}              = get_url( $cells[0] );
        $book{ebook}    = get_url( $cells[3] );
        $book{safari}   = get_url( $cells[4] );
        $book{examples} = get_url( $cells[5] );
        push @books, \%book;
}

sub get_url {
        my $node = shift;
        my @hrefs = $node->look_down( _tag => 'a');
        return unless @hrefs;
        my $url = $hrefs[0]->atr('href');
        $url =~ s/\s+$//;
        return $url;
}

$p = $p->delete; #we don't need this anymore.

{
        my $count = 1;
        my @perlbooks = sort { $a->{price} <=> $b->{price} }
                                        grep { $_->{title} =~/perl/i } @books;
        print $count++, "\t", $_->{price}, "\t", $_->{title} for @perlbooks;
}

{
        my @perlbooks = grep { $_->{title} =~ /perl/i } @books;
        my @javabooks = grep { $_->{title} =~ /java/i } @books;
        my $diff =  @javabooks - @perlbooks;
        print "There are ".@perlbooks." Perl books and ".@javabooks. " Java books. $diff more Java than Perl.";
}

for my $book ( $books[34] ) {
        my $url = $book->{url};
        my $page = get( $url );
        my $tree = HTML::TreeBuilder->new_from_content( $page );
        my ($pubinfo) = $tree->look_down(


        _tag => 'span',


        class => 'secondary2'
        );
        my $html = $pubinfo->as_HTML; print $html;
        my ($pages) = $html =~ /(\d+) pages/,
        my ($edition) = $html =~ /(\d)(?:st|nd|rd|th) Edition/;
        my ($date) = $html =~ /(\w+ (19|20)\d\d)/;

        print "\n$pages $edition $date\n";

        my ($img_node) = $tree->look_down(


        _tag => 'img',


        src  => qr{^/catalog/covers/},
        );
        my $img_url = 'http://www.oreilly.com'.$img_node->attr('src');
        my $cover = get( $img_url );
        # now save $cover to disk
}

person Dennis    schedule 28.06.2010    source источник
comment
Каков твой вопрос? Вы правы в своем подозрении, что HTML больше не соответствует тому, что ищет код Perl.   -  person Richard Simões    schedule 29.06.2010


Ответы (2)


Ошибки формы:

 Can't call method _________ on an undefined value at _________  line ___

Значит, у вас есть такая конструкция:

 $object->method 

А значение вещи слева ($object) не определено.

Это означает, что в вашем случае рядом со строкой 67 $pubinfo не определено. Вы должны визуально просмотреть код, чтобы выяснить, почему. В этом случае $tree->look_down() должен вернуть неопределенное значение.

Это, вероятно, имеет прямое отношение к изменению структуры страницы, как уже указывалось. Элементы больше не там, где должны быть. Получите исходный код для HTML-страницы и код и посмотрите, сможете ли вы понять, что он пытался сделать изначально, и примените его к новой странице. Надеюсь, книга получилась достаточно хорошей, чтобы вы понимали код даже без рабочего примера.

person Clinton Pierce    schedule 28.06.2010

Когда вы используете look методы HTML :: Treebuilder, вам нужно обрабатывать случаи, когда результаты не возвращаются.

Если HTB просматривает страницу и ничего не находит, вы получите именно ту ошибку, с которой столкнулись.

Где у вас есть:

my ($pubinfo) = $tree->look_down(
    _tag => 'span',
    class => 'secondary2'
);

my $html = $pubinfo->as_HTML; print $html;

Сделайте это, чтобы пропустить книги без pubinfo:

my ($pubinfo) = $tree->look_down(
    _tag => 'span',
    class => 'secondary2'
);

next unless $pubinfo;  # trap no results.    

my $html = $pubinfo->as_HTML; print $html;

Или попробуйте это, чтобы отобразить сообщение по умолчанию:

my ($pubinfo) = $tree->look_down(
    _tag => 'span',
    class => 'secondary2'
);

my $html = $pubinfo 
         ? $pubinfo->as_HTML
         : '<span>No Publisher Info Available</span>';
print $html;

ЛЮБОЙ раз, когда вы делаете что-то, что может дать неопределенные результаты, вам необходимо изучить результаты и убедиться, что они соответствуют вашим ожиданиям. В этом коде вы должны проверять результаты get и каждой операции просмотра.

Кстати, почему вы используете цикл for для перебора одного элемента? (for my $book ( $books[34] )). Я не уверен, что это вас покупает, кроме закрывающей области блока для содержимого цикла.

person daotoad    schedule 29.06.2010