避免Python 3中的堆栈溢出

时间:2015-08-20 17:00:30

标签: python python-3.x stack beautifulsoup overflow

免责声明:我完全不了解计算机科学,也不了解幕后发生的任何事情的内部运作。使用互联网上的所有内容自学编码。

Python版本:

Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:43:06) [MSC v.1600 32 bit(Intel)] on win32

使用普通解析器,其主要目的是获取图像的完整大小的图像,将其保存到文件中以便以后下载,然后进入下一个图像,这几乎是强制性的,因为有问题的网站的糟糕的网络架构。当我完成程序时,我在第976次执行时遇到了错误。

  RuntimeError: maximum recursion depth exceeded in comparison

经过研究,我发现有问题的原因是“堆栈溢出”。但是,目前我还不知道如何在不造成任何重大性能下降的情况下解决问题。 (虽然这不是一个真正的问题,因为我只是为了学习而做。)

这让我想到了我的问题,我怎样才能解决这个问题?我在哪里可以了解更多关于这些事情的内容,比如什么是Stack Overflow?

(程序运行正常,堆栈溢出会阻止它)

import requests
from bs4 import BeautifulSoup

def somesite_parsing(url):

    connection = requests.get(url)
    html = connection.text
    soup = BeautifulSoup(html, "html.parser")

    # The exception is necessary due to the web architecture.
    # Images that don't have different versions by size have an img tag.
    # Returns "http://www.somesite.net/tag_tag_tag.full.jpg"
    try:
        semi_link = soup.select("html > body > #wrapper > #body > #content > #large > a")
        full_link = semi_link[0].get("href")
        print(full_link)

    except IndexError:
        semi_link = soup.select("html > body > #wrapper > #body > #content > #large > img")
        full_link = semi_link[0].get("src")
        print(full_link)

    # File was created during testing so I switched to appending.
    # Saves link into folder.
    fx = open("list_file.txt", "a")
    fx.write(full_link + "\n")
    fx.close()

    # Fetches the next url.
    # Returns "/id_number"
    next_link = soup.select("html > body > #wrapper > #body > #menu > .smallthumbs > li > a")
    next_link = next_link[0].get("href")
    next_link = "http://www.somesite.net" + next_link
    print(next_link)

    print()
    somesite_parsing(next_link)


somesite_parsing("http://www.somesite.net/1905220")

2 个答案:

答案 0 :(得分:1)

当嵌套函数调用太多时,会发生堆栈溢出。这主要发生在一个函数继续无休止地调用它时。

在您的情况下,您在其内部调用somesite_parsing。这最终会导致堆栈溢出。

有几种方法可以避免这种情况。我建议你在解析时循环。

更改somesite_parsing以返回下一个链接,而不是自行调用,您可以执行此操作:

next_link = "http://www.somesite.net/1905220"
while next_link:
    next_link = somesite_parsing(next_link)

这样您就可以从somesite_parsing返回falsy值来停止循环播放。

答案 1 :(得分:0)

A'而'循环确实是你需要的。

虽然我没有运行代码,但我会这样做。

import requests
import json

start_url = "http//your_start_url"

def save_data(data):
    """Or however you want to save your data.
     I like .jsonl, see http://jsonlines.org/"""
    data = json.dumps(data)
    fx = open("data_file.jsonl", "a") #see 
    fx.write(data + "\n")
    fx.close()

def get_url(url):
    "This returns something similar to an 'option type'."
    r = requests.get(url)
    return {"success":  r.ok,
            "next_url": parse_your_response_for_next_url(r.text),
            "page":     r.text,
            "url":      url}

##################################


response = get_url(start_url)

while respose["success"]:
    save_data(response)
    response = get_url(response["next_url"])

(我使用伪'选项类型'和jsonl文件。但这只是一个风格决定。请参阅https://en.wikipedia.org/wiki/Option_typehttp://jsonlines.org/

此外,如果您正在制作足够的请求以达到最大递归深度,那么使用@functools.lru_cache或某些磁盘支持的替代方案存储响应可能会很好。