2008-10-31 6 views
19

Ich fragte vorher, wie man das in Groovy macht. Jetzt schreibe ich meine App in Perl wegen aller CPAN-Bibliotheken um.Wie kann ich URL und Link-Text aus HTML in Perl extrahieren?

Wenn die Seite enthält diese Links:

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

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

Der Ausgang wäre:

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

Was ist der beste Weg, dies in Perl zu tun?

Antwort

39

Bitte verwenden Sie hierzu das Modul WWW::Mechanize. Es wird Ihre Webseiten für Sie abrufen und Ihnen dann die Arbeit mit URL-Listen erleichtern.

Ziemlich einfach, und wenn Sie zu anderen URLs auf dieser Seite navigieren möchten, ist es noch einfacher.

Mech ist im Grunde ein Browser in einem Objekt.

+2

Ich habe mir die Freiheit genommen, die print-Anweisung so zu ändern, dass sie den Linktext enthält, wie von melling angefordert. – cjm

11

Werfen Sie einen Blick auf HTML::LinkExtractor und HTML::LinkExtor, Teil des HTML::Parser Pakets.

HTML :: LinkExtractor ist ähnlich wie HTML :: LinkExtor, außer dass Sie neben der URL auch den Link-Text erhalten.

+1

Leider HTML :: LinkExtor können Sie nicht geben den Text innerhalb des Tag, die er sagt, er interessiert ist Es sagt Ihnen, nur den Tag-Namen und seine Attribute.. – cjm

+0

@cjm: Ich habe einen Link zu HTML :: LinkExtractor hinzugefügt, der zusätzlich zu den URLs den Linktext erzeugt. –

2

HTML ist eine strukturierte Auszeichnungssprache, die analysiert werden muss, um ihre Bedeutung ohne Fehler zu extrahieren. Das aufgelistete Modul Sherm analysiert den HTML-Code und extrahiert die Links für Sie. Ad-hoc-Lösungen, die auf regulären Ausdrücken basieren, sind möglicherweise akzeptabel, wenn Sie wissen, dass Ihre Eingaben immer auf die gleiche Weise gebildet werden (Attribute nicht vergessen), aber ein Parser ist fast immer die richtige Antwort für die Verarbeitung von strukturiertem Text.

4

Sherm empfohlen HTML::LinkExtor, die fast, was Sie wollen. Leider kann es den Text innerhalb des < a> Tags nicht zurückgeben.

Andy empfohlen WWW::Mechanize. Das ist wahrscheinlich die beste Lösung.

Wenn Sie feststellen, dass WWW :: Mechanize ist nicht nach Ihrem Geschmack, versuchen HTML::TreeBuilder. Es wird eine DOM-ähnliche Struktur aus dem HTML-Code erstellt, die Sie dann nach den gewünschten Links durchsuchen und alle in der Nähe befindlichen Inhalte extrahieren können.

4

Oder erwägen Sie, HTML :: LinkExtor zu verbessern, um zu tun, was Sie wollen, und die Änderungen dem Autor zu übermitteln.

+0

HTML :: LinkExtractor tut bereits, was Sie vorgeschlagen haben. –

5

Eine andere Möglichkeit ist, XPath zu verwenden, um geparstes HTML abzufragen. Es ist in komplexen Fällen erforderlich, wie alle Links in div mit bestimmten Klassen extrahieren. Verwenden Sie hierfür HTML :: TreeBuilder :: XPath.

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

Fügen Sie außerdem ein $ tree-> delete hinzu, um Speicherlecks zu vermeiden. –

4

Vorherige Antworten waren vollkommen gut und ich weiß, ich bin spät zur Party, aber dies wurde in dem [Perl] gestoßen füttert so ...

XML::LibXML ist hervorragend für die HTML-Analyse und unschlagbar für die Geschwindigkeit. Stellen Sie recover Option ein, wenn Sie schlecht formatiertes HTML analysieren.

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

Wenn Sie abenteuerlich sind und wollen ohne Module, um zu versuchen, wie etwas, das sollte (es an Ihre Bedürfnisse anpassen) arbeiten:

#!/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"; 
} 

Es gibt wahrscheinlich ein paar Dinge, die ich hier falsch gemacht habe, aber es funktioniert in einer Handvoll von Testfällen, die ich nach dem Schreiben versuchte (es berücksichtigt nicht Dinge wie <img> Tags, etc).

+0

Sie sind der Meister, Sie haben viel Zeit für mich gerettet..thanks eine Tonne. – run

-1

Wir können regulären Ausdruck verwenden, um den Link mit seinem Linktext zu extrahieren. Dies ist auch der eine Weg.

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 ist besser als HTML :: LinkExtor

Es kann sowohl Linktext und URL geben.

Verbrauch:

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