DOM traversal
Once you have an element, you often need the ones around it: its children, its siblings, elements inside a shadow root, or content inside an iframe. This guide covers moving through the DOM tree from a known starting point. To locate that starting element in the first place, see Element finding.
Get child elements
get_children_elements() returns the descendants of an element. max_depth controls how deep it goes (1 is direct children only), and tag_filter keeps only the tags you name.
from pydoll.sync import Chrome
def main():
with Chrome() as browser:
tab = browser.start()
tab.go_to('https://books.toscrape.com')
container = tab.find(class_name='row', tag_name='ol')
direct = container.get_children_elements(max_depth=1)
print(f'{len(direct)} direct children')
# descendants up to 2 levels deep, links only
links = container.get_children_elements(max_depth=2, tag_filter=['a'])
print(f'{len(links)} links within two levels')
main()
import asyncio
from pydoll import Chrome
async def main():
async with Chrome() as browser:
tab = await browser.start()
await tab.go_to('https://books.toscrape.com')
container = await tab.find(class_name='row', tag_name='ol')
direct = await container.get_children_elements(max_depth=1)
print(f'{len(direct)} direct children')
# descendants up to 2 levels deep, links only
links = await container.get_children_elements(max_depth=2, tag_filter=['a'])
print(f'{len(links)} links within two levels')
asyncio.run(main())
Get sibling elements
get_siblings_elements() returns the elements at the same level as your element, excluding it. tag_filter narrows the result to specific tags.
Scoped search vs direct children
A scoped find() or query() searches all descendants of an element. When you want only the direct children, use the CSS child combinator > or an XPath step, which query() accepts:
Use get_children_elements() when you want to explore structure or filter by tag; use a scoped find()/query() when you want elements matching specific attributes anywhere in the subtree.
Read text and attributes
From any element you can read its visible text and its HTML attributes:
text() returns the element's visible text; get_attribute(name) returns the attribute string, or None when the attribute is absent.
Shadow DOM
Many components hide their internals inside a shadow root, which regular DOM queries can't see. Access the shadow host, get its shadow root, then search inside it.
Inside a shadow root, use query() with CSS
find() and XPath are not supported on a ShadowRoot and raise NotImplementedError. Search shadow roots with query() and CSS selectors only.
query() inside a shadow root takes the usual find_all, timeout, and raise_exc parameters:
Web components nest, so a shadow root can contain another shadow host:
Discover shadow roots on a page
When you don't know which shadow roots exist (debugging, or dynamic widgets like Cloudflare Turnstile), find_shadow_roots() returns all of them. Shadow hosts often load late, so pass timeout to poll until they appear:
By default the search covers the main document (including same-origin iframes). Pass deep=True to also reach shadow roots inside cross-origin iframes (OOPIFs), which is what widgets like Turnstile use:
Work inside an iframe
An iframe has its own DOM context. Find the iframe element, then call find() or query() on it; Pydoll routes the search into the frame automatically. Keep chaining for nested iframes.
For a full iframe guide including CAPTCHA frames and troubleshooting, see Iframes.
Screenshots inside iframes
tab.take_screenshot() captures the top-level page only. To capture iframe content, find an element inside the frame and call element.take_screenshot().
What's next
- Element finding: locate the elements you traverse from.
- Iframes: the complete guide to frame contexts.
- Structured extraction: let a model walk repeating structures for you.