Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use .next_sibling or .previous_sibling to move to the immediately adjacent node in Beautiful Soup’s parse tree. For the next or previous matching tag—skipping intervening whitespace and other non-matching nodes—use find_next_sibling() or find_previous_sibling(). To retrieve several matches, use the plural methods or iterate over .next_siblings and .previous_siblings.

Parse the HTML and find your starting node

Sibling navigation starts with a parsed tree and a node to navigate from. In this example, the target is the summary paragraph inside a card:

from bs4 import BeautifulSoup

html = '''
<div class="card">
  <h2>Title</h2>
  <p class="summary">Summary</p>
  <p class="details">Details</p>
</div>
'''

soup = BeautifulSoup(html, "html.parser")
summary = soup.find("p", class_="summary")

if summary is None:
    raise ValueError("Could not find the summary paragraph")

Passing "html.parser" explicitly makes the parser choice visible in the code. Beautiful Soup’s documentation warns that parser choice can affect the resulting tree; malformed markup or a different parser can therefore change which nodes are adjacent. The documentation page identifies Beautiful Soup 4.14.3.

Once you have the target, choose a sibling method based on whether you need the physically adjacent node or the closest node that matches a condition.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Get the immediately adjacent node

The singular properties return the adjacent node in the same parent’s child list:

next_node = summary.next_sibling
previous_node = summary.previous_sibling

print(repr(next_node))
print(repr(previous_node))

These properties do not mean “next tag.” They mean the next or previous node, whatever its type. With indented HTML, the node adjacent to a tag is often a NavigableString containing a newline and spaces. Punctuation or other text between tags can also be returned.

For example, the next node after the summary paragraph in the sample markup may be the newline and indentation before the details paragraph, rather than the details tag itself. This is why printing repr() is useful when inspecting an unexpected result: it makes whitespace visible.

Skip text nodes when you need the next tag

If you specifically need the next tag in sibling order, advance past strings before using the result:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
from bs4 import NavigableString

node = summary.next_sibling
while node is not None and isinstance(node, NavigableString):
    node = node.next_sibling

if node is not None:
    print(node.name)
    print(node.get_text(" ", strip=True))

The loop checks for None because there may be no later sibling. It also skips all NavigableString nodes, not only indentation. If meaningful text between tags matters to your extraction, do not discard it this way; use a matching method when the task is to find a particular tag.

Find the nearest matching sibling

For most extraction tasks, a matching method is clearer than manually stepping through adjacent nodes. find_next_sibling() searches later siblings and returns the first match; find_previous_sibling() searches earlier siblings in reverse document order.

next_paragraph = summary.find_next_sibling("p")
previous_heading = summary.find_previous_sibling("h2")

if next_paragraph is not None:
    print(next_paragraph.get_text(" ", strip=True))

if previous_heading is not None:
    print(previous_heading.get_text(" ", strip=True))

In the sample card, the next matching paragraph is the details paragraph. The method can move past whitespace strings and other nodes that do not match the requested tag. It does not search arbitrary descendants or the whole document: it looks among siblings of the starting node.

Filter by a class or attribute

Matching methods accept the same kinds of filters used by Beautiful Soup’s search methods, including tag names, attributes, strings, and keyword attribute filters:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
# The first later paragraph with this class
next_detail = summary.find_next_sibling("p", class_="details")

# A preceding table row with a particular attribute
previous_row = cell.find_previous_sibling(
    "tr", attrs={"data-state": "ready"}
)

Use class_ for a class filter in Python code. For attributes that do not map conveniently to keyword arguments, pass an attrs dictionary. If no sibling matches, the singular method returns None; check that result before accessing tag properties such as .name or calling .get_text().

Collect all matching siblings

Use the plural methods when you need every matching sibling in one direction. They return a list and accept a limit as well as the matching filters:

all_paragraphs_after = summary.find_next_siblings("p")
all_paragraphs_before = summary.find_previous_siblings("p")

first_three_links = first_link.find_next_siblings(
    "a", class_="sister", limit=3
)

For a matching-method search, the returned values are the matching tags, not the intervening whitespace nodes. Use find_next_siblings() when you need to filter to particular tags or attributes; use the sibling generators when you want to inspect every node, including strings.

Iterate over every later or earlier node

for node in summary.next_siblings:
    print(repr(node))

for node in summary.previous_siblings:
    print(repr(node))

These generators include strings as well as tags. If the loop should act only on tags, test the node type:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
for node in summary.next_siblings:
    if getattr(node, "name", None) is not None:
        print(node.name, node.get_text(" ", strip=True))

The first yielded node is the nearest sibling in that direction. The plural matching methods and generators answer different questions: one returns all nodes matching your filters, while the other lets you examine the full sequence and decide what to keep.

Know what counts as a sibling

Two nodes are siblings when they have the same parent in the parsed tree. They are not necessarily adjacent in the source text once whitespace and other nodes are counted, and nodes that merely appear next to one another on a rendered page are not necessarily siblings.

For example, the text inside a <b> tag and the text inside a neighboring <c> tag have different parents: each text node belongs to its own tag. The tags may be siblings, but their contents are not siblings of each other. Start navigation from the element whose position matters, then verify that the intended target shares its parent.

Sibling navigation is not document-order navigation

.next_sibling stays among nodes under the same parent. .next_element follows document order instead, which can descend into a node’s children and then continue elsewhere in the tree. If a sibling lookup seems to stop before a visible element, check the HTML structure and parent relationships rather than substituting .next_element without considering that broader traversal.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the right method

Need Use What to expect
The adjacent node only .next_sibling or .previous_sibling May return whitespace, punctuation, text, or a tag.
The nearest later or earlier matching tag .find_next_sibling() or .find_previous_sibling() Returns the first sibling that matches your filters, or None.
All matching siblings in one direction .find_next_siblings() or .find_previous_siblings() Returns matching siblings as a list; filters and a limit can narrow the result.
Every intervening node in order .next_siblings or .previous_siblings Yields tags and strings so you can apply your own logic.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshoot unexpected results

next_sibling returns a newline or spaces

This is expected for indented HTML: the immediate node is often a whitespace string. Use find_next_sibling("tagname") for the closest matching tag, or explicitly advance over strings if you need direct navigation.

A matching method returns None or an empty list

Check the starting node, direction, tag name, and filters. The desired element may be a descendant, an ancestor, or elsewhere in the document rather than a sibling. Also check whether its attribute value matches the filter you supplied.

The result changes with the parser

Beautiful Soup builds a tree from the source, and parser choice can produce a different parse tree. Keep the parser explicit, inspect the parsed structure and parent relationships, and confirm that your input markup is well formed enough for the structure you expect.

The code fails when no match exists

A singular matching method can return None. Guard against that before calling tag methods:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
match = summary.find_next_sibling("p", class_="details")
if match is None:
    print("No matching later paragraph")
else:
    print(match.get_text(" ", strip=True))

A loop misses text or removes too much

Sibling generators include strings, while a loop that skips every NavigableString discards both whitespace and meaningful text. Decide whether your task needs only tags or needs to preserve text nodes, and filter accordingly.

Or skip the browser setup

If your actual goal is to capture a webpage rather than inspect its parsed HTML yourself, ScreenshotNeo offers a screenshot API and MCP server. Its clean-shot options accept cookie or consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and responses identify the page verdict and billing status in headers. AI agents can use its MCP server tools to take screenshots, get page information, or capture PDFs. The free plan includes 1,000 screenshots a month without a card; paid plans start at $5 for 3,000 screenshots.

Here is a one-request cURL example that saves a WebP screenshot:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for setup and request options. ScreenshotNeo also supports PNG, JPEG, or PDF output and options such as full-page capture, selector-based capture, viewport and device settings, and custom CSS or JavaScript. Sign up for ScreenshotNeo to get 1,000 free screenshots a month, with no card required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Can I use a CSS selector to find a sibling in Beautiful Soup?

The sibling methods use Beautiful Soup’s tag, attribute, string, and keyword filters; they are not CSS-selector methods.

Do the plural sibling methods return generators?

No. The plural find methods return a list of matching siblings. The properties .next_siblings and .previous_siblings provide iterators over sibling nodes.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.