2011-12-19 11 views
6

Quiero analizar un sitio web en una estructura de datos Perl. En primer lugar me carga la página conCómo analizar entre <div class ="foo"> and</div> fácilmente en Perl

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

Ahora sé dos maneras de tratar con él. Primero están las expresiones regulares y los demás módulos.

Comencé leyendo sobre HTML::Parser y encontré algunos ejemplos. Pero no estoy tan seguro acerca del conocimiento de Perl.

Mi ejemplo de código va en

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"); 
} 

No entiendo por qué hay dos veces por turno. El secound debe ser el auto puntero. Pero el primero me hace pensar que la auto-referencia ya está en shiftet, se usa como Hash y el valor para href se almacena en $class. ¿Alguien podría explicar esta línea (my ($class) = shift->{href};)?

Junto a esta falta, no quiero que analizar todas las direcciones URL, quiero poner todo el código entre <div class ="foo"> y </div> en una cadena, donde las porciones de código es el medio, especialmente otros <div></div> etiquetas. Entonces, yo o un módulo tenemos que encontrar el extremo correcto. Después de que lo planee para escanear la cadena de nuevo, para encontrar las clases especiales, como <h1>,<h2>, <p class ="foo2"></p>, etc.

espero que esta información le ayuda a darme algunos consejos útiles, y por favor tenga en cuenta que en primer lugar me gustaría añadir una fácil comprensión, que no tiene que ser una gran actuación en el primer nivel!

+5

DON 'T USE EXPRESIONES REGULARES! ¡HTML NO ES REGULAR! –

+5

Qué reconfortante ver a alguien usando un analizador HTML para analizar HTML en lugar de expresiones regulares: p +1 solo para eso – fge

+1

FWIW: 'my ($ class) = shift -> {href};' <- significa tomar el 'href' hash miembro del argumento desplazado. Podría haber sido escrito 'my $ ref = shift; my $ class = $ ref -> {"href"}; ' – fge

Respuesta

1

De acuerdo con los documentos, la firma del manejador es (\%attr, \@attr_seq, $text). Hay tres turnos, uno para cada argumento.

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

es equivalente a:

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

$attr_seq_ref = shift; 
%attr_seq = %$attr_seq_ref; 
$class = $attr_seq{'href'}; 
+0

Lo tengo. Pero, ¿qué pasa con la condición? ¿No llama a otro cambio? ¿Y por qué es solo una 'a' cuando comienza con '... froehli

+0

Como dije, hay tres cambios allí, no dos: uno en el 'si', uno para los atributos (uno de los cuales se asigna a '$ class'), y uno para lo que se convierte en' $ self'. La condición de prueba prueba el nombre de la etiqueta; el analizador en sí mismo se ocupará de '<'. – Amadan

+0

si el 'si' cuenta, entonces veo cinco turnos. Dos de ellos en una condición. Si solo hay tres, los cambios de condición no sacan algo de la matriz o? – froehli

5

Uso HTML::TokeParser::Simple.

código ensayada basándose en su descripción:

#!/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

HTML :: Parser es más de un señalizador de un analizador. Deja mucho trabajo duro para ti. ¿Ha considerado usar HTML::TreeBuilder (que usa HTML :: Parser) o XML::LibXML (una gran biblioteca que admite HTML)?

3

No hay necesidad de ser tan complicado. Puede recuperar y encontrar elementos en el DOM utilizando CSS selectors con Mojo::UserAgent:

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

o, bucle a través de los elementos encontrados:

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

o bucle que utiliza una devolución de llamada:

Mojo::UserAgent->new->get('http://f.oo')->res->dom->find('div.foo')->each(sub { 
    my ($count, $el) = @_; 
    say "$count: $el"; 
}); 
+0

Parece que mi Mac no tiene Mojo :: UserAgent instalado, lo que significa que nuestro servidor web tampoco tiene esto. Lo mismo para TokeParser :: Simple. Pero de todos modos. Descubrí que el sitio para analizar no es apropiado xhtml, así que tengo que tomar el camino por mi cuenta. – froehli

+0

Mojo :: UserAgent no es parte del núcleo, pero es simple de instalar: "curl -L cpanmin.us | perl - Mojolicious". Si te estás limitando al núcleo, te estás perdiendo el principal beneficio de Perl, lo que sería desafortunado. Además, si sus documentos son cualquier forma de HTML, Mojo :: DOM debería manejarlo; está destinado para el uso en el mundo real, no para etiquetas xml estrictas. – tempire

Cuestiones relacionadas