2012-07-01 31 views
7

Intenté procesar varias páginas web con BeautifulSoup4 en Python 2.7.3 pero después de cada análisis, el uso de la memoria aumenta y aumenta.Uso de memoria de Python con BeautifulSoup

Este código simplificado produce el mismo comportamiento:

from bs4 import BeautifulSoup 

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

while True: 
    parse() 
    raw_input() 

Después de llamar parse() por cinco veces el proceso de pitón ya utiliza 30 MB de memoria (archivo HTML utilizado fue de alrededor de 100 kB) y se sube por 4 MB cada llamada. ¿Hay alguna manera de liberar esa memoria o algún tipo de solución?

Actualización: Este comportamiento me da dolores de cabeza. Este código utiliza fácilmente un montón de memoria a pesar de que la variable BeautifulSoup debería suprimirse larga:

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() 

Podría ser algún tipo de un error tal vez?

+0

30 MB no es mucho, la recolección de basura podría no haberse activado todavía, supongo ... ¿hay algún problema con la memoria o algo así? – Aprillion

Respuesta

2

Trate de basura recogida:

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() 

Ver también:

Python garbage collection

+0

Esto hace que deje de subir después de una llamada, pero por alguna razón la primera llamada aún usa 5 MB que no se libera. – Sesshu

+0

@Sesshu: ¿no es eso porque la primera llamada necesita 5MB, entonces es basura recolectada e inmediatamente después de eso la próxima llamada necesita 5MB? Esos 5MB son necesarios para hacer que la estructura de index.html sea fácilmente accesible. –

+0

Incluso cuando se llama a gc.collect() entre parse() y raw_input() esos 5 MB no se liberan. – Sesshu

0

La recolección de basura es probablemente viable, sino un gestor de contexto parece manejar bastante bien para mí sin ningún uso de memoria adicional :

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

Además, tho uf no es del todo necesario, si está usando raw_input para dejarlo en bucle mientras prueba en realidad me parece bastante útil este idioma:

while not raw_input(): 
    parse() 

Se va a seguir bucle cada vez que se pulsa enter, pero tan pronto como se ingrese cualquier cadena no vacía que se detendrá por usted.

+0

Gracias por la sugerencia raw_input. Desafortunadamente, usar un administrador de contexto no cambia el comportamiento para mí – Sesshu

4

Pruebe la funcionalidad Beautiful Soup decompose, que destruye el árbol, cuando termine de trabajar con cada archivo.

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

Sé que este es un hilo antiguo, pero hay una cosa más a tener en cuenta al analizar páginas con beautifulsoup. Cuando navegue por un árbol y esté almacenando un valor específico, asegúrese de obtener la cadena y no un objeto bs4. Por ejemplo esto provocó una pérdida de memoria cuando se utiliza en un bucle:

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

que podría ser fijado mediante el cambio en en:

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

En el primer ejemplo del tipo de nombre de categoría es bs4.element. NavigableString

Cuestiones relacionadas