0
class Crawler1(object):
    def __init__(self):
        'constructor'
        self.visited = []
        self.will_visit = []

    def reset(self):
        'reset the visited links'
        self.visited = []
        self.will_visit = []

    def crawl(self, url, n):
        'crawl to depth n starting at url'
        self.analyze(url)
        if n < 0:
            self.reset()
        elif url in self.visted:
            self.crawl(self.will_visit[-1],n-1)
        else:
            self.visited.append(url)
            self.analyze(url)
            self.visited.append(url)
            self.will_visit.pop(-1)
            self.crawl(self.will_visit[-1],n-1)


    def analyze(self, url):
        'returns the list of URLs found in the page url'
        print("Visiting", url)
        content = urlopen(url).read().decode()
        collector = Collector(url)
        collector.feed(content)
        urls = collector.getLinks()
        for i in urls:
            if i in self.will_visit:
                pass
            else:
                self.will_visit.append(i)

我希望该程序通过一系列链接运行,但仅在“n”允许的范围内运行

我不确定代码有什么问题,尽管我确信它已经足够了。一些提示会很好。

如果 n = 1 并且在 Site1 上存在 Site2 和 Site3 的链接,则预期输出:

Visiting [Site1]
Visiting [Site2]
Visiting [Site3]
4

1 回答 1

2

您需要仔细考虑它的行为方式,尤其是在它决定如何爬到另一个页面时。这段代码集中在crawl方法中:

  1. 如果n < 0,那么您已经爬得足够深并且不想做任何事情。所以在这种情况下简单地返回。

  2. 否则,分析页面。然后,您想爬到每个新的 url,深度为n-1.

我认为,部分困惑是您保留了要访问的 URL 队列,而且还递归地爬行。一方面,这意味着队列不仅包含您要按顺序访问的最后一个抓取的 url 的子节点,还包含来自其他已抓取但尚未完全处理的节点的子节点。很难以这种方式管理深度优先搜索的形状。

相反,我会删除该will_visit变量,并analyze返回找到的链接列表。然后根据上面的步骤 2 处理该列表,例如:

# Crawl this page and process its links
child_urls = self.analyze(url)    
for u in child_urls:
    if u in self.visited:
        continue  # Do nothing, because it's already been visited
    self.crawl(u, n-1)

为此,您还需要更改analyze为简单地返回 url 列表,而不是将它们放入堆栈:

def analyze(self, url):
    ...
    urls = collector.getLinks()
    returns urls
于 2012-11-12T03:29:07.587 回答