【问题标题】:How to wrap this into a recursive call如何将其包装到递归调用中
【发布时间】:2011-02-09 21:32:08
【问题描述】:

我正在用 python 写一个小蜘蛛。它点击一个页面,根据某种模式获取页面上的所有链接,然后转到每个页面,然后重复。

我需要以某种方式使这个递归。以下是网址格式:

www.example.com

然后我根据正则表达式获取所有链接,然后访问每个页面。

递归部分:

假设我正在访问一个带有如下网址的页面:

www.example.com/category/1

现在如果此页面包含如下链接:

www.example.com/category/1_234

(基本相同的url,只是多了一个“_234234”)

我访问该页面,然后检查以下网址:

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

我不需要正则表达式,我只需要帮助构建递归调用。

【问题讨论】:

    标签: python


    【解决方案1】:

    按照您要求的方式,仅递归可能不是最好的方法。

    一方面,如果要索引的页面超过 1000 个,您可能会“触底”调用堆栈并崩溃。另一方面,如果你在递归过程中不小心释放变量,最终可能会消耗相当多的内存。

    我会推荐类似的东西:

    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 列表几乎肯定会收集到许多重复的链接)。

    【讨论】:

    • visited 可以是一个简单存在的集合,表示链接已被访问。最后一行的列表visit_next 需要append,而不是add
    • 递归,就像线程一样,当它是适合工作的工具时非常适合使用,但它并不总是适合工作的工具。这是一个很好的解决方案。
    • @eumiro 是对的,您应该使用集合而不是具有虚假值的 dict。如果你打算使用visit_next 作为堆栈,弹出最后一个元素而不是第一个元素(纯.pop,这是默认值)。
    • @delnan:我认为它更像是一个队列;无论如何,集合可能是更好的解决方案(自动处理多次插入的值)。
    • 如果它是重复的集合不会插入?
    【解决方案2】:

    基本上,你会像其他人一样有轮廓(有缺陷):

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

    但是(正如也指出的那样),您必须跟踪您已经访问过的网站。一种天真的(但有点有效)的方法是存储它们(也许在“规范化”它们以捕获实际上以不同方式写下的相同链接之后 - 例如,strip /#.*$/)。示例:

    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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-15
      相关资源
      最近更新 更多