私はPythonで単純なWebクローラーに取り組んでおり、単純なキュークラスを作成したくありませんが、開始する最良の方法がよくわかりません. クローラーがスクリプトの実行ごとに各ページを 1 回だけクロールするように、処理する一意のアイテムのみを保持するものが必要です (単純に無限ループを回避するため)。誰かが私に教えてくれるか、私が実行できる簡単なキューの例を教えてくれますか?
5 に答える
セットを使用するだけです。順序は維持されませんが、一意性を維持するのに役立ちます。
>>> q = set([9, 8, 7, 7, 8, 5, 4, 1])
>>> q.pop()
1
>>> q.pop()
4
>>> q.pop()
5
>>> q.add(3)
>>> q.add(3)
>>> q.add(3)
>>> q.add(3)
>>> q
set([3, 7, 8, 9]
私の理解が正しければ、各ページに 1 回だけアクセスしてください。これを行う最善の方法は、アクセスするページのキューと、アクセスしたページのセットを保持することだと思います。投稿された他のソリューションの問題は、キューからページをポップすると、そこに行ったかどうかの記録がなくなることです。
セットとリストの組み合わせを使用します。
visited = set()
to_visit = []
def queue_page(url):
if url not in visited:
to_visit.append(url)
def visit(url):
visited.add(url)
... # some processing
# Add all found links to the queue
for link in links:
queue_page(link)
def page_iterator(start_url):
visit(start_url)
try:
yield to_visit.pop(0)
except IndexError:
raise StopIteration
for page in page_iterator(start):
visit(page)
もちろん、これは少し不自然な例であり、おそらくこれを何らかの方法でカプセル化するのが最善ですが、概念を示しています。
非常に単純な例は、各項目の URL を dict に詰め込むことですが、値としてではなくキーとして詰め込みます。次に、その dict のキーに URL が含まれていない場合にのみ、次の項目を処理します。
visited = {}
# grab next url from somewhere
if url not in visited.keys():
# process url
visited[url] = 1 # or whatever, the value is unimportant
# repeat with next url
もちろん、より効率的になることができますが、これは簡単です。
順序が必要な場合はリストを使用しないのはなぜですか (または、代わりにセットが提案される前に zacherates によって以前に提案されていたように heapq でさえも)、セットを使用して重複をチェックしないのはなぜですか?
リストクラスを拡張して、使用しているリストのメソッドに一意のテストコードを追加します。これは、単にクラスにaを追加することから、、、、、、などのすべてを.append_unique(item)
オーバーライドすることから、append
一意でないアイテムの場合に例外をスローすること(または、必要に応じてサイレントにすること)までさまざまです。insert
extend
__setitem__
__setslice__
たとえば、appendメソッドが一意性を維持していることを確認したいだけの場合:
class UniqueList(list):
def append(self, item):
if item not in self:
list.append(self, item)