Contents, Children and Descendants
A tag's children are the nodes directly inside it. Beautiful Soup exposes three related views: .contents (a list of direct children), .children (a generator over the same), and .descendants (a generator over everything nested, at any depth).
.contents - Direct Children as a List
from bs4 import BeautifulSoup
html = "<div><p>a</p><p>b</p><!-- note --></div>"
soup = BeautifulSoup(html, "html.parser")
print(soup.div.contents)
# [<p>a</p>, <p>b</p>, <!-- note -->]
print(len(soup.div.contents)) # 3
.contents is a plain list, so you can index and slice it: soup.div.contents[0] is the first child.
.children - Iterate Direct Children
for child in soup.div.children:
print(child.name if child.name else repr(str(child)))
.children is a generator: it yields each direct child once, without building a list in memory. It also yields text nodes and comments, not just tags.
.descendants - Everything Nested
html = "<div><p><b>x</b></p></div>"
soup = BeautifulSoup(html, "html.parser")
for d in soup.div.descendants:
print(repr(str(d))[:40])
.descendants walks the whole subtree in document order: tags, strings, and comments at every depth. It includes the whitespace text nodes between elements.
Which One to Use
- .contents when you need a count, indexing, or one-off processing of direct children.
- .children when you want to iterate direct children without materializing a list.
- .descendants when you need every node in the subtree, for example to strip all text.
Summary
.contents gives a list of a tag's direct children, .children gives a generator over the same nodes, and .descendants gives a generator over the entire nested subtree. All three include text nodes and comments, so filter by type when you only want tags.