Как извлечь URL и ссылку на текст из HTML в Perl?

Ранее я спросил, как это сделать в Groovy. Однако теперь я переписываю свое приложение в Perl из-за всех библиотек CPAN.

Если страница содержит эти ссылки:

<a href="#" onclick="location.href='http://www.google.com'; return false;">Google</a>

<a href="#" onclick="location.href='http://www.apple.com'; return false;">Apple</a>

Вывод будет:

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

Каков наилучший способ сделать это в Perl?

Ответы

Ответ 1

Пожалуйста, посмотрите на использование WWW:: Mechanize для этого. Он будет получать ваши веб-страницы для вас, а затем даст вам возможность работать со списками 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;
}

Довольно просто, и если вы хотите перейти к другим URL-адресам на этой странице, это еще проще.

Механизм - это в основном браузер в объекте.

Ответ 2

Посмотрите HTML::LinkExtractor и HTML::LinkExtor, часть пакета HTML:: Parser.

HTML:: LinkExtractor похож на HTML:: LinkExtor, за исключением того, что помимо получения URL-адреса вы также получаете текст-ссылку.

Ответ 3

Мне нравится использовать pQuery для таких вещей...

use pQuery;

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

Также проверьте этот предыдущий вопрос stackoverflow.com Эмуляция функций, похожих на lex, в Perl или Python для аналогичных ответов.

Ответ 4

Если вы предприимчивы и хотите попробовать без модулей, что-то вроде этого должно работать (адаптируйте его к вашим потребностям):

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

Вероятно, некоторые вещи я сделал неправильно, но он работает в нескольких тестовых случаях, которые я пробовал после написания (он не учитывает такие вещи, как теги <img> и т.д.).

Ответ 5

Другой способ сделать это - использовать XPath для запроса проанализированного HTML. Это необходимо в сложных случаях, таких как извлечение всех ссылок в div с определенным классом. Для этого используйте 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');
  }

Ответ 6

Шерм рекомендовал HTML::LinkExtor, что почти то, что вы хотите. К сожалению, он не может вернуть текст внутри тега <a> .

Энди рекомендовал WWW::Mechanize. Это, вероятно, лучшее решение.

Если вы обнаружите, что WWW:: Mechanize вам не по душе, попробуйте HTML:: TreeBuilder. Он построит DOM-подобное дерево из HTML, после чего вы сможете искать нужные вам ссылки и извлекать любой контент, который вы хотите.

Ответ 7

Или рассмотрите возможность улучшения HTML:: LinkExtor для выполнения того, что вы хотите, и отправки изменений автору.

Ответ 8

Предыдущие ответы были совершенно хорошими, и я знаю, что я опаздываю на вечеринку, но это наткнулось на фишку [perl], поэтому...

XML:: LibXML отлично подходит для разбора HTML и непревзойденного для скорости. Установите параметр recover при разборе плохо сформированного 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>

-yields -

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

Ответ 9

HTML:: LinkExtractor лучше, чем HTML:: LinkExtor

Он может содержать как текст ссылки, так и URL.

Использование:

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

Ответ 10

HTML - это структурированный язык разметки, который необходимо проанализировать, чтобы извлечь его значение без ошибок. Перечисленный модуль Sherm будет анализировать HTML и извлекать ссылки для вас. Специальные решения на основе регулярных выражений могут быть приемлемыми, если вы знаете, что ваши входы всегда будут сформированы одинаково (не забывайте атрибуты), но парсер почти всегда является правильным ответом для обработки структурированного текста.

Ответ 11

Мы можем использовать регулярное выражение для извлечения ссылки со своим текстом ссылки. Это также один из способов.

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="#" onclick="location.href='http://www.google.com'; return false;">Google</a>

<a href="#" onclick="location.href='http://www.apple.com'; return false;">Apple</a>