2012-07-01 10 views
7

Ich habe versucht, mehrere Web-Seiten mit BeautifulSoup4 in Python 2.7.3 zu verarbeiten, aber nach jedem Parsen geht die Speicherauslastung hoch und hoch.Python hohe Speicherauslastung mit BeautifulSoup

Dieser vereinfachte Code erzeugt das gleiche Verhalten:

from bs4 import BeautifulSoup 

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

while True: 
    parse() 
    raw_input() 

Nach Parse() aufgerufen wird für fünf Mal die Python-Prozess 30 MB Speicher bereits verwendet (verwendet HTML-Datei war etwa 100 kB) und es geht nach oben durch 4 MB bei jedem Anruf Gibt es eine Möglichkeit, diesen Speicher oder eine Art Workaround zu befreien?

Update: Dieses Verhalten gibt mir Kopfschmerzen. Dieser Code verwendet leicht viel Speicher auf, obwohl die BeautifulSoup Variable sollte lange gelöscht werden:

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

das könnte vielleicht eine Art ein Fehler sein?

+0

30 MB ist nicht viel ,, Garbage Collection wurde möglicherweise noch nicht ausgelöst, ich denke, .. gibt es ein Problem mit Speicher oder etwas? – Aprillion

Antwort

2

Try Mülleinsammlungs:

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

Siehe auch:

Python garbage collection

+0

Dadurch wird es nach einem Anruf nicht mehr hochgefahren, aber aus irgendeinem Grund verwendete der erste Anruf noch 5 MB, die nicht freigegeben wurden. – Sesshu

+0

@Sesshu: ist das nicht, weil der erste Anruf 5MB benötigt, dann ist Müll gesammelt und sofort danach braucht der nächste Anruf 5MB? Diese 5 MB werden benötigt, um die Struktur von index.html leicht zugänglich zu machen. –

+0

Auch beim Aufruf von gc.collect() zwischen parse() und raw_input() diese 5 MB werden nicht freigegeben. – Sesshu

0

Garbage Collection ist wahrscheinlich lebensfähig, aber ein Kontext-Manager scheint es für mich ohne zusätzlichen Speicherverbrauch recht gut zu handhaben :

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

Auch tho igitt nicht unbedingt erforderlich, wenn Sie mit raw_input es Schleife zu lassen, während Sie teste ich dieses Idiom tatsächlich finden sehr nützlich:

while not raw_input(): 
    parse() 

Es Schleife jedes Mal, weiterhin werden Sie die Eingabetaste drücken, aber sobald Sie Geben Sie eine nicht leere Zeichenfolge ein, die für Sie gestoppt wird.

+0

Danke für den raw_input tip.Leider die Verwendung eines Kontext-Managers ändert nicht das Verhalten für mich – Sesshu

4

Versuchen Sie die decompose Funktion von Beautiful Soup, die den Baum zerstört, wenn Sie mit jeder Datei fertig sind.

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

Ich weiß, dass dies ein alter Thread ist, aber es gibt noch etwas, das man beachten sollte, wenn man Seiten mit beautifulsoup analysiert. Wenn Sie in einem Baum navigieren und einen bestimmten Wert speichern, stellen Sie sicher, dass Sie die Zeichenfolge und kein bs4-Objekt erhalten. Zum Beispiel verursachte dies einen Speicherverlust, wenn sie in einer Schleife verwendet:

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

, die durch Veränderung in in behoben werden kann:

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

Im ersten Beispiel die Art des Kategorienamen bs4.element ist. NavigableString