Ранее я спрашивал, как это сделать в Groovy. Однако сейчас я переписываю свое приложение на Perl из-за наличия всех библиотек CPAN.
Если на странице были эти ссылки:
<a href = "http://www.google.com">Google</a> <a href = "http://www.apple.com">Apple</a>
Результатом будет:
Google, http://www.google.com Apple, http://www.apple.com
Как лучше всего это сделать в Perl?






Взгляните на HTML :: LinkExtractor и HTML :: LinkExtor, часть пакета HTML :: Парсер.
HTML :: LinkExtractor похож на HTML :: LinkExtor, за исключением того, что помимо получения URL-адреса вы также получаете текст ссылки.
@cjm: я добавил ссылку на HTML :: LinkExtractor, которая создает текст ссылки в дополнение к URL-адресам.
HTML - это структурированный язык разметки, который необходимо анализировать, чтобы без ошибок извлекать его значение. Указанный модуль Sherm проанализирует HTML и извлечет ссылки за вас. Специальные решения на основе регулярных выражений могут быть приемлемыми, если вы знаете, что ваши входные данные всегда будут формироваться одинаково (не забывайте атрибуты), но синтаксический анализатор почти всегда является правильным ответом для обработки структурированного текста.
Мне нравится использовать pQuery для таких вещей ...
use pQuery;
pQuery( 'http://www.perlbuzz.com' )->find( 'a' )->each(
sub {
say $_->innerHTML . q{, } . $_->getAttribute( 'href' );
}
);
Также ознакомьтесь с этим предыдущим вопросом stackoverflow.com Эмуляция lex-подобной функциональности в Perl или Python для получения аналогичных ответов.
Пожалуйста, посмотрите, как использовать для этого модуль 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-адресам на этой странице, это еще проще.
Механизм - это, по сути, браузер в объекте.
Я взял на себя смелость изменить оператор печати, включив в него текст ссылки, как того требует melling.
Шерм рекомендовал HTML :: LinkExtor, что почти то, что вы хотите. К сожалению, он не может вернуть текст внутри тега <a>.
Энди рекомендуется WWW :: Mechanize. Это, наверное, лучшее решение.
Если вы обнаружите, что WWW :: Mechanize вам не нравится, попробуйте HTML :: TreeBuilder. Он построит DOM-подобное дерево из HTML, в котором вы затем сможете искать нужные ссылки и извлекать любой ближайший контент, который вам нужен.
Или подумайте о том, чтобы улучшить HTML :: LinkExtor, чтобы он делал то, что вы хотите, и отправьте изменения автору.
Другой способ сделать это - использовать 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');
}
Также добавьте $ tree-> delete, чтобы избежать утечки памяти.
Предыдущие ответы были очень хорошими, и я знаю, что опаздываю на вечеринку, но это попало в ленту [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
Если вы любите приключения и хотите попробовать без модулей, должно сработать что-то вроде этого (адаптируйте его под свои нужды):
#!/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> и т. д.).
ты хозяин, ты сэкономил мне много времени .. спасибо за тонну.
Мы можем использовать регулярное выражение для извлечения ссылки с ее текстом. Это тоже один путь.
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>
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";
}
}
К сожалению, HTML :: LinkExtor не может предоставить вам текст внутри тега <a>, который, по его словам, его интересует. Он сообщает вам только имя тега и его атрибуты.