【问题标题】:Python high memory usage with BeautifulSoupBeautifulSoup 的 Python 高内存使用率
【发布时间】:2012-07-02 08:01:27
【问题描述】:

我试图在 python 2.7.3 中使用 BeautifulSoup4 处理几个网页,但每次解析后内存使用量都会上升。

此简化代码产生相同的行为:

from bs4 import BeautifulSoup

def parse():
    f = open("index.html", "r")
    page = BeautifulSoup(f.read(), "lxml")
    f.close()

while True:
    parse()
    raw_input()

在调用 parse() 五次后,python 进程已经使用了 30 MB 内存(使用的 HTML 文件大约 100 kB),每次调用它都会增加 4 MB。 有没有办法释放该内存或某种解决方法?

更新: 这种行为让我很头疼。即使 BeautifulSoup 变量应该被长期删除,这段代码也很容易占用大量内存:

from bs4 import BeautifulSoup
import threading, httplib, gc

class pageThread(threading.Thread):
    def run(self):
        con = httplib.HTTPConnection("stackoverflow.com")
        con.request("GET", "/")
        res = con.getresponse()
        if res.status == 200:
            page = BeautifulSoup(res.read(), "lxml")
        con.close()

def load():
    t = list()
    for i in range(5):
        t.append(pageThread())
        t[i].start()
    for thread in t:
        thread.join()

while not raw_input("load? "):
    gc.collect()
    load()

这可能是某种错误吗?

【问题讨论】:

  • 30 MB 不是很多,我猜可能还没有触发垃圾收集......内存有问题吗?

标签: python memory beautifulsoup


【解决方案1】:

尝试使用 Beautiful Soup 的 decompose 功能,它会在您处理完每个文件后破坏树。

from bs4 import BeautifulSoup

def parse():
    f = open("index.html", "r")
    page = BeautifulSoup(f.read(), "lxml")
    # page extraction goes here
    page.decompose()
    f.close()

while True:
    parse()
    raw_input()

【讨论】:

    【解决方案2】:

    我知道这是一个旧线程,但是在使用 beautifulsoup 解析页面时,还有一件事要记住。导航树时,如果要存储特定值,请确保获取字符串而不是 bs4 对象。例如,这在循环中使用时会导致内存泄漏:

    category_name = table_data.find('a').contents[0]
    

    这可以通过改成来解决:

    category_name = str(table_data.find('a').contents[0])
    

    在第一个示例中,类别名称的类型是 bs4.element.NavigableString

    【讨论】:

      【解决方案3】:

      尝试垃圾收集:

      from bs4 import BeautifulSoup
      import gc
      
      def parse():
          f = open("index.html", "r")
          page = BeautifulSoup(f.read(), "lxml")
          page = None
          gc.collect()
          f.close()
      
      while True:
          parse()
          raw_input()
      

      另见:

      Python garbage collection

      【讨论】:

      • 这使得它在一个呼叫后停止上升,但由于某种原因,第一个呼叫仍然使用了 5 MB,没有被释放。
      • @Sesshu :这不是因为第一次调用需要 5MB,然后它会被垃圾收集,然后下一次调用需要 5MB 吗?需要这 5MB 来使 index.html 的结构易于访问。
      • 即使在 parse() 和 raw_input() 之间调用 gc.collect() 时,这 5 MB 也不会被释放。
      • 对不起。收集发生在之前的解析结果仍然绑定到page 时。我首先不得不断开连接。我更新了我的答案。
      【解决方案4】:

      垃圾收集可能是可行的,但上下文管理器似乎对我来说处理得很好,没有任何额外的内存使用:

      from bs4 import BeautifulSoup as soup
      def parse():
        with open('testque.xml') as fh:
          page = soup(fh.read())
      

      此外,虽然不是完全必要,但如果您在测试时使用raw_input 让它循环,我实际上发现这个成语非常有用:

      while not raw_input():
        parse()
      

      每次你按回车它都会继续循环,但一旦你输入任何非空字符串,它就会为你停止。

      【讨论】:

      • 感谢 raw_input 提示。不幸的是,使用上下文管理器并没有改变我的行为
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-03
      • 2014-02-24
      • 2011-09-19
      • 2018-07-01
      • 1970-01-01
      • 2012-05-31
      • 1970-01-01
      相关资源
      最近更新 更多