-1

私はいくつかのhtmlドキュメントに取り組んでおり、それぞれにリンクのリストがあり、開いたときの各リンクには別のリンクのリストがありますが、リンクの各リストには別のリストからのリンクが含まれている可能性があり、リンクが1つだけのハッシュ配列があります最初my %list = ($link1 => 1);に、これまでに行ったことは、既存のリンクを開き、html ドキュメント内のすべてのリンクをループすることです (次のコードは、リンクの html コンテンツを解析した変数 $tree を示しています)。

for my $node ( $tree->look_down('_tag' => 'a'))
{
next unless $node;

my $link = $node->attr('href');
unless(exists($list{$link}))
{
    $list{$link} = 1;
}
}       

今私がやりたいことは、新しいリンクが表示されるたびにフィードされているハッシュテーブルをループすることです。

私がはっきりしていることを願っています。

編集 :

これは私がリンクを取得しているページです。リストから 1 つのリンクを選択すると、別のリストにないリンクが存在することがあります。そのため、さまざまなリストからすべてのリンクがあることを確認するには、各リンクを開き、リストをループし、新しいリンクがあればハッシュ配列に追加します。

より明確にするために、私のアルゴリズムは次のとおりです。

  • 私は 1 つのリンクを持つハッシュ テーブルを持っていmy %list = ($link1 => 1);ます。値 1 は、リンクが開かれていないことを意味するため、まだリンクのリストを確認していません。
  • リンクのリストを取得したら、それをループして、ハッシュ配列にループしているリンクのいずれかがないかどうかを確認します
  • 上記のリストのループが終了すると、最初に開いたリンクが 2 に更新さ$list{$link}=2れ、ハッシュ テーブルの次のリンクに渡されます (新しいリンクが見つかるたびにハッシュ配列がフィードされることに注意してください)。

前もって感謝します

4

1 に答える 1

3

クローラーを作成して、リンクに 2 回アクセスしないようにしたいようです。したがって、訪問したリンクをハッシュに追加しています。これは正しいです?

あなたの問題は、実際にそれらにアクセスする前に、表示されたリンクに新しいリンクを追加したため、それらを再度見つけるのが困難であるようです. この場合、ハッシュは間違ったデータ構造です。(重複を避けるために) 見られたリンクを登録するためにハッシュを使用しますが、未訪問のリンクのキューには配列を使用します:

my @queue = ('http://www.example.com/');     # start with at least one link in the queue
my %seen = ('http://www.example.com/' => 1); # this link is "known"

# look at the next link in the queue
while (defined(my $url = shift @queue)) {
  my $tree = some_magic($url);

  # 1. extract all <a>s
  # 2. extract the href value, skipping <a>s that don't have a href
  # 3. add them to the queue if not yet seen
  for my $link ($tree->look_down(...)) {
    my $href = $link->attr('href');
    next unless length $href;
    next if $seen{$href};

    $seen{$href} = 1;
    push @queue, $href;
  }
}

内側のループは、次のようにも記述できます。

push @queue,
  grep { length($_) and not $seen{$_}++ }
  map  { $_->('href') }
  $tree->look_down(...);

いくつかの問題が残っています。

  • 一部の URL は異なって見える場合がありますが、同等です。たとえば、スペースはしばしば+またはとしてエンコードされ%20ます。これを回避するには、URL を正規化します。
  • URL#fooには、サーバーに送信されないフラグメント部分を含めることができます。すでに URL を見たことがある場合は、テストする前におそらくそのフラグメントを削除する必要があります。
  • リクエストでサーバーを攻撃するのは失礼です。各リクエストのsleep間に数秒の間隔を空けることをお勧めします。
  • インターネットは広大な場所です。おそらく、検索の深さを制限し、URL とともに記録する必要があります@queue

    my @queue = (['http://www.example.com/', 5]); # start with depth 5
    ...
    while(my $item = shift @queue) {
      my ($url, $depth) = @$item;
      ...
      $seen{$href} = 1;
      next if $depth <= 0;
      push @queue, [$href, $depth-1];
      ...
    }
    
于 2013-09-27T14:30:58.703 に答える