2011-12-19 24 views
6

Tôi muốn phân tích một Trang web thành cấu trúc dữ liệu Perl. Trước tiên tôi tải trang bằngCách phân tích giữa <div class ="foo"> and</div> dễ dàng trong Perl

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

Bây giờ tôi biết hai cách để giải quyết. Đầu tiên là các biểu thức chính quy và giữ chặt các mô-đun.

Tôi bắt đầu đọc khoảng HTML::Parser và tìm thấy một số ví dụ. Nhưng tôi không chắc chắn về kiến ​​thức của Perl.

mã ví dụ của tôi đi trên

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

Tôi không hiểu tại sao có hai lần một sự thay đổi. Các secound nên là con trỏ tự. Nhưng đầu tiên làm cho tôi nghĩ rằng tham chiếu tự là allready shiftet, được sử dụng như một Hash và Value cho href được lưu trữ trong $class. Ai đó có thể Giải thích dòng này (my ($class) = shift->{href};)?

Bên cạnh sự thiếu này, tôi không muốn phân tích tất cả các URL, tôi muốn đặt tất cả mã giữa <div class ="foo"></div> thành chuỗi, trong đó có nhiều mã nằm giữa các thẻ <div></div>. Vì vậy, tôi hoặc một mô-đun phải tìm đúng điểm. Sau đó tôi đã lên kế hoạch quét chuỗi lần nữa, để tìm các lớp đặc biệt, như <h1>,<h2>, <p class ="foo2"></p>, v.v.

Tôi hy vọng thông tin này sẽ giúp bạn cung cấp cho tôi một số lời khuyên hữu ích và xin lưu ý rằng trước hết tôi muốn cách hiểu dễ hiểu, không phải là một hoạt động tuyệt vời ở cấp độ đầu tiên!

+5

DON 'T SỬ DỤNG THƯỜNG XUYÊN NÀY! HTML KHÔNG CHẤP NHẬN! –

+5

Cách làm mới để xem ai đó sử dụng trình phân tích cú pháp HTML để phân tích cú pháp HTML thay vì regexes: p +1 chỉ cho rằng – fge

+1

FWIW: 'my ($ class) = shift -> {href};' <- nghĩa là lấy 'href' thành viên băm của đối số đã dịch chuyển. Có thể đã được viết 'my $ ref = shift; $ class = $ ref -> {"href"}; ' – fge

Trả lời

1

Theo tài liệu, chữ ký của người xử lý là (\%attr, \@attr_seq, $text). Có ba ca, một ca cho mỗi đối số.

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

tương đương với:

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

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

Tôi đã hiểu điều đó. Nhưng điều gì về tình trạng này? Liệu nó không gọi một sự thay đổi khác? Và tại sao nó chỉ là 'a' khi nó bắt đầu bằng '... froehli

+0

Như tôi đã nói, có ba thay đổi trong đó, không phải hai: một trong 'if', một cho các thuộc tính (một trong số đó được gán cho' $ class'), và một cho những gì trở thành '$ tự'. Kiểm tra điều kiện kiểm tra cho tên thẻ - chính trình phân tích cú pháp sẽ xử lý '<'. – Amadan

+0

nếu 'if'counts, thì tôi thấy năm ca. Hai trong số họ trong tình trạng. Nếu chỉ có ba, thì điều kiện thay đổi không kéo cái gì đó ra khỏi mảng, hay? – froehli

5

Sử dụng HTML::TokeParser::Simple.

đang chưa được kiểm tra dựa trên mô tả của bạ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 là chi tiết của một tokenizer hơn một phân tích cú pháp. Nó để lại rất nhiều công việc khó khăn cho bạn. Bạn có cân nhắc sử dụng HTML::TreeBuilder (sử dụng HTML :: Trình phân tích cú pháp) hoặc XML::LibXML (một thư viện tuyệt vời có hỗ trợ HTML) không?

3

Không cần quá phức tạp. Bạn có thể lấy và tìm các yếu tố trong DOM bằng CSS selectors với Mojo::UserAgent:

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

hoặc, vòng lặp thông qua các yếu tố được tìm thấy:

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

hoặc, vòng lặp sử dụng một callback:

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

Dường như máy Mac của tôi không có cài đặt Mojo :: UserAgent, nghĩa là máy chủ web của chúng tôi cũng không có. Tương tự cho TokeParser :: Đơn giản. Nhưng dù sao. Tôi phát hiện ra rằng các trang web để phân tích cú pháp không phải là xhtml thích hợp, vì vậy tôi đã phải thực hiện theo cách của riêng tôi. – froehli

+0

Mojo :: UserAgent không phải là một phần của lõi, nhưng nó đơn giản để cài đặt: "curl -L cpanmin.us | perl - Mojolicious". Nếu bạn đang giới hạn bản thân, bạn sẽ bỏ lỡ lợi ích chính của Perl, điều này thật không may. Ngoài ra, nếu tài liệu của bạn là bất kỳ dạng HTML nào, Mojo :: DOM sẽ xử lý nó; nó có nghĩa là sử dụng trong thế giới thực, không phải thẻ xml nghiêm ngặt. – tempire

Các vấn đề liên quan