首页 > 解决方案 > 替换 BeautifulSoup 迭代器中的字符串提前退出?

问题描述

我正在使用 BeautifulSoup 4 尝试迭代字符串列表并替换子字符串,但是我遇到了一个问题,即replace_with在生成器上执行一段时间迭代会strings提前退出循环。

例如,给定这段代码

from bs4 import BeautifulSoup

s = BeautifulSoup("<p>a</p><p>b</p><p>c</p>", features="html.parser")
for st in s.strings:
  st.replace_with('replace')

的最终内容s将是<p>replace</p><p>b</p><p>c</p>,而预期的行为将是 a、b 和 c 各自被替换。strings使用调试器单步执行确认在替换发生后迭代停止,基本上只执行一次迭代并提前退出。

在实践中,我将更新字符串的子部分并用新创建的 BeautifulSoup 对象替换它们,因此更简单的替换方法可能不起作用:

updated = st.replace(keyword, f'<a href="url/{keyword}">{keyword}</a>')
st.replace_with(BeautifulSoup(updated, features="html.parser"))

是否有解决方法或更正确的方法来做到这一点?

标签: pythonbeautifulsoup

解决方案


您将获得此输出 b'coz,如replace_with()的文档中所述

PageElement.replace_with() 从树中删除标签或字符串,并将其替换为您选择的标签或字符串

一旦从树中移除,它就不再有next_element并且生成器会提前退出。我们可以使用此代码检查这一点

from bs4 import BeautifulSoup
s = BeautifulSoup("<p>a</p><p>b</p><p>c</p>", features="html.parser")
for st in s.strings:
    print(st.next_element)
    st.replace_with('replace')
    print(st)
    print(st.next_element)

输出

<p>b</p>
a
None

之后是. replace_with()_next_elementNone

一种方法是@cody 提到的方法,即。使用 list() 一次获取所有值。

另一种方法是存储next_element并在之后设置它replace_with()以让生成器产生更多元素。

from bs4 import BeautifulSoup
s = BeautifulSoup("<p>a</p><p>b</p><p>c</p>", features="html.parser")
for st in s.strings:
    next=st.next_element
    st.replace_with('replace')
    st.next_element=next
print(s)

输出

<p>replace</p><p>replace</p><p>replace</p>

推荐阅读