如何将bs4.element.ResultSet转换为字符串?Python

17

我有一个简单的代码,如下:

    p = soup.find_all("p")
    paragraphs = []

    for x in p:
        paragraphs.append(str(x))

我试图将从XML获取的列表转换为字符串。我希望保留它的原始标记,以便可以重用一些文本,因此我像这样添加它。但是该列表包含6000多个观察结果,因此由于str而导致递归错误:

"RuntimeError: maximum recursion depth exceeded while calling a Python object"

我了解到可以更改最大递归深度,但这样做并不明智。我的下一个想法是将字符串转换分批为500,但我相信必须有更好的方法来实现这一点。有人有什么建议吗?


你能否将一个示例XML文件发布到pastebin或其他地方(如果需要,请删除敏感数据)?我无法理解为什么仅在<p>元素上调用str就会导致递归深度错误,除非您的标记嵌套深度接近500。 - senshin
我正在使用一份公共数据。该文件可以在此处找到http://www.sec.gov/Archives/edgar/data/1547063/000119312513465948/0001193125-13-465948.txt。正如我在描述中提到的,其中有超过6000个段落标签p。 - samuraiexe
问题的原因是文档底部的二进制图形块,其中一些包含序列<P,我认为BeautifulSoup试图将其修复为实际的XML标记。你需要这些图形块吗? - senshin
@senshin:不,beautifulsoup很好用。问题在于将每个单独的标签转换为字符串,从而导致运行时错误。 - samuraiexe
好的,如果你认为这是问题所在,试试这个:在你的for循环中添加一个计数器,在每次迭代时将计数器加一并打印出计数器的值。告诉我当RuntimeError发生时计数器的值是多少。 - senshin
i 值为 6015。p 的长度为 6040。 - samuraiexe
2个回答

11
这里的问题可能是文档底部一些二进制图形数据包含字符序列<P,Beautiful Soup试图将其修复为实际的HTML标签。我还没有确定哪段文本导致了"递归深度超过限制"错误,但它肯定在那里。对我来说,它是p[6053],但由于您似乎已经对文件进行了一些修改(或者您正在使用不同的Beautiful Soup解析器),所以您的情况会有所不同。
假设您不需要从文档底部的二进制数据中提取任何内容,可以尝试以下方法:
# boot out the last `<document>`, which contains the binary data
soup.find_all('document')[-1].extract()

p = soup.find_all('p')
paragraphs = []
for x in p:
    paragraphs.append(str(x))

1
我也在将此代码用于其他文档,所以我认为放弃最后一个文档并不是最好的选择,但你正在引导我走向正确的方向。 - samuraiexe
你需要采用一种策略,基本上是查看每个 <DOCUMENT><TYPE> 并消除其中 <TYPE>GRAPHIC 的文档。这不会很优雅,因为数据文件的标签格式非常糟糕,但应该可以工作。你也可以尝试检查 begin 644,它只出现在 GRAPHIC 文档中。作为最后的手段,尝试将数据文件中的 <HTML>...</HTML> 重命名为 <HTMLTWO>...</HTMLTWO>,然后仅迭代 soup.find_all('htmltwo') 而不是整个 soup。 - senshin
@samuraiexe 如果数据文件的非“GRAPHICS”部分的文本包含您正在过滤的某些字符串,则所有这些都有可能失败,但我认为这是您必须接受的。 - senshin

1
我认为问题在于BeautifulsSoup对象p没有被迭代地构建,因此在你完成构建p = soup.find_all('p')之前,方法调用限制已经达到。请注意,在构建soup.prettify()时也会引发RecursionError
为了解决这个问题,我使用了re模块来收集所有的<p>...</p>标签(请参见下面的代码)。我的最终结果是len(p) = 5571。这个计数比你的低,因为正则表达式条件没有匹配二进制图形数据中的任何文本。
import re
import urllib
from urllib.request import Request, urlopen

url = 'https://www.sec.gov/Archives/edgar/data/1547063/000119312513465948/0001193125-13-465948.txt'

response = urllib.request.urlopen(url).read()
p = re.findall('<P((.|\s)+?)</P>', str(response)) #(pattern, string)

paragraphs = []
for x in p:
    paragraphs.append(str(x))

使用对象的 .__str__() 方法不是更好吗?因此,x.__str__() - wesinat0r

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接