Как я могу рекурсивно посещать ссылки без повторного просмотра ссылок? - PullRequest
0 голосов
/ 22 мая 2009

Я хочу проверить сайт на наличие ссылок, а затем рекурсивно проверить эти сайты на наличие ссылок. Но я не хочу получать одну и ту же страницу дважды. У меня проблемы с логикой. Это код Perl:

my %urls_to_check = ();
my %checked_urls = ();

&fetch_and_parse($starting_url);

use Data::Dumper; die Dumper(\%checked_urls, \%urls_to_check);

sub fetch_and_parse {
    my ($url) = @_;

    if ($checked_urls{$url} > 1) { return 0; }
    warn "Fetching 'me' links from $url";

    my $p = HTML::TreeBuilder->new;

    my $req = HTTP::Request->new(GET => $url);
    my $res = $ua->request($req, sub { $p->parse($_[0])});
    $p->eof();

    my $base = $res->base;

    my @tags = $p->look_down(
        "_tag", "a",
    );

    foreach my $e (@tags) {
        my $full = url($e->attr('href'), $base)->abs;
        $urls_to_check{$full} = 1 if (!defined($checked_urls{$full}));
    }

    foreach my $url (keys %urls_to_check) {
        delete $urls_to_check{$url};
        $checked_urls{$url}++;
        &fetch_and_parse($url);
    }
}

Но, похоже, это не то, что я хочу.

Помощь?! * * 1006

РЕДАКТИРОВАТЬ : Я хочу получить URL-адреса из $starting_url, а затем получить все URL-адреса из полученных выборок. Но если один из URL-адресов ссылается на $starting_url, я не хочу получать его снова.

Ответы [ 5 ]

9 голосов
/ 22 мая 2009

Самое простое, что можно сделать, это не изобретать велосипед и использовать CPAN .

2 голосов
/ 26 мая 2009

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

my @need_to_check   = ( ... ); # however you make that list
my %already_checked = ();

while( my $link = shift @need_to_check )
    {
    next if exists $already_checked{$link};
    ...;
    $already_checked{$link}++;
    }

Ситуация несколько сложнее с URL-адресами, которые выглядят немного по-другому, но заканчиваются на том же ресурсе, как http://example.com, http://www.example.com, http://www.example.com/, и так далее. Если бы я заботился об этом, я бы добавил шаг нормализации, создав для каждого объект URI, а затем снова вытащил URL-адрес в виде строки. Если бы это была более серьезная проблема, я бы также посмотрел URL-адрес, который, как утверждали заголовки ответа, я получил (например, с помощью перенаправления и т. Д.) И отметил, что я их тоже видел.

2 голосов
/ 23 мая 2009

Я бы предположил, что проблема в том, что

foreach my $url (keys %urls_to_check) {...}

не повторяется так, как вы думаете. Для каждого восстанавливаемого URL вы должны рекурсивно вызывать свою функцию еще раз, что очень неэффективно для памяти.

Несмотря на то, что вы пишете программу для "рекурсивного" сканирования веб-страниц, в вашем коде вам нужно использовать итерацию, а не рекурсию:

sub fetch_and_parse {
    my ($url) = @_;
    $urls_to_check{$url} = 1;
    while(%urls_to_check) {
        // Grab a URL and process it, putting any new URLs you find into urls_to_check
    }
  }

Конечно, как отмечали другие авторы, есть и другие инструменты, которые могут автоматизировать это для вас.

0 голосов
/ 24 мая 2009

может быть, это может вам помочь: blog.0x53a.de/where-do-my-links-go/ Он выполняет поиск в ширину, начиная с данного веб-сайта. Также вам может быть интересен используемый модуль HTML :: LinkExtractor.

С уважением, Manuel

0 голосов
/ 23 мая 2009

Если вы хотите извлечь все ссылки со страницы, я рекомендую использовать LinkExtor от Gisle Aas, и быстрый поиск CPAN покажет вам это. Затем вы можете рекурсивно пройти по найденным ссылкам, выдвинув их в список и вытолкнув их, проверив сначала, прежде чем переходить к ним, если вы уже посетили их, используя хеш, как вы это сделали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...