Kinds of Objects
Beautiful Soup's tree is made of a small set of object types. Knowing them stops surprises: a tag's .string is a NavigableString, .contents is a list of mixed types, and the soup object itself is a special tag.
The Four Types
- Tag - an HTML or XML element, represented by a bs4.element.Tag object with a name, attributes, and children.
- NavigableString - a string of text found in the document.
- BeautifulSoup - the whole document; a Tag subclass named "[document]" whose .contents hold the root elements.
- Comment - an HTML comment, a NavigableString subclass that behaves like text but knows it is a comment.
Inspecting Types
from bs4 import BeautifulSoup
from bs4.element import Comment, NavigableString, Tag
html = "<div><!-- hidden --><p>Hi</p></div>"
soup = BeautifulSoup(html, "html.parser")
print(type(soup)) # <class 'bs4.BeautifulSoup'>
print(type(soup.div)) # <class 'bs4.element.Tag'>
print(type(soup.p.string)) # <class 'bs4.element.NavigableString'>
print(type(soup.div.contents[0])) # <class 'bs4.element.Comment'>
Practical Checks
When iterating .contents you will see tags and strings mixed together, so filter by type:
for child in soup.div.children:
if isinstance(child, Tag):
print("tag:", child.name)
elif isinstance(child, Comment):
print("comment:", child)
elif isinstance(child, NavigableString):
print("text:", str(child).strip())
Tag Anatomy
A Tag exposes .name, .attrs (the attribute dict), .string (only when there is exactly one text child), .contents (direct children), and navigation properties you will meet in the next chapters.
Summary
A Beautiful Soup document is a tree of Tags, NavigableStrings, and Comments, wrapped by a BeautifulSoup root that is itself a tag. Use isinstance checks with Tag, NavigableString, and Comment when iterating mixed children, and remember that .string only exists when a tag has a single text child.