Je ne peux pas éviter la profondeur de récursivité maximale Python RuntimeError en utilisant BeautifulSoup.

J'essaie de revenir sur des sections de code imbriquées et d'extraire le contenu. Le HTML joliment ressemble à ceci (ne demandez pas pourquoi il ressemble à ceci :)):

<div><code><code><code><code>Code in here</code></code></code></code></div>

La fonction à laquelle je passe mon objet soupe est:

def _strip_descendent_code(self, soup):
    sys.setrecursionlimit(2000)
    # soup = BeautifulSoup(html, 'lxml')
    for code in soup.findAll('code'):
        s = ""
        for c in code.descendents:
            if not isinstance(c, NavigableString):
                if c.name != code.name:
                    continue
                elif c.name == code.name:
                    if isinstance(c, NavigableString):
                        s += str(c)
                    else:
                        continue
        code.append(s)
    return str(soup)

Vous pouvez voir que j'essaie d'augmenter la limite de récursivité par défaut mais ce n'est pas une solution. J'ai augmenté au point que C atteint la limite de mémoire sur l'ordinateur, et la fonction ci-dessus ne fonctionne jamais.

Toute aide pour que cela fonctionne et signale les erreurs serait très appréciée.

La trace de pile répète ceci:

  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 1234, in find
    l = self.find_all(name, attrs, recursive, text, 1, **kwargs)
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 1255, in find_all
    return self._find_all(name, attrs, text, limit, generator, **kwargs)
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 529, in _find_all
    i = next(generator)
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 1269, in descendants
    stopNode = self._last_descendant().next_element
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 284, in _last_descendant
    if is_initialized and self.next_sibling:
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 997, in __getattr__
    return self.find(tag)
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 1234, in find
    l = self.find_all(name, attrs, recursive, text, 1, **kwargs)
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 1255, in find_all
    return self._find_all(name, attrs, text, limit, generator, **kwargs)
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 529, in _find_all
    i = next(generator)
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 1269, in descendants
    stopNode = self._last_descendant().next_element
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 284, in _last_descendant
    if is_initialized and self.next_sibling:
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 997, in __getattr__
    return self.find(tag)
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 1234, in find
    l = self.find_all(name, attrs, recursive, text, 1, **kwargs)
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 1255, in find_all
    return self._find_all(name, attrs, text, limit, generator, **kwargs)
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 512, in _find_all
    strainer = SoupStrainer(name, attrs, text, **kwargs)
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 1548, in __init__
    self.text = self._normalize_search_value(text)
  File "/Users/almccann/.virtualenvs/evernoteghost/lib/python3.4/site-packages/bs4/element.py", line 1553, in _normalize_search_value
    if (isinstance(value, str) or isinstance(value, collections.Callable) or hasattr(value, 'match')
RuntimeError: maximum recursion depth exceeded while calling a Python object
10
almccann 21 juil. 2015 à 03:42

2 réponses

Meilleure réponse

J'avais rencontré ce problème et parcouru de nombreuses pages Web. Je résume deux méthodes pour résoudre ce problème.

Cependant, je pense que nous devrions savoir pourquoi cela s'est produit. Python limite le nombre de récursifs (le nombre par défaut est 1000). Nous pouvons voir ce nombre avec print sys.getrecursionlimit(). Je suppose que BeautifulSoup utilise la récursivité pour trouver des éléments enfants . Lorsque la récursivité est plus de 1000 fois, RuntimeError: maximum recursion depth exceeded apparaîtra.

Première méthode: utilisez sys.setrecursionlimit() définir un nombre limité de récursifs. Vous pouvez évidemment définir 1000000, mais peut-être provoquer segmentation fault.

Deuxième méthode: utilisez try-except. S'il apparaissait maximum recursion depth exceeded, notre algorithme pourrait avoir des problèmes. De manière générale, nous pouvons utiliser des boucles au lieu de la récursivité. Dans votre question, nous pourrions traiter à l'avance du HTML avec replace() ou une expression régulière.

Enfin, je donne un exemple.

from bs4 import BeautifulSoup
import sys   
#sys.setrecursionlimit(10000)

try:
    doc = ''.join(['<br>' for x in range(1000)])
    soup = BeautifulSoup(doc, 'html.parser')
    a = soup.find('br')
    for i in a:
        print i
except:
    print 'failed'

Si supprimé le #, il pourrait imprimer doc.

En espérant vous aider.

11
Absinth 3 mai 2016 à 09:18

Je ne sais pas pourquoi cela fonctionne (je n'ai pas examiné la source), mais l'ajout de .text ou .get_text() semble contourner l'erreur pour moi.

Par exemple, changer

lambda x: BeautifulSoup(x, 'html.parser')

À

lambda x: BeautifulSoup(x, 'html.parser').get_text() semble fonctionner sans générer une erreur de profondeur de récursivité.

2
ngopal 20 sept. 2019 à 17:13