如何在lxml iterwalk循环中用文字替换HTML标签

2 投票
2 回答
3198 浏览
提问于 2025-04-18 09:08

我正在用lxml的iterwalk遍历一个HTML树,我想把所有在<pre></pre>标签里的<br>标签替换成换行符。到目前为止,我有这样的代码:

root = lxml.html.fromstring(text)
for action, el in etree.iterwalk(root):
    if el.tag == 'pre':
        for br in el.xpath('br'):
            # replace this <br> tag with "\n"

如果可以的话,这个替换操作最好是在这个循环里面完成,因为我们本来就需要这个循环,把这个步骤放进去可能是最有效的方式。

在StackOverflow上有一个类似的问题和回答,但并没有帮助我解决这个问题: 如何在lxml中用文本替换一个元素?

2 个回答

3

我知道你需要用到 lxml,但是用 BeautifulSoup 来解析和修改 HTML 其实要简单得多,而且更有趣。如果速度真的很重要的话,你可以把 lxml 当作一个 底层解析器 来使用:

from bs4 import BeautifulSoup

text = """
<div>
    <pre>
        <br>
        test
        <br>
    </pre>
    <br>
</div>
"""

soup = BeautifulSoup(text, "lxml")
for pre in soup.find_all('pre'):
    for br in pre.find_all('br'):
        br.replace_with('\n')

print soup.prettify()

输出结果是:

<html>
 <body>
  <div>
   <pre>


        test


    </pre>
   <br/>
  </div>
 </body>
</html>
5

drop_tree() 方法正是你需要的:

.drop_tree():

这个方法会删除这个元素以及它的所有子元素。和 el.getparent().remove(el) 不同的是,这个方法不会删除尾部文本;使用 drop_tree 的话,尾部文本会和前一个元素合并在一起。

找到所有在 pre 标签里的 br 标签,把 tail 设置为 \n 然后删除这个元素:

from lxml import etree
import lxml.html

text = """
<div>
    <pre>
        <br>
        test
        <br>
    </pre>
    <br>
</div>
"""

root = lxml.html.fromstring(text)
for action, el in etree.iterwalk(root):
    if el.tag == 'pre':
        for br in el.xpath('br'):
            br.tail = '\n' + br.tail
            br.drop_tree()

print etree.tostring(root)

输出结果:

<div>
    <pre>


        test


    </pre>
    <br/>
</div>

撰写回答