2012-07-01 20 views
7

Stavo cercando di elaborare diverse pagine Web con BeautifulSoup4 in python 2.7.3 ma dopo ogni analisi l'utilizzo della memoria aumenta.Utilizzo di memoria alta Python con BeautifulSoup

Questo codice semplificato produce lo stesso comportamento:

from bs4 import BeautifulSoup 

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

while True: 
    parse() 
    raw_input() 

Dopo aver chiamato parse() per cinque volte il processo di Python utilizza già 30 MB di memoria (file HTML utilizzato è stato di circa 100 kB) e si va da 4 MB ogni chiamata. C'è un modo per liberare quella memoria o qualche tipo di soluzione alternativa?

Aggiornamento: Questo comportamento mi dà mal di testa. Questo codice utilizza facilmente fino un sacco di memoria, anche se la variabile BeautifulSoup dovrebbe essere lunga cancellata:

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

Che potrebbe essere una specie di bug forse?

+0

30 MB non è molto, la raccolta dei dati inutili potrebbe non essere stata ancora attivata, suppongo .. c'è un problema con la memoria o qualcosa del genere? – Aprillion

risposta

2

Prova raccolta dei rifiuti:

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

Vedi anche:

Python garbage collection

+0

Questo lo fa smettere di salire dopo una chiamata, ma per qualche motivo la prima chiamata ha ancora utilizzato 5 MB che non sono stati liberati. – Sesshu

+0

@Sesshu: non è così perché la prima chiamata ha bisogno di 5 MB, quindi è raccolta della spazzatura e subito dopo la chiamata successiva richiede 5 MB? Quei 5 MB sono necessari per rendere facilmente accessibile la struttura di index.html. –

+0

Anche quando si chiama gc.collect() tra parse() e raw_input() quei 5 MB non vengono liberati. – Sesshu

0

Garbage Collection è probabilmente fattibile, ma un manager contesto sembra gestire abbastanza bene per me senza alcun utilizzo di memoria in più :

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

Inoltre, tho ugh non del tutto necessaria, se si sta utilizzando raw_input di lasciarlo ciclo while si prova in realtà ho trovato questo linguaggio molto utile:

while not raw_input(): 
    parse() 

E continueremo a ciclo ogni volta che si preme entrare, ma non appena si inserisci una stringa non vuota che si fermerà per te.

+0

Grazie per il suggerimento raw_input. Sfortunatamente l'utilizzo di un gestore di contesto non modifica il comportamento per me – Sesshu

4

Prova la funzionalità decompose di Beautiful Soup che distrugge l'albero quando hai finito di lavorare con ogni file.

2

So che questo è un thread vecchio, ma c'è ancora una cosa da tenere a mente quando si analizzano le pagine con beautifulsoup. Quando navighi in un albero e stai memorizzando un valore specifico, assicurati di ottenere la stringa e non un oggetto bs4. Per esempio questo ha causato una perdita di memoria quando utilizzato in un ciclo:

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

che può essere fissato modificando in in:

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

Nel primo esempio il tipo di nome categoria è bs4.element. NavigableString

Problemi correlati