Skip to content

Combinators and Selector Lists

CSS employs a number of tokens in order to represent lists or to provide relational context between two selectors.

Selector Lists

Selector lists use the comma (,) to join multiple selectors in a list. When presented with a selector list, any selector in the list that matches an element will return that element.

element1, element2
>>> from bs4 import BeautifulSoup as bs
>>> html = """
... <html>
... <head></head>
... <body>
... <h1>Title</h1>
... <p>Paragraph</p>
... </body>
... </html>
... """
>>> soup = bs(html, 'html5lib')
>>> soup.select('h1, p')
[<h1>Title</h1>, <p>Paragraph</p>]

Descendant Combinator

Descendant combinators combine two selectors with whitespace ( ) in order to signify that the second element is matched if it has an ancestor that matches the first element.

parent descendant
>>> from bs4 import BeautifulSoup as bs
>>> html = """
... <html>
... <head></head>
... <body>
... <div><p>Paragraph 1</p></div>
... <div><p>Paragraph 2</p></div>
... </body>
... </html>
... """
>>> soup = bs(html, 'html5lib')
>>> soup.select('body p')
[<p>Paragraph 1</p>, <p>Paragraph 2</p>]

Warning

Selectors like the descendant and subsequent sibling combinators (a b and a ~ b) often cause entire subtrees of the main document tree to be crawled when evaluating a single element. If used poorly, this can impact performance in a non-linear ways. It should be noted that Soup Sieve employs caching to reduce performance concerns in various cases, but there will always be the potential produce non-linear cases simply due to how the selectors work.

Child combinator

Child combinators combine two selectors with > in order to signify that the second element is matched if it has a parent that matches the first element.

parent > child
>>> from bs4 import BeautifulSoup as bs
>>> html = """
... <html>
... <head></head>
... <body>
... <div><p>Paragraph 1</p></div>
... <div><ul><li><p>Paragraph 2</p></li></ul></div>
... </body>
... </html>
... """
>>> soup = bs(html, 'html5lib')
>>> soup.select('div > p')
[<p>Paragraph 1</p>]

General Sibling Combinator

General sibling combinators combine two selectors with ~ in order to signify that the second element is matched if it has a sibling that precedes it that matches the first element.

prevsibling ~ sibling
>>> from bs4 import BeautifulSoup as bs
>>> html = """
... <html>
... <head></head>
... <body>
... <h1>Title</h1>
... <p>Paragraph 1</p>
... <p>Paragraph 2</p>
... </body>
... </html>
... """
>>> soup = bs(html, 'html5lib')
>>> soup.select('h1 ~ p')
[<p>Paragraph 1</p>, <p>Paragraph 2</p>]

Warning

Selectors like the descendant and subsequent sibling combinators (a b and a ~ b) often cause entire subtrees of the main document tree to be crawled when evaluating a single element. If used poorly, this can impact performance in a non-linear ways. It should be noted that Soup Sieve employs caching to reduce performance concerns in various cases, but there will always be the potential produce non-linear cases simply due to how the selectors work.

Adjacent Sibling Combinator

Adjacent sibling combinators combine two selectors with + in order to signify that the second element is matched if it has an adjacent sibling that precedes it that matches the first element.

prevsibling + nextsibling
>>> from bs4 import BeautifulSoup as bs
>>> html = """
... <html>
... <head></head>
... <body>
... <h1>Title</h1>
... <p>Paragraph 1</p>
... <p>Paragraph 2</p>
... </body>
... </html>
... """
>>> soup = bs(html, 'html5lib')
>>> soup.select('h1 + p')
[<p>Paragraph 1</p>]