2008-10-31 74 views
19

Trước đây tôi đã hỏi cách thực hiện điều này trong Groovy. Tuy nhiên, bây giờ tôi đang viết lại ứng dụng của mình trong Perl vì tất cả các thư viện CPAN.Làm cách nào để trích xuất URL và văn bản liên kết từ HTML trong Perl?

Nếu trang chứa những liên kết này:

 
<a href="http://www.google.com">Google</a> 

<a href="http://www.apple.com">Apple</a> 

Kết quả sẽ là:

 
Google, http://www.google.com 
Apple, http://www.apple.com 

cách tốt nhất để làm điều này trong Perl là gì?

Trả lời

39

Vui lòng xem xét sử dụng mô-đun WWW::Mechanize cho việc này. Nó sẽ lấy các trang web của bạn cho bạn, và sau đó cung cấp cho bạn dễ dàng làm việc với danh sách các URL.

my $mech = WWW::Mechanize->new(); 
$mech->get($some_url); 
my @links = $mech->links(); 
for my $link (@links) { 
    printf "%s, %s\n", $link->text, $link->url; 
} 

Khá đơn giản và nếu bạn muốn điều hướng đến các URL khác trên trang đó, nó thậm chí còn đơn giản hơn.

Mech về cơ bản là trình duyệt trong một đối tượng.

+2

Tôi đã tự do thay đổi tuyên bố in để bao gồm văn bản liên kết, như được yêu cầu bằng cách kể. – cjm

11

Hãy xem HTML::LinkExtractorHTML::LinkExtor, một phần của gói HTML::Parser.

HTML :: LinkExtractor tương tự như HTML :: LinkExtor, ngoại trừ việc ngoài việc nhận URL, bạn cũng nhận được văn bản liên kết.

+1

Thật không may, HTML :: LinkExtor không thể cung cấp cho bạn các văn bản bên trong thẻ , mà ông nói rằng ông là quan tâm đến Nó chỉ cho bạn biết tên thẻ và các thuộc tính của nó.. – cjm

+0

@cjm: Tôi đã thêm liên kết vào HTML :: LinkExtractor tạo văn bản liên kết ngoài các URL. –

2

HTML là ngôn ngữ đánh dấu có cấu trúc phải được phân tích cú pháp để trích xuất ý nghĩa của nó mà không có lỗi. Mô-đun Sherm được liệt kê sẽ phân tích cú pháp HTML và trích xuất các liên kết cho bạn. Các giải pháp dựa trên cụm từ thông dụng có thể chấp nhận được nếu bạn biết rằng các yếu tố đầu vào của bạn sẽ luôn được hình thành theo cùng một cách (đừng quên thuộc tính), nhưng một trình phân tích cú pháp hầu như luôn là câu trả lời đúng để xử lý văn bản có cấu trúc.

6

Tôi thích sử dụng pQuery cho những thứ như thế này ...

use pQuery; 

pQuery('http://www.perlbuzz.com')->find('a')->each(
    sub { 
     say $_->innerHTML . q{, } . $_->getAttribute('href'); 
    } 
); 

Cũng kiểm này câu hỏi stackoverflow.com trước Emulation of lex like functionality in Perl or Python cho câu trả lời tương tự.

4

Sherm được đề xuất HTML::LinkExtor, gần như bạn muốn. Thật không may, nó không thể trả lại văn bản bên trong thẻ < a>.

Andy được đề xuất WWW::Mechanize. Đó có lẽ là giải pháp tốt nhất.

Nếu bạn thấy rằng WWW :: Cơ chế hóa không theo ý thích của bạn, hãy thử HTML::TreeBuilder. Nó sẽ xây dựng một cây giống như DOM ra khỏi HTML, sau đó bạn có thể tìm kiếm các liên kết bạn muốn và trích xuất bất kỳ nội dung nào gần đó mà bạn muốn.

4

Hoặc xem xét tăng cường HTML :: LinkExtor để thực hiện những gì bạn muốn và gửi các thay đổi cho tác giả.

+0

HTML :: LinkExtractor đã làm những gì bạn đề xuất. –

5

Cách khác để thực hiện việc này là sử dụng XPath để truy vấn HTML được phân tích cú pháp. Nó là cần thiết trong các trường hợp phức tạp, như trích xuất tất cả các liên kết trong div với lớp cụ thể. Sử dụng HTML :: TreeBuilder :: XPath cho việc này.

my $tree=HTML::TreeBuilder::XPath->new_from_content($c); 
    my $nodes=$tree->findnodes(q{//map[@name='map1']/area}); 
    while (my $node=$nodes->shift) { 
    my $t=$node->attr('title'); 
    } 
+2

Ngoài ra, thêm $ tree-> delete để tránh rò rỉ bộ nhớ. –

4

câu trả lời trước là hoàn toàn tốt và tôi biết tôi là muộn để bên nhưng điều này đã tình cờ gặp trong [perl] ăn như vậy ...

XML::LibXML là tuyệt vời cho phân tích cú pháp HTML và cạnh tranh nhất cho tốc độ. Đặt tùy chọn recover khi phân tích cú pháp HTML được định dạng sai.

use XML::LibXML; 

my $doc = XML::LibXML->load_html(IO => \*DATA); 
for my $anchor ($doc->findnodes("//a[\@href]")) 
{ 
    printf "%15s -> %s\n", 
     $anchor->textContent, 
     $anchor->getAttribute("href"); 
} 

__DATA__ 
<html><head><title/></head><body> 
<a href="http://www.google.com">Google</a> 
<a href="http://www.apple.com">Apple</a> 
</body></html> 

-yields-

 Google -> http://www.google.com 
     Apple -> http://www.apple.com 
6

Nếu bạn thích mạo hiểm và muốn thử mà không cần mô-đun, một cái gì đó như thế này nên làm việc (điều chỉnh nó cho nhu cầu của bạn):

#!/usr/bin/perl 

if($#ARGV < 0) { 
    print "$0: Need URL argument.\n"; 
    exit 1; 
} 

my @content = split(/\n/,`wget -qO- $ARGV[0]`); 
my @links = grep(/<a.*href=.*>/,@content); 

foreach my $c (@links){ 
    $c =~ /<a.*href="([\s\S]+?)".*>/; 
    $link = $1; 
    $c =~ /<a.*href.*>([\s\S]+?)<\/a>/; 
    $title = $1; 
    print "$title, $link\n"; 
} 

Có có thể một vài điều tôi đã làm sai ở đây, nhưng nó hoạt động trong một số ít các trường hợp thử nghiệm mà tôi đã thử sau khi viết nó (nó không tính đến những thứ như <img> thẻ, v.v.).

+0

bạn là bậc thầy, bạn đã tiết kiệm rất nhiều thời gian cho tôi .. cảm ơn một tấn. – run

-1

Chúng tôi có thể sử dụng cụm từ thông dụng để trích xuất liên kết với văn bản liên kết của nó. Đây cũng là một cách.

local $/ = ''; 
my $a = <DATA>; 

while($a =~ m/<a[^>]*?href=\"([^>]*?)\"[^>]*?>\s*([\w\W]*?)\s*<\/a>/igs) 
{ 
    print "Link:$1 \t Text: $2\n"; 
} 


__DATA__ 

<a href="http://www.google.com">Google</a> 

<a href="http://www.apple.com">Apple</a> 
3

HTML::LinkExtractor là tốt hơn so với HTML :: LinkExtor

Nó có thể cung cấp cho cả hai văn bản liên kết và URL.

Cách sử dụng:

use HTML::LinkExtractor; 
my $input = q{If <a href="http://apple.com/"> Apple </a>}; #HTML string 
my $LX = new HTML::LinkExtractor(undef,undef,1); 
$LX->parse(\$input); 
for my $Link(@{ $LX->links }) { 
     if($$Link{_TEXT}=~ m/Apple/) { 
      print "\n LinkText $$Link{_TEXT} URL $$Link{href}\n"; 
     } 
    } 
Các vấn đề liên quan