2011-02-09 8 views
1

私はPythonで小さなスパイダーを書いています。ページをヒットし、パターンに従ってページ上のすべてのリンクを取得し、それらのページのそれぞれに行き、繰り返します。これを再帰呼び出しにラップする方法

何とか再帰的にする必要があります。以下のURLパターンは、次のとおりです。

www.example.com 

その後、私は、私はそれぞれのページをご覧ください正規表現に基づいて、すべてのリンクを取得します。

再帰部分:

www.example.com/category/1_234 

(基本的には同じURL:このページのようなリンクが含まれている場合

www.example.com/category/1 

は、私のようなURLでページを訪問していますと言います追加の "_234234"を除いて)

私はそのページにアクセスして、次のようなURLを確認してください:

www.example.com/category/1_234_4232 

(再び、同じURLに加えて、アンダースコアおよび番号)

このパターンを当てはめるこれ以上のリンクが存在しなくなるまで、私はこれをやり続けます。

1. visit a category page 
2. does it contain links with the same url + "_dddd" if yes, visit that page 
3. back to #2 unless no links 

私は正規表現を必要としません。私は再帰呼び出しを構造化するのに助けが必要です。

答えて

4

あなたが求めている方法で、ちょうど再帰が最良の方法ではないかもしれません。

索引付けするページが1000を超える場合は、コールスタックを「ボトムアウト」してクラッシュすることがあります。もう1つは、再帰中に変数を解放することに注意しないと、かなりのメモリを消費する可能性があります。

私はより多くのようなものをお勧めします:

visit_next = set(['www.example.com']) 
visited = set() 

while len(visit_next): 
    next_link = visit_next.pop() 
    if next_link not in visited: 
     visited.add(next_link) 
     for link in find_all_links_from(next_link): 
      if link not in visited: 
       visit_next.add(link) 

編集:

示唆したように、私はこの使用してセットに書き換えています。これは少ないメモリを使用する必要があります(長いトラバーサルの場合、visit_nextリストはほとんどの場合重複リンクを多数収集しています)。他の人が(欠陥付き)輪郭を持っているよう

+1

'visited'リンクが訪問された意味シンプルな存在で設定することができます:あなたは、再帰と同じように同じ順序をこする心配している場合 - リスト - またはスタックを使用しています。最後の行の 'visit_next'のリストは、' add'ではなく 'append'を必要とします。 – eumiro

+0

スレッドのような再帰は、ジョブにとって適切なツールである場合には使い勝手が良いですが、ジョブにとって常に適切なツールではありません。これは良い解決策です。 –

+1

@eumiroが正しいとすると、偽の値を持つ辞書の代わりに集合を使用するべきです。そして 'visit_next'をスタックとして使うつもりなら、最初の要素(普通の' .pop'、これはデフォルト)の代わりに最後の要素をポップします。 – delnan

2

基本的に、あなたはそれを行うだろう:(も指摘したように)

def visit(url): 
    content = get_content(url) 
    links = extract_links(content) 
    for link in links: 
     visit(link) 

は、しかし、あなたはすでに訪問したサイトを追跡する必要があります。単純な(ただしちょっとした)効果的なアプローチは、それらを保存することです(おそらく、別々に書かれた実質的に同一のリンクをキャッチするためにそれらを「正規化」した後に - 例えば、 /#.*$/を削除する)。例:

visited = set() 
def visit(url): 
    content = get_content(url) 
    links = extract_and_normalize_links(content) 
    for link in links: 
     if link not in visited: 
      visited.add(link) 
      visit(link) 

スタックオーバーフローは、(スクリプトがとにかく非常に長い時間を実行します呼び出し、あなたが1000に達した場合、他の一方で)どのくらいのリンクがあるに応じて、問題になる可能性があります。その多くの回帰がある場合は、別の答えに示すように再帰を削除する必要があります。

while link_stack: 
    current_page = link_stack.pop() 
    # get links 
    link_stack.extend(links_from_current_page) 
関連する問題