Как извлечь элемент HTML на основе его класса?

Я только начинаю в Perl и написал простой script, чтобы сделать некоторые веб-скребки. Я использую WWW:: Mechanize и HTML:: TreeBuilder, чтобы выполнить большую часть работы, но у меня возникли проблемы. У меня есть следующий HTML:

<table class="winsTable">
    <thead>...</thead>
    <tbody>
        <tr>
            <td class = "wins">15</td>
        </tr>
    </tbody>
</table>

Я знаю, что есть некоторые модули, которые получают данные из таблиц, но это особый случай; не все данные, которые я хочу, находятся в таблице. Итак, я попробовал:

my $tree = HTML::TreeBuilder->new_from_url( $url );
my @data = $tree->find('td class = "wins"');

Но @data возвращается пустым. Я знаю, что этот метод будет работать без имени класса, потому что я успешно проанализировал данные с помощью $tree->find('strong'). Итак, есть ли модуль, который может обрабатывать этот тип синтаксиса HTML? Я просмотрел документацию HTML:: TreeBuilder и не нашел ничего, что появилось, но я мог ошибаться.

Ответ 1

Я использую отличный (но иногда немного медленный) модуль HTML::TreeBuilder::XPath:

my $tree = HTML::TreeBuilder::XPath->new_from_content( $mech->content() );
my @data = $tree->findvalues('//table[ @class = "winsTable" ]//td[@class = "wins"]');

Ответ 2

Вы можете использовать метод look_down для поиска определенного тега и атрибутов, которые вы ищете. Это находится в модуле HTML::Element (который импортируется HTML::TreeBuilder).

my $data = $tree->look_down(
    _tag  => 'td',
    class => 'wins'
);

print $data->content_list, "\n" if $data; #prints '15' using the given HTML

$data = $tree->look_down(
    _tag  => 'td',
    class => 'losses'
);

print $data->content_list, "\n" if $data; #prints nothing using the given HTML

Ответ 3

(Это своего рода дополнительный ответ dspain)

На самом деле вы пропустили место в документации HTML:: TreeBuilder, где говорится:

Объекты этого класса наследуют методы как HTML:: Parser, так и HTML:: Element. Методы, унаследованные от HTML:: Parser, используются для построения дерева HTML, а методы, унаследованные от HTML:: Element, - это то, что вы используете для тщательного изучения дерева. Помимо этой (HTML:: TreeBuilder) документации, вы также должны внимательно прочитать документацию HTML:: Element, а также снять документацию HTML:: Parser - возможно, интересны только ее методы синтаксического анализа и parse_file.

(Обратите внимание, что полужирное форматирование принадлежит мне, это не в документации)

Это означает, что вы должны читать документацию HTML:: Element, где вы найдете find метод, в котором говорится

Это просто псевдоним find_by_tag_name

Это должно сказать вам, что оно не работает для имен классов, но в его описании также упоминается метод look_down, который может быть немного ниже. Если вы посмотрите на пример, вы увидите, что он делает то, что вы хотите. И dspain answer показывает, как именно в вашем случае.

Справедливости ради, документация не так просто ориентироваться.

Ответ 4

Я нашел ссылку this наиболее полезной, рассказывая мне, как извлекать конкретную информацию из html-контента. Я использовал последний пример на странице:

use v5.10;
use WWW::Mechanize;
use WWW::Mechanize::TreeBuilder;

my $mech = WWW::Mechanize->new;
WWW::Mechanize::TreeBuilder->meta->apply($mech);

$mech->get( 'http://htmlparsing.com/' );

# Find all <h1> tags
my @list = $mech->find('h1');

# or this way <----- I found this way very useful to pinpoint exact classes with in some html
my @list = $mech->look_down('_tag' => 'h1', 
                            'class' => 'main_title');

# Now just iterate and process
foreach (@list) {
    say $_->as_text();
}

Казалось, что гораздо проще вставать и работать, чем любой из других модулей, на которые я смотрел. Надеюсь, это поможет!