Parents and Siblings Navigation
Beautiful Soup lets you move up and sideways in the tree. From any node you can reach its parent and grandparents with .parent and .parents, and its horizontal neighbors with .next_sibling and .previous_sibling.
.parent - One Level Up
from bs4 import BeautifulSoup
html = "<table><tr><td>cell</td></tr></table>"
soup = BeautifulSoup(html, "html.parser")
td = soup.find("td")
print(td.parent.name) # tr
print(td.parent.parent.name) # table
If the node has no parent (it is the root), .parent is None.
.parents - All Ancestors
for p in td.parents:
print(p.name) # tr, table, [document]
.parents walks upward to the root, yielding each ancestor tag in order. It is useful for "find the enclosing section" problems:
def enclosing(tag, name):
for p in tag.parents:
if p.name == name:
return p
return None
.next_sibling and .previous_sibling
Siblings are the nodes immediately before or after you in the parent's .contents. Text nodes count as siblings, so you will often see whitespace strings:
html = "<ul><li>one</li><li>two</li></ul>"
soup = BeautifulSoup(html, "html.parser")
li = soup.find("li")
print(repr(str(li.next_sibling)).strip()) # whitespace text node
print(li.next_sibling.next_sibling.name) # the second <li>
.next_siblings and .previous_siblings
The plural forms are generators over all following or preceding siblings, which is cleaner than chaining .next_sibling twice:
for sib in soup.find("li").next_siblings:
if getattr(sib, "name", None) == "li":
print(sib.get_text()) # two
Summary
Move up the tree with .parent and .parents, and sideways with .next_sibling, .previous_sibling, and their plural generator forms. Remember that whitespace text nodes are siblings too, so filter by tag name when you only want elements.