The parse tree

Tags, .name, .contents, and NavigableString.

The soup is a tree of Tag objects. .name is the tag name. .contents is the list of direct children (including text and whitespace).

Goal

Print tag names, contents, and the type of a text node.

Names

html = """
<html>
  <body>
    <h1>Nairobi kiosk</h1>
    <p>Open today.</p>
  </body>
</html>
"""
soup = BeautifulSoup(html, "html.parser")
print(soup.html.name)
print(soup.body.name)
print([child.name for child in soup.body.children if getattr(child, "name", None)])

Whitespace text nodes have name of None. The if getattr filter keeps real tags.

Contents vs string

html = "<p>Hello <strong>Nairobi</strong></p>"
soup = BeautifulSoup(html, "html.parser")
p = soup.p
print("contents", p.contents)
print("string", p.string)
print("get_text", p.get_text())

.string is None when the tag has more than one child. Use get_text() in that case.

Tip

soup.body is the same as soup.find("body"). Dot-access is a shortcut for the first match.