2015-04-24 3 views
0

я в основном имеют те же проблемы, что и парень здесь: Python high memory usage with BeautifulSoupPython использование памяти с BeautifulSoup: не может удалить объект

Мои BeautifulSoup объекты не мусора, в результате чего важного потребления оперативной памяти. Вот код, который я использую («запись» - это объект, который я получаю с веб-страницы RSS. Это в основном статья RSS).

title = entry.title 
date = arrow.get(entry.updated).format('YYYY-MM-DD') 

try: 
    url = entry.feedburner_origlink 
except AttributeError: 
    url = entry.link 

abstract = None 
graphical_abstract = None 
author = None 

soup = BeautifulSoup(entry.summary) 

r = soup("img", align="center") 
print(r) 
if r: 
    graphical_abstract = r[0]['src'] 

if response.status_code is requests.codes.ok: 
    soup = BeautifulSoup(response.text) 

    # Get the title (w/ html) 
    title = soup("h2", attrs={"class": "alpH1"}) 
    if title: 
     title = title[0].renderContents().decode().lstrip().rstrip() 

    # Get the abstrat (w/ html) 
    r = soup("p", xmlns="http://www.rsc.org/schema/rscart38") 
    if r: 
     abstract = r[0].renderContents().decode() 
     if abstract == "": 
      abstract = None 

    r = soup("meta", attrs={"name": "citation_author"}) 
    if r: 
     author = [tag['content'] for tag in r] 
     author = ", ".join(author) 

Таким образом, в документе (http://www.crummy.com/software/BeautifulSoup/bs3/documentation.html#Improving%20Memory%20Usage%20with%20extract), они говорят, что проблема может исходить от того, что, до тех пор, пока вы используете тег, содержащийся в объекте супа, объект супа остается в памяти. Так что я пытался что-то подобное (за каждый раз, когда я использую объект суп в предыдущем примере):

r = soup("img", align="center")[0].extract() 
    graphical_abstract = r['src'] 

Но тем не менее, память не освобождается, когда программа выходит из сферы.

Итак, я ищу эффективный способ удаления суп-объекта из памяти. У вас есть идеи?

+0

Вы пробовали ** lxml **? Это 'iterparse' очень эффективно для большого анализа документов, посмотрите [здесь] (http://lxml.de/api/lxml.etree.iterparse-class.html) – Anzel

+0

Я знаю lxml, но предпочитаю BeautifulSoup. И у меня есть полный модуль, закодированный с BS. Он работает, за исключением части утечки памяти. – Rififi

ответ

1

У меня была аналогичная проблема и выяснилось, что, несмотря на мое внимание, я все еще хранил некоторые BS NavigableString и/или ResultSet, которые заставляли суп оставаться в памяти, как вы уже знаете. Не уверен, что если оба полезны (я позволю вам попробовать), но я помню, что извлечение текста таким образом исправлена ​​проблема

ls_result = [unicode(x) for x in soup_bloc.findAll(text = True)] 
str_result = unicode(soup_bloc.text) 
+0

Так что в принципе, каждый раз, когда мне нужна строка из объекта супа, мне просто нужно вызвать функцию unicode на нем, правильно? Мне не нужно ничего делать при просмотре/поиске дерева? – Rififi

+0

В моем случае этого было достаточно. Я также играл с gc и decpose(), как это было предложено в вопросе SO, который вы упомянули, но это не помогло. В конце концов, я обнаружил проблему путем методической проверки типа каждой вещи, которую я сохранил (включая тип того, что, по моему мнению, было списком, и получилось BS ResultSets и элементов в списках, которые, как я полагал, являются строковыми и чтобы быть BS NavigableStrings). Думаю, ваша проблема может быть другой. Я не возражаю, если вы опубликуете фрагмент, который я могу запустить. – etna

1

Чтобы избежать большая утечки памяти из BeautifulSoup объектов попробовать использовать класс SoupStrainer.

Он отлично работал для меня.

from bs4 import SoupStrainer 

only_span = SoupStrainer('span') 
only_div = SoupStrainer('div') 
only_h1 = SoupStrainer('h1') 

soup_h1 = BeautifulSoup(response.text, 'lxml', parse_only=only_h1) 
soup_span = BeautifulSoup(response.text, 'lxml', parse_only=only_span) 
soup_div = BeautifulSoup(response.text, 'lxml', parse_only=only_div) 


try: 
    name = soup_h1.find('h1', id='itemTitle').find(text=True, recursive=False) 
except: 
    name = 'Noname' 

try: 
    price = soup_span.find('span', id='prcIsum').text.strip() 

и т.д ...

Даже если мы создадим три BeautifulSoup объекты с помощью SoupStrainer он будет потреблять намного меньше оперативной памяти, чем без SoupStrainer и используя только один объект BeautifulSoup.

Смежные вопросы