Как легко разобрать <div class = "foo"> и </div> в Perl - PullRequest
6 голосов
/ 20 декабря 2011

Я хочу разобрать сайт в структуру данных Perl. Сначала я загружаю страницу с

use LWP::Simple;
my $html = get("http://f.oo");

Теперь я знаю два способа справиться с этим. Сначала регулярные выражения и вторые модули.

Я начал с чтения HTML :: Parser и нашел несколько примеров. Но я не настолько уверен в знании Perl.

Мой пример кода продолжается

my @links;

my $p = HTML::Parser->new();
$p->handler(start => \&start_handler,"tagname,attr,self");
$p->parse($html);

foreach my $link(@links){
  print "Linktext: ",$link->[1],"\tURL: ",$link->[0],"\n";
}

sub start_handler{
  return if(shift ne 'a');
  my ($class) = shift->{href};
  my $self = shift;
  my $text;
  $self->handler(text => sub{$text = shift;},"dtext");
  $self->handler(end => sub{push(@links,[$class,$text]) if(shift eq 'a')},"tagname");
}

Я не понимаю, почему сдвиг два раза. Секундом должен быть сам указатель. Но первое заставляет меня думать, что ссылка на себя уже сдвинута, используется как хэш, а значение для href хранится в $class. Может ли кто-нибудь объяснить эту строку (my ($class) = shift->{href};)?

Помимо этого, я не хочу анализировать все URL, я хочу поместить весь код между <div class ="foo"> и </div> в строку, где много кода, особенно другие теги <div></div>. Так что я или модуль должен найти правильный конец. После этого я планировал снова просмотреть строку, чтобы найти специальные классы, такие как <h1>,<h2>, <p class ="foo2"></p> и т. Д.

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

Ответы [ 4 ]

5 голосов
/ 20 декабря 2011

Использование HTML :: TokeParser :: Simple .

Непроверенный код на основе вашего описания:

#!/usr/bin/env perl

use strict; use warnings;

use HTML::TokeParser::Simple;

my $p = HTML::TokeParser::Simple->new(url => 'http://example.com/example.html');

my $level;

while (my $tag = $p->get_tag('div')) {
    my $class = $tag->get_attr('class');
    next unless defined($class) and $class eq 'foo';

    $level += 1;

    while (my $token = $p->get_token) {
        $level += 1 if $token->is_start_tag('div');
        $level -= 1 if $token->is_end_tag('div');
        print $token->as_is;
        unless ($level) {
            last;
        }
    }
}
5 голосов
/ 20 декабря 2011

HTML :: Parser - больше токенайзер, чем парсер.Это оставляет вам много тяжелой работы.Рассматривали ли вы использование HTML :: TreeBuilder (который использует HTML :: Parser) или XML :: LibXML (отличная библиотека с поддержкой HTML)?

3 голосов
/ 25 декабря 2011

Не нужно быть таким сложным. Вы можете извлекать и находить элементы в DOM, используя CSS-селекторы с Mojo :: UserAgent :

say Mojo::UserAgent->new->get('http://f.oo')->res->dom->find('div.foo');

или, просмотреть все найденные элементы:

say $_ for Mojo::UserAgent->new->get('http://f.oo')->res->dom
    ->find('div.foo')->each;

или, цикл с использованием обратного вызова:

Mojo::UserAgent->new->get('http://f.oo')->res->dom->find('div.foo')->each(sub {
  my ($count, $el) = @_;
  say "$count: $el";
});
1 голос
/ 20 декабря 2011

Согласно документации, подпись обработчика (\%attr, \@attr_seq, $text).Существует три смены, по одной для каждого аргумента.

my ($class) = shift->{href};

эквивалентно:

my $class;
my %attr_seq;
my $attr_seq_ref;

$attr_seq_ref = shift;
%attr_seq = %$attr_seq_ref;
$class = $attr_seq{'href'};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...