用 BeautifulSoup 包裹多个标签

Ben*_*Ben 5 python beautifulsoup

我正在编写一个 python 脚本,允许将 html 文档转换为reveal.js幻灯片。为此,我需要将多个标签包装在一个<section>标签中。

使用该wrap()方法很容易将单个标签包装在另一个标签中。但是我不知道如何包装多个标签。

一个澄清的例子,原始html:

html_doc = """
<html>

<head>
  <title>The Dormouse's story</title>
</head>

<body>

  <h1 id="first-paragraph">First paragraph</h1>
  <p>Some text...</p>
  <p>Another text...</p>
  <div>
    <a href="http://link.com">Here's a link</a>
  </div>

  <h1 id="second-paragraph">Second paragraph</h1>
  <p>Some text...</p>
  <p>Another text...</p>

  <script src="lib/.js"></script>
</body>

</html>
"""


"""
Run Code Online (Sandbox Code Playgroud)

我想将<h1>标签和它们的下一个标签包装在<section>标签中,如下所示:

<html>
<head>
  <title>The Dormouse's story</title>
</head>
<body>

  <section>
    <h1 id="first-paragraph">First paragraph</h1>
    <p>Some text...</p>
    <p>Another text...</p>
    <div>
      <a href="http://link.com">Here's a link</a>
    </div>
  </section>

  <section>
    <h1 id="second-paragraph">Second paragraph</h1>
    <p>Some text...</p>
    <p>Another text...</p>
  </section>

  <script src="lib/.js"></script>
</body>

</html>
Run Code Online (Sandbox Code Playgroud)

以下是我进行选择的方式:

from bs4 import BeautifulSoup
import itertools
soup = BeautifulSoup(html_doc)
h1s = soup.find_all('h1')
for el in h1s:
    els = [i for i in itertools.takewhile(lambda x: x.name not in [el.name, 'script'], el.next_elements)]
    els.insert(0, el)
    print(els)
Run Code Online (Sandbox Code Playgroud)

输出:

[<h1 id="first-paragraph">First paragraph</h1>, 'First paragraph', '\n  ', <p>Some text...</p>, 'Some text...', '\n  ', <p>Another text...</p>, 'Another text...', '\n  ', <div><a href="http://link.com">Here's a link</a>  </div>, '\n    ', <a href="http://link.com">Here's a link</a>, "Here's a link", '\n  ', '\n\n  ']

[<h1 id="second-paragraph">Second paragraph</h1>, 'Second paragraph', '\n  ', <p>Some text...</p>, 'Some text...', '\n  ', <p>Another text...</p>, 'Another text...', '\n\n  ']
Run Code Online (Sandbox Code Playgroud)

选择是正确的,但我看不到如何将每个选择包装在<section>标签中。

Ben*_*Ben 6

最后我找到了wrap在这种情况下如何使用该方法。我需要了解汤对象中的每一个更改都已就位。

from bs4 import BeautifulSoup
import itertools
soup = BeautifulSoup(html_doc)

# wrap all h1 and next siblings into sections
h1s = soup.find_all('h1')
for el in h1s:
    els = [i for i in itertools.takewhile(
              lambda x: x.name not in [el.name, 'script'],
              el.next_siblings)]
    section = soup.new_tag('section')
    el.wrap(section)
    for tag in els:
        section.append(tag)

print(soup.prettify())
Run Code Online (Sandbox Code Playgroud)

这给了我想要的输出。希望这是有帮助的。

  • 谢谢你。我想指出一些我学到的可能并不明显的东西。1)在其他地方附加标签(例如通过附加)将其从以前的位置删除。2) 由于 (1) 并且因为 .next_siblings 是一个生成器,而不是一个列表,您需要在遍历调用 section.append(tag) 的循环之前将其转换为列表,您的复杂 `els=[... ]` 就是这样做的。我不需要过滤,所以我只尝试了`els=el.next_siblings`。这失败了,因为同级的第一个动作打破了同级链。`els=list(el.next_siblings)` 有效。 (2认同)