python – 超出最大递归深度.多处理和bs4

我正在尝试使解析器使用beautifulSoup和多处理.我有一个错误:

RecursionError: maximum recursion depth exceeded

我的代码是:

import bs4, requests, time
from multiprocessing.pool import Pool

html = requests.get('https://www.avito.ru/moskva/avtomobili/bmw/x6?sgtd=5&radius=0')
soup = bs4.BeautifulSoup(html.text, "html.parser")

divList = soup.find_all("div", {'class': 'item_table-header'})


def new_check():
    with Pool() as pool:
        pool.map(get_info, divList)

def get_info(each):
   pass

if __name__ == '__main__':
    new_check()

为什么我会收到此错误以及如何解决?

更新:
所有错误的文字都是

Traceback (most recent call last):
  File "C:/Users/eugen/PycharmProjects/avito/main.py", line 73, in <module> new_check()
  File "C:/Users/eugen/PycharmProjects/avito/main.py", line 67, in new_check
    pool.map(get_info, divList)
  File "C:\Users\eugen\AppData\Local\Programs\Python\Python36\lib\multiprocessing\pool.py", line 266, in map
    return self._map_async(func, iterable, mapstar, chunksize).get()
  File "C:\Users\eugen\AppData\Local\Programs\Python\Python36\lib\multiprocessing\pool.py", line 644, in get
    raise self._value
  File "C:\Users\eugen\AppData\Local\Programs\Python\Python36\lib\multiprocessing\pool.py", line 424, in _handle_tasks
    put(task)
  File "C:\Users\eugen\AppData\Local\Programs\Python\Python36\lib\multiprocessing\connection.py", line 206, in send
    self._send_bytes(_ForkingPickler.dumps(obj))
  File "C:\Users\eugen\AppData\Local\Programs\Python\Python36\lib\multiprocessing\reduction.py", line 51, in dumps
    cls(buf, protocol).dump(obj)
RecursionError: maximum recursion depth exceeded

最佳答案 使用多处理时,传递给worker的所有内容都必须为
pickled.

不幸的是,很多BeautifulSoup树都无法腌制.

这有几个不同的原因.其中一些是已修复的错误,所以你可以尝试确保你有最新的bs4版本,有些是特定于不同的解析器或树构建器……但是这样的事情很有可能对这有帮助.

但根本问题是树中的许多元素都包含对树的其余部分的引用.

偶尔,这会导致实际的无限循环,因为循环引用对于其循环引用检测来说太间接.但这通常是一个被修复的错误.

但是,更重要的是,即使循环不是无限的,它仍然可以拖动来自树的其余部分的1000多个元素,这已经足以导致RecursionError.

我认为后者就是这里发生的事情.如果我拿你的代码并尝试挑选divList [0],它就会失败. (如果我将递归限制上升并计算帧数,它需要23080的深度,这是超过默认值1000的方式.)但是,如果我采用完全相同的div并分别解析它,它成功没有问题.

所以,一种可能性是只做sys.setrecursionlimit(25000).这将解决这个确切页面的问题,但稍微不同的页面可能需要甚至更多. (另外,设置递归限制通常不是一个好主意,因为浪费的内存不是很多,而是因为它意味着实际的无限递归需要25倍的时间和25倍的浪费资源来检测.)

另一个技巧是编写“修剪树”的代码,在你腌制它之前消除div中的任何向上链接.这是一个很好的解决方案,除了它可能需要做很多工作,并且需要深入了解BeautifulSoup如何工作的内部,我怀疑你想做什么.

最简单的解决方法是有点笨重,但是……你可以将汤转换为字符串,将其传递给孩子,并让孩子重新解析它:

def new_check():
    divTexts = [str(div) for div in divList]
    with Pool() as pool:
        pool.map(get_info, divTexts)

def get_info(each):
    div = BeautifulSoup(each, 'html.parser')

if __name__ == '__main__':
    new_check()

这样做的性能成本可能并不重要;更大的担心是,如果你有不完美的HTML,转换为字符串并重新解析它可能不是一个完美的往返.因此,我建议您先进行一些测试,不要先进行多处理,以确保不影响结果.

点赞