Jak mogę wyodrębnić URL i link tekst z HTML w Perlu?

Wcześniej pytałem, jak to zrobić w Groovy. Jednak teraz przepisuję moją aplikację w Perlu ze względu na wszystkie biblioteki CPAN.

Jeśli strona zawierała te linki:

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

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

Wyjście będzie:

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

Jaki jest najlepszy sposób, aby to zrobić w Perlu?

Author: Brad Gilbert, 2008-10-31

11 answers

Prosimy o zapoznanie się z Modułem WWW::Mechanize . Pobierze za Ciebie Twoje strony internetowe, a następnie zapewni Ci łatwą pracę z listami adresów 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;
}

Całkiem proste, a jeśli chcesz przejść do innych adresów URL na tej stronie, jest jeszcze prostsze.

Mech jest w zasadzie przeglądarką w obiekcie.
 40
Author: Andy Lester,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-31 20:04:34

Spójrz na HTML::LinkExtractor i HTML::LinkExtor, część pakietu HTML::Parser.

HTML:: LinkExtractor jest podobny do HTML:: LinkExtor, z tą różnicą, że oprócz uzyskania adresu URL, otrzymujesz również tekst linku.

 11
Author: Sherm Pendley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-25 10:55:51

Jeśli jesteś poszukiwaczem przygód i chcesz spróbować bez modułów, coś takiego powinno zadziałać (dostosuj to do swoich potrzeb):

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

Jest prawdopodobnie kilka rzeczy, które zrobiłem źle, ale działa to w kilku przypadkach testowych, które próbowałem po napisaniu (nie uwzględnia rzeczy takich jak tagi itp.).

 6
Author: Aaron Graves,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-04 20:39:14

Lubię używać pQuery do takich rzeczy...

use pQuery;

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

Również sprawdź ten poprzedni stackoverflow.com question Emulacja funkcji lex like w Perlu lub Pythonie dla podobnych odpowiedzi.

 6
Author: draegtun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:17:42

Innym sposobem na to jest użycie XPath do odpytywania przetworzonego HTML. Jest to potrzebne w skomplikowanych przypadkach, takich jak wyodrębnienie wszystkich linków w div z określoną klasą. W tym celu użyj 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');
  }
 5
Author: Alexandr Ciornii,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-05 17:49:25

Sherm recommended HTML:: LinkExtor , czyli prawie to, czego chcesz. Niestety, nie można zwrócić tekstu wewnątrz znacznika .

Andy poleca WWW:: Mechanize . To chyba najlepsze rozwiązanie.

Jeśli nie podoba ci się Strona WWW::Mechanize, spróbuj HTML::TreeBuilder. Zbuduje drzewo podobne do DOM z HTML, które można następnie wyszukać linki, które chcesz i wyodrębnić dowolną pobliską zawartość chcesz.
 4
Author: cjm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:01

Lub rozważ ulepszenie HTML:: LinkExtor, aby zrobić to, co chcesz i przesłać zmiany do autora.

 4
Author: ysth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-02 02:43:11

Poprzednie odpowiedzi były całkiem dobre i Wiem, że jestem spóźniony na imprezę, ale to wpadło w kanał [perl], więc ...

XML:: LibXML jest doskonały do parsowania HTML i nie do pobicia pod względem szybkości. Ustawia opcję recover podczas parsowania źle uformowanego HTML.

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>

–{–4]}

     Google -> http://www.google.com
      Apple -> http://www.apple.com
 4
Author: Ashley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-22 23:10:38

HTML:: LinkExtractor jest lepszy / a niż HTML:: LinkExtor

Może podać zarówno tekst linku, jak i adres URL.

Użycie:

 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";
        }
    }
 3
Author: user13107,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-25 11:00:18

HTML jest strukturalnym językiem znaczników, który musi być parsowany, aby wydobyć jego znaczenie bez błędów. Wymieniony moduł Sherm przetworzy kod HTML i wyodrębni linki dla Ciebie. Rozwiązania ad hoc oparte na wyrażeniach regularnych mogą być akceptowalne, jeśli wiesz, że Twoje dane wejściowe będą zawsze tworzone w ten sam sposób( nie zapomnij o atrybutach), ale parser jest prawie zawsze właściwą odpowiedzią na przetwarzanie tekstu strukturalnego.

 2
Author: converter42,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-31 18:49:00

Możemy użyć wyrażenia regularnego, aby wyodrębnić link z jego tekstem. Jest to również jedyny sposób.

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>
 -1
Author: Deiveegaraja Andaver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-29 09:36:48