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



我正在尝试使解析器使用漂亮的汤和多处理。我有一个错误:

递归错误:超出最大递归深度

我的代码是:

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:UserseugenAppDataLocalProgramsPythonPython36libmultiprocessingpool.py", line 266, in map
return self._map_async(func, iterable, mapstar, chunksize).get()
File "C:UserseugenAppDataLocalProgramsPythonPython36libmultiprocessingpool.py", line 644, in get
raise self._value
File "C:UserseugenAppDataLocalProgramsPythonPython36libmultiprocessingpool.py", line 424, in _handle_tasks
put(task)
File "C:UserseugenAppDataLocalProgramsPythonPython36libmultiprocessingconnection.py", line 206, in send
self._send_bytes(_ForkingPickler.dumps(obj))
File "C:UserseugenAppDataLocalProgramsPythonPython36libmultiprocessingreduction.py", line 51, in dumps
cls(buf, protocol).dump(obj)
RecursionError: maximum recursion depth exceeded

当你使用multiprocessing时,你传递给工人的所有东西都必须被腌制。

不幸的是,许多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不完美,转换为字符串并重新解析它可能不是一个完美的往返。因此,我建议您先在没有多处理的情况下进行一些测试,以确保这不会影响结果。

最新更新