2011-12-19 12 views
6

Voglio analizzare un sito Web in una struttura dati Perl. primo passo per caricare la pagina conCome analizzare tra <div class ="foo"> and</div> facilmente in Perl

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

Ora so due modi per affrontare con esso. Prima sono le espressioni regolari e il secondo i moduli.

Ho iniziato a leggere su HTML::Parser e ho trovato alcuni esempi. Ma non sono sicuro della conoscenza di Perl.

Il mio esempio di codice va avanti

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

non capisco il motivo per cui ci sono due volte un turno. Il secondo dovrebbe essere l'auto puntatore. Ma il primo mi fa pensare che l'auto riferimento sia già spostato, usato come un hash e il valore per href è memorizzato in $class. Qualcuno potrebbe spiegare questa riga (my ($class) = shift->{href};)?

Accanto a questa mancanza, non voglio per analizzare tutti gli URL, voglio mettere tutto il codice tra <div class ="foo"> e </div> in una stringa, dove un sacco di codice è tra, specialmente altri <div></div> tag. Quindi io o un modulo dobbiamo trovare l'estremità giusta. Dopo di che ho programmato di eseguire la scansione di nuovo la stringa, per trovare classi speciali, come <h1>,<h2>, <p class ="foo2"></p>, ecc

Spero che queste informazioni ti aiuta a darmi alcuni consigli utili, e vi prego di avere in mente che prima di tutto voglio un modo semplice di comprensione, che non deve essere una grande prestazione nel primo livello!

+5

DON 'USARE ESPRESSIONI REGOLARI! HTML NON È REGOLARE! –

+5

Come rinfrescante vedere qualcuno che usa un parser HTML per analizzare HTML invece di espressioni regolari: p +1 solo per quello – fge

+1

FWIW: 'my ($ class) = shift -> {href};' <- significa prendere il 'href' membro dell'hash dell'argomento spostato. Potrebbe essere stato scritto 'my $ ref = shift; my $ class = $ ref -> {"href"}; ' – fge

risposta

1

Secondo i documenti, la firma del gestore è (\%attr, \@attr_seq, $text). Ci sono tre turni, uno per ogni argomento.

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

è 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

L'ho ottenuto. Ma cos'è la condizione? Non chiama un altro turno? E perché è solo un 'a' quando inizia con '... froehli

+0

Come ho detto, ci sono tre turni in là, non due: uno in 'if', uno per gli attributi (uno dei quali viene assegnato a' $ class'), e uno per quello che diventa '$ self'. La condizione di test verifica il nome del tag - il parser stesso si prenderà cura di '<'. – Amadan

+0

se il 'if' conti, poi vedo cinque turni. Due di loro in una condizione. Se ci sono solo tre, allora i cambiamenti di condizione non estraggono qualcosa dall'array, o? – froehli

5

Usa HTML::TokeParser::Simple.

codice non testato in base alla descrizione:

#!/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 è più di un tokenizer di un parser. Lascia un sacco di duro lavoro a voi. Hai preso in considerazione l'utilizzo di HTML::TreeBuilder (che utilizza HTML :: Parser) o XML::LibXML (una grande libreria che supporta HTML)?

3

Non c'è bisogno di complicarsi così tanto. È possibile recuperare e trovare elementi nel DOM utilizzando CSS selectors con Mojo::UserAgent:

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

o, scorrere gli elementi trovati:

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

o, ciclo usando una richiamata:

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

Sembra che sul mio Mac non sia installato Mojo :: UserAgent, il che significa che anche il nostro server web non ha questo. Lo stesso per TokeParser :: Semplice. Ma in ogni caso. Ho scoperto che il sito da analizzare non è corretto xhtml, quindi devo prendere la strada da solo. – froehli

+0

Mojo :: UserAgent non fa parte del core, ma è semplice da installare: "curl -L cpanmin.us | perl - Mojolicious". Se stai limitando te stesso al nucleo, ti stai perdendo il principale vantaggio di Perl, che sarebbe sfortunato. Inoltre, se i tuoi documenti sono qualsiasi forma di HTML, Mojo :: DOM dovrebbe gestirli; è pensato per l'uso nel mondo reale, non per i tag xml rigidi. – tempire

Problemi correlati