Сообщить об ошибке.

CSS селекторы и модуль BeautifulSoup4 в Python

Поиск по CSS селекторам (справочное руководство)

В модуле BeautifulSoup4 есть метод BeautifulSoup.select(), который использует SoupSieve, чтобы запустить CSS селектор и вернуть все подходящие элементы. В объекте Tag есть похожий метод, который запускает CSS селектор в отношении содержимого одного тега.

Интеграция SoupSieve была добавлена в BeautifulSoup4.7.0. В более ранних версиях также есть метод .select(), но он поддерживат только самые часто используемые селекторы CSS. Если BeautifulSoup4 устанавливался через pip, то одновременно должен был установиться SoupSieve.

Содержание:


Базовые CSS-селекторы.

Поиск по имени/названию HTML-тега.

Синтаксис:

  • element
>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
  <div>Here is some text.</div>
  <div>Here is some more text.</div>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('div')
# [<div>Here is some text.</div>, 
# <div>Here is some more text.</div>]

Поиск по индификатору HTML-тега.

Синтаксис:

  • #id
>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
   <div id="some-id">Here is some text.</div>
   <div>Here is some more text.</div>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('#some-id')
# [<div id="some-id">Here is some text.</div>]

Поиск по классу HTML-тега.

Синтаксис:

  • .class
>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
   <div class="some-class">Here is some text.</div>
   <div>Here is some more text.</div>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('.some-class')
# [<div class="some-class">Here is some text.</div>]

Поиск по атрибутам HTML-тега.

[attribute]:

Ищет HTML-элементы с атрибутом attribute.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<ul>
  <li><a href="#internal">Internal link</a></li>
  <li><a href="http://example.com">Example link</a></li>
  <li><a href="#InSensitive">Insensitive internal link</a></li>
  <li><a href="http://example.org">Example org link</a></li>
</ul>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('[href]')
# [<a href="#internal">Internal link</a>, 
# <a href="http://example.com">Example link</a>, 
# <a href="#InSensitive">Insensitive internal link</a>, 
# <a href="http://example.org">Example org link</a>]

[attribute="value"]:

Ищет HTML-элементы с атрибутом attribute, который имеет значение value.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<ul>
  <li><a href="#internal">Internal link</a></li>
  <li><a href="http://example.com">Example link</a></li>
  <li><a href="#InSensitive">Insensitive internal link</a></li>
  <li><a href="http://example.org">Example org link</a></li>
</ul>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('[href="#internal"]')
# [<a href="#internal">Internal link</a>]

[attribute~="value"]:

Ищет HTML-элементы с атрибутом attribute, где значение value встречается в строке, представляющей список разделенный пробелом.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<ul>
  <li><a href="#internal" class="class1 class2 class3">Internal link</a></li>
  <li><a href="http://example.com">Example link</a></li>
  <li><a href="#InSensitive">Insensitive internal link</a></li>
  <li><a href="http://example.org">Example org link</a></li>
</ul>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('[class~=class2]')
# [<a class="class1 class2 class3" href="#internal">Internal link</a>]

[attribute|="value"]:

Ищет HTML-элементы с атрибутом attribute, значение которого представляет собой список разделенный черточками, и который начинается со значения value.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<div lang="en">Some text</div>
<div lang="en-US">Some more text</div>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('div[lang|="en"]')
# [<div lang="en">Some text</div>, 
# <div lang="en-US">Some more text</div>]

[attribute^="value"]:

Ищет HTML-элементы с атрибутом attribute, значение которого начинается с value.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<ul>
  <li><a href="#internal">Internal link</a></li>
  <li><a href="http://example.com">Example link</a></li>
  <li><a href="#InSensitive">Insensitive internal link</a></li>
  <li><a href="http://example.org">Example org link</a></li>
</ul>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('[href^=http]')
# [<a href="http://example.com">Example link</a>, 
# <a href="http://example.org">Example org link</a>]

[attribute$="value"]:

Ищет HTML-элементы с атрибутом attribute, значение которого заканчивается на value.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<ul>
  <li><a href="#internal">Internal link</a></li>
  <li><a href="http://example.com">Example link</a></li>
  <li><a href="#InSensitive">Insensitive internal link</a></li>
  <li><a href="http://example.org">Example org link</a></li>
</ul>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('[href$=org]')
# [<a href="http://example.org">Example org link</a>]

[attribute*="value"]:

Ищет HTML-элементы с атрибутом attribute, значение которого содержит подстроку value.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<html>
<head></head>
<body>
<ul>
  <li><a href="#internal">Internal link</a></li>
  <li><a href="http://example.com">Example link</a></li>
  <li><a href="#InSensitive">Insensitive internal link</a></li>
  <li><a href="http://example.org">Example org link</a></li>
</ul>
</body>
</html>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('[href*="example"]')
# [<a href="http://example.com">Example link</a>, 
# <a href="http://example.org">Example org link</a>]

[attribute!="value"]:

Ищет HTML-элементы с атрибутом attribute, значение которого НЕ равно value (эквивалентно :not([attribute=value])).

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<ul>
  <li><a href="#internal">Internal link</a></li>
  <li><a href="http://example.com">Example link</a></li>
  <li><a href="#InSensitive">Insensitive internal link</a></li>
  <li><a href="http://example.org">Example org link</a></li>
</ul>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('a[href!="#internal"]')
# или
>>> soup.select('a:not([href="#internal"])')
# [<a href="http://example.com">Example link</a>, 
# <a href="#InSensitive">Insensitive internal link</a>, 
# <a href="http://example.org">Example org link</a>]

[attribute="value" s]:

Ищет HTML-элементы с атрибутом attribute, значение которого совпадает с value с учетом регистра.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<ul>
  <li><a href="#internal">Internal link</a></li>
  <li><a href="http://example.com">Example link</a></li>
  <li><a href="#InSensitive">Insensitive internal link</a></li>
  <li><a href="http://example.org">Example org link</a></li>
</ul>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('[href="#INTERNAL" s]')
# []
>>> soup.select('[href="#internal" s]')
# [<a href="#internal">Internal link</a>]

Комбинаторы и списки селекторов.

Списки селекторов.

Для объединения нескольких селекторов в списке, необходимо использовать запятую, например 'h1, p'. При представлении списка селекторов любой селектор в списке, соответствующий HTML-тегу, вернет этот элемент.

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

Комбинатор потомков.

Комбинаторы потомков объединяют два селектора пробелами, например 'body p'. Это означает, что второй элемент будет найден только в том случае, если у него есть предок, соответствующий первому элементу.

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

Комбинатор дочерних элементов.

Комбинатор дочерних элементов объединяют два селектора знаком >, например 'div > p'. Это означает, что второй элемент будет найден только в том случае, если у него есть родитель, соответствующий первому элементу.

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

Комбинатор одноуровневых соседей.

Комбинаторы одноуровневых соседей объединяют два селектора знаком ~, например 'h1 ~ p'. Это означает, что второй элемент будет найден только в том случае, если у него есть одноуровневый сосед, который предшествует ему, и соответствует первому элементу.

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

Комбинатор соседнего элемента.

Комбинатор соседнего элемента объединяет два селектора знаком +, например 'h1 + p'. Это означает, что второй элемент будет найден только в том случае, если перед ним непосредственно находится сосед, который соответствует первому элементу.

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

Псевдоклассы.

Здесь представлены псевдоклассы, которые поддерживаются полностью или частично. Частичная поддержка обычно связана с ограничениями, связанными с отсутствием активной среды браузера.

Любые селекторы, которые не указаны здесь относятся к категории неприменимых.

:link:

Выбирает каждый элемент <a> или <area>, имеющий атрибут href, независимо от того, посещался ли он.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<p>A link to <a href="http://example.com">click</a></p>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select(':link')
# [<a href="http://example.com">click</a>]

:checked:

Выбирает любой элемент <input type="radio"/>, <input type="checkbox"/> или <option> (в элементе <select>), который отмечен или переключен в состояние включено.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>

<div>
  <input type="radio" name="my-input" id="yes" checked>
  <label for="yes">Yes</label>
  <input type="radio" name="my-input" id="no">
  <label for="no">No</label>
</div>
<select name="my-select" id="fruit">
  <option id="1" value="opt1">Apples</option>
  <option id="2" value="opt2" selected>Grapes</option>
  <option id="3" value="opt3">Pears</option>
</select>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select(':checked')
# [<input checked="" id="yes" name="my-input" type="radio"/>, 
# <option id="2" selected="" value="opt2">Grapes</option>]

:default:

Выбирает любой элемент формы, который является элементом по умолчанию среди группы связанных элементов, в том числе: <button>, <input type="radio"/>, <input type="checkbox"/> и <option> (в элементе <select>) .

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<form>
<input type="radio" name="season" id="spring">
<label for="spring">Spring</label>
<input type="radio" name="season" id="summer" checked>
<label for="summer">Summer</label>
<input type="radio" name="season" id="fall">
<label for="fall">Fall</label>
<input type="radio" name="season" id="winter">
<label for="winter">Winter</label>
<select id="pet-select">
    <option value="">--Please choose an option--</option>
    <option id="dog" value="dog">Dog</option>
    <option id="cat" value="cat">Cat</option>
    <option id="hamster" value="hamster" selected>Hamster</option>
    <option id="parrot" value="parrot">Parrot</option>
    <option id="spider" value="spider">Spider</option>
    <option id="goldfish" value="goldfish">Goldfish</option>
</select>
</form>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select(':default')
# [<input checked="" id="summer" name="season" type="radio"/>, 
# <option id="hamster" selected="" value="hamster">Hamster</option>]

:disabled:

Выбирает любой отключенный элемент.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<form action="#">
  <fieldset id="shipping">
    <legend>Shipping address</legend>
    <input type="text" placeholder="Name">
    <input type="text" placeholder="Address">
    <input type="text" placeholder="Zip Code">
  </fieldset>
  <br>
  <fieldset id="billing">
    <legend>Billing address</legend>
    <label for="billing-checkbox">Same as shipping address:</label>
    <input type="checkbox" id="billing-checkbox" checked>
    <br>
    <input type="text" placeholder="Name" disabled>
    <input type="text" placeholder="Address" disabled>
    <input type="text" placeholder="Zip Code" disabled>
  </fieldset>
</form>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('input:disabled')
# [<input disabled="" placeholder="Name" type="text"/>, 
# <input disabled="" placeholder="Address" type="text"/>, 
# <input disabled="" placeholder="Zip Code" type="text"/>]

:empty:

Выбирает элементы, у которых нет дочерних элементов и текста (пробелы игнорируются).

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<span> <!-- comment --> </span>
<span></span>
<span><span>    </span></span>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('body:empty')
# [<span> <!-- comment --> </span>,
# <span></span>,
# <span>    </span>]

:enabled:

Выбирает любой активный/включенный элемент.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<form action="#">
  <fieldset id="shipping">
    <legend>Shipping address</legend>
    <input type="text" placeholder="Name">
    <input type="text" placeholder="Address">
    <input type="text" placeholder="Zip Code">
  </fieldset>
  <br>
  <fieldset id="billing">
    <legend>Billing address</legend>
    <label for="billing-checkbox">Same as shipping address:</label>
    <input type="checkbox" id="billing-checkbox" checked>
    <br>
    <input type="text" placeholder="Name" disabled>
    <input type="text" placeholder="Address" disabled>
    <input type="text" placeholder="Zip Code" disabled>
  </fieldset>
</form>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('input:enabled')
# [<input placeholder="Name" type="text"/>, 
# <input placeholder="Address" type="text"/>, 
# <input placeholder="Zip Code" type="text"/>, 
# <input checked="" id="billing-checkbox" type="checkbox"/>]

:first-child:

Выбирает первый элемент в группе одноуровневых элементов.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<p id="0"></p>
<p id="1"></p>
<p id="2"></p>
<p id="3"></p>
<p id="4"></p>
<p id="5"></p>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('p:first-child')
# [<p id="0"></p>]

:first-of-type:

Выбирает первый элемент данного типа в группе родственных элементов.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<p id="0"></p>
<p id="1"></p>
<span id="2"></span>
<span id="3"></span>
<span id="4"></span>
<span id="5"></span>
<span id="6"></span>
<p id="7"></p>
<p id="8"></p>
<p id="9"></p>
<p id="10"></p>
<span id="11"></span>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('span:first-of-type')
# [<span id="2"></span>]

:has():

Выбирает элемент, если какой-либо из относительных селекторов, переданных в качестве параметров (которые относятся к :scope данного элемента), соответствует хотя бы одному элементу.

Спецификации CSS4 говорится, что :has() поддерживают составные селекторы, а сложные селекторы запланированы для селекторов CSS5. BeautifulSoup4 поддерживает сложные селекторы.

Синтаксис:

  • :has(selector);
  • :has(> selector);
  • :has(~ selector);
  • :has(+ selector);
  • :has(selector1, > selector2, ~ selector3, + selector4);
>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<div><p>Test <span>paragraph</span></p></div>
<div><p class="class">Another test paragraph</p></div>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('div:has(span, > .class)')
# [<div><p>Test <span>paragraph</span></p></div>, 
# <div><p class="class">Another test paragraph</p></div>]

:in-range:

Выбирает все <input>, значения которых находятся в диапазоне в соответствии с их атрибутами type, min, и max.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<input id="0" type="month" min="1980-02" max="2004-08" value="1999-05">
<input id="7" type="month" min="1980-02" max="2004-08" value="1979-02">
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select(':in-range')
# [<input id="0" max="2004-08" min="1980-02" type="month" value="1999-05"/>]

:indeterminate:

Выбирает все элементы формы, которые находятся в неопределенном состоянии.

Элемент считается неопределенным, если:

  • У <input type="checkbox"/> установлен атрибут indeterminate.
  • Группа <input type="radio"/> с одинаковым значением атрибута name не имеет выбранного значения checked.
  • Элемент имеет тип <progress> без значения.
>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<input type="checkbox" id="checkbox1" indeterminate>
<label for="checkbox1">I like cats.</label>
<input type="checkbox" id="checkbox2">
<label for="checkbox2">I like dogs.</label>
<form>
    <input type="radio" name="test" id="radio1">
    <label for="radio1">Yes</label>
    <input type="radio" name="test" id="radio2">
    <label for="radio2">No</label>
    <input type="radio" name="test" id="radio3">
    <label for="radio3">Maybe</label>
</form>
<form>
    <input type="radio" name="another" id="radio4">
    <label for="radio4">Red</label>
    <input type="radio" name="another" id="radio5" checked>
    <label for="radio5">Green</label>
    <input type="radio" name="another" id="radio6">
    <label for="radio6">Blue</label>
</form>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select(':indeterminate')
# [<input id="checkbox1" indeterminate="" type="checkbox"/>, 
# <input id="radio1" name="test" type="radio"/>, 
# <input id="radio2" name="test" type="radio"/>, 
# <input id="radio3" name="test" type="radio"/>]

:is():

Выбирает элемент, но только если он соответствует хотя бы одному селектору в списке селекторов.

Также поддерживается псевдоним :matches() , т.к. это было исходное имя селектора, и некоторые браузеры до сих пор его поддерживают. Настоятельно рекомендуется использовать :is(), поскольку поддержка :matches() может быть удалена в будущем.

Хотя в спецификациях CSS4 указано, что поддерживаются составные селекторы, некоторые браузеры (например Safari) поддерживают сложные селекторы, которые запланированы для селекторов CSS5. BeautifulSoup4 также поддерживает сложные селекторы.

Синтаксис:

  • :is(selector1, selector2)
>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<p id="0">Some text <span id="1"> in a paragraph</span>.
<a id="2" href="http://google.com">Link.</a></p>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('[id]:is(a, span)')
# [<span id="1"> in a paragraph</span>, 
# <a href="http://google.com" id="2">Link.</a>]

:last-child:

Выбирает последний элемент из группы родственных элементов.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<p id="0"></p>
<p id="1"></p>
<p id="2"></p>
<p id="3"></p>
<p id="4"></p>
<p id="5"></p>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('p:last-child')
# [<p id="5"></p>]

:last-of-type:

Выбирает последний элемент данного типа в группе родственных элементов. Если перевести "last of type", то получится последний в своем роде.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<p id="0"></p>
<p id="1"></p>
<span id="2"></span>
<span id="3"></span>
<span id="4"></span>
<span id="5"></span>
<span id="6"></span>
<p id="7"></p>
<p id="8"></p>
<p id="9"></p>
<p id="10"></p>
<span id="11"></span>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('span:last-of-type')
# [<span id="11"></span>]

:not():

Выбирает все элементы, которые не соответствуют селектору. Спецификация CSS3 гласит, что :not() поддерживает только простые селекторы.

Синтаксис CSS 3:

  • :not(simple-selector).
>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
   <div>Here is some text.</div>
   <div>Here is some more text.</div>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('div:not(:-soup-contains(more))')
[<div>Here is some text.</div>]
Для CSS 4:

Выбирает все элементы, которые не соответствуют ни одному из селекторов в списке селекторов. Хотя в спецификациях CSS4 указано, что поддерживаются составные селекторы, некоторые браузеры (Safari) поддерживают сложные селекторы, которые запланированы для селекторов CSS5. Soup Sieve также поддерживает сложные селекторы.

Синтаксис CSS 4:

  • :not(compound.selector, complex > selector).
>>> from bs4 import BeautifulSoup as bs
>>> html = """
<html>
<head></head>
<body>
   <div>Here is some text.</div>
   <div>Here is some more text.</div>
</body>
</html>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('*:not(html, head, body)'))
# [<div>Here is some text.</div>, 
# <div>Here is some more text.</div>]

:nth-child():

Сопоставляет элементы в зависимости от их положения в группе братьев и сестер.

Ключевые слова even и odd соответственно будут выбирать элементы, положение которых является четным или нечетным среди одноуровневой группы.

Шаблоны в форме an+b выбирают элементы на основе их положения в одноуровневой группе для каждого положительного целого числа или нулевого значения n. Индекс первого элемента равен 1. Значения a и b должны быть целыми числами.

Синтаксис:

  • :nth-child(even);
  • :nth-child(odd);
  • :nth-child(2);
  • :nth-child(2n+2).
>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<p id="0"></p>
<p id="1"></p>
<p id="2"></p>
<p id="3"></p>
<p id="4"></p>
<p id="5"></p>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('p:nth-child(even)')
# [<p id="1"></p>, <p id="3"></p>, <p id="5"></p>]
>>> soup.select('p:nth-child(odd)')
# [<p id="0"></p>, <p id="2"></p>, <p id="4"></p>]
>>> soup.select('p:nth-child(2)')
# [<p id="1"></p>]
>>> soup.select('p:nth-child(-n+3)')
# [<p id="0"></p>, <p id="1"></p>, <p id="2"></p>]

Для CSS 4:

CSS 4 добавляет дополнительный шаблон в форме an+b of S, где S представляет собой список селекторов. Шаблон an+b также можно заменить на even или odd.

При использовании шаблона an+b of S, он будет выбирать элементы из подгруппы одноуровневых элементов, которые все соответствуют списку селектора ([of S]?), в зависимости от их положения в этой подгруппе, используя шаблон an+b для каждого положительного целого или нулевого значения n. Индекс первого элемента равен 1. Значения a и b должны быть целыми числами.

По сути, img:nth-of-type(2) будет эквивалентен :nth-child(2 of img). Преимущество использования :nth-child(an+b [of S]?) Перед :nth-of-type заключается в том, что :nth-of-type ограничивается типами, а :nth-child(an+b [of S ]?) могут использовать сложные селекторы.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<p id="0"></p>
<p id="1"></p>
<p id="2"></p>
<p id="3"></p>
<p id="4"></p>
<p id="5"></p>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('*:nth-child(-n+3 of [id])')
# [<p id="0"></p>, <p id="1"></p>, <p id="2"></p>]

:nth-last-child():

Сопоставляет элементы в зависимости от их положения в одноуровневой группе, считая с конца.

Считая с конца, ключевые слова even и odd будут соответственно выбирать элементы, положение которых является четным или нечетным среди одноуровневой группы.

Считая с конца, шаблоны в форме an+b выбирают элементы на основе их положения в одноуровневой группе для каждого положительного целого или нулевого значенияn. Индекс первого элемента равен1. Значенияaиb` должны быть целыми числами.

Синтаксис:

  • :nth-last-child(even);
  • :nth-last-child(odd);
  • :nth-last-child(2);
  • :nth-last-child(2n+2).
>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<p id="0"></p>
<p id="1"></p>
<p id="2"></p>
<p id="3"></p>
<p id="4"></p>
<p id="5"></p>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('p:nth-last-child(even)')
# [<p id="0"></p>, <p id="2"></p>, <p id="4"></p>]
>>> soup.select('p:nth-last-child(odd)')
# [<p id="1"></p>, <p id="3"></p>, <p id="5"></p>]
>>> soup.select('p:nth-last-child(2)')
# [<p id="4"></p>]
>>> soup.select('p:nth-last-child(-n+3)')
# [<p id="3"></p>, <p id="4"></p>, <p id="5"></p>]

Для CSS 4:

CSS 4 добавляет дополнительный шаблон в форме an+b of S, где S представляет собой список селекторов. шаблон an+b также можно заменить на even или odd.

Более подробно о поведении шаблона an+b of S смотрите описание в описание псевдокласса :nth-child() для CSS 4

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<p id="0"></p>
<p id="1"></p>
<p id="2"></p>
<p id="3"></p>
<p id="4"></p>
<p id="5"></p>
</html>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('*:nth-last-child(-n+3 of [id])')
# [<p id="3"></p>, <p id="4"></p>, <p id="5"></p>]

:nth-last-of-type():

Сопоставляет элементы данного типа в зависимости от их положения в одноуровневой группе, считая с конца.

Ключевые слова even и odd будут соответственно выбирать элементы из подгруппы одноуровневых элементов, которые все соответствуют заданному типу, чья позиция является четной или нечетной. Исходное положение отсчитывается с конца.

Шаблоны в форме an+b выбирают из подгруппы одноуровневых элементов, которые все соответствуют заданному типу, в зависимости от их положения для каждого положительного целого или нулевого значенияn. Индекс первого элемента равен 1. Значенияaиb` должны быть целыми числами. Исходное положение отсчитывается с конца.

Синтаксис:

  • element:nth-last-of-type(even);
  • element:nth-last-of-type(odd);
  • element:nth-last-of-type(2);
  • element:nth-last-of-type(2n+2).
>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<p id="0"></p>
<p id="1"></p>
<span id="2"></span>
<span id="3"></span>
<span id="4"></span>
<span id="5"></span>
<span id="6"></span>
<p id="7"></p>
<p id="8"></p>
<p id="9"></p>
<p id="10"></p>
<span id="11"></span>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('span:nth-last-of-type(even)')
# [<span id="2"></span>, <span id="4"></span>, <span id="6"></span>]
>>> soup.select('span:nth-last-of-type(odd)')
# [<span id="3"></span>, <span id="5"></span>, <span id="11"></span>]
>>> soup.select('p:nth-last-of-type(2)')
# [<p id="9"></p>]
>>> soup.select('p:nth-last-of-type(-n+3)')
# [<p id="8"></p>, <p id="9"></p>, <p id="10"></p>]

:nth-of-type():

Сопоставляет элементы данного типа в зависимости от их положения в группе одноуровневых элементов.

Ключевые слова even и odd будут соответственно выбирать элементы из подгруппы одноуровневых элементов, которые все соответствуют заданному типу, чья позиция является четной или нечетной.

Шаблоны в форме an+b выбирают из подгруппы одноуровневых элементов, которые все соответствуют заданному типу, в зависимости от их положения для каждого положительного целого или нулевого значенияn. Индекс первого элемента равен 1. Значенияaиb` должны быть целыми числами.

Синтаксис:

  • element:nth-of-type(even);
  • element:nth-of-type(odd);
  • element:nth-of-type(2);
  • element:nth-of-type(2n+2).
>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<p id="0"></p>
<p id="1"></p>
<span id="2"></span>
<span id="3"></span>
<span id="4"></span>
<span id="5"></span>
<span id="6"></span>
<p id="7"></p>
<p id="8"></p>
<p id="9"></p>
<p id="10"></p>
<span id="11"></span>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('span:nth-of-type(even)')
# [<span id="3"></span>, <span id="5"></span>, <span id="11"></span>]
>>> soup.select('span:nth-of-type(odd)')
# [<span id="2"></span>, <span id="4"></span>, <span id="6"></span>]
>>> soup.select('p:nth-of-type(2)')
# [<p id="1"></p>]
>>> soup.select('p:nth-of-type(-n+3)')
# [<p id="0"></p>, <p id="1"></p>, <p id="7"></p>]

:only-child:

Выбирает элемент, который не имеет одноуровневых элементов, т.е. он является единственным дочерним элементом.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<div>
    <p id="0"></p>
    <p id="1"></p>
    <p id="2"></p>
    <p id="3"></p>
    <p id="4"></p>
    <p id="5"></p>
</div>
<div>
    <p id="6"></p>
</div>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('p:only-child')
# [<p id="6"></p>]

:only-of-type:

Выбирает элемент соответствующий данному типу, который не имеет одноуровневых элементов, т.е. он является единственным дочерним элементом.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<p id="0"></p>
<p id="1"></p>
<span id="2"></span>
<p id="3"></p>
<p id="4"></p>
<p id="5"></p>
<p id="6"></p>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('span:only-of-type')
# [<span id="2"></span>]

:optional:

Выбирает любой элемент <input>, <select> или <textarea>, для которого не задан атрибут required.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<form>
<input type="name" required>
<input type="checkbox" required>
<input type="email">
<textarea name="name" cols="30" rows="10" required></textarea>
<select name="nm" required>
    <!-- options -->
</select>
</form>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select(':optional')
# [<input type="email"/>]

:out-of-range:

Выбирает все элементы <input>, значения которых выходят за пределы диапазона, в соответствии с их атрибутами type, min и max.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<input id="0" type="month" min="1980-02" max="2004-08" value="1999-05">
<input id="7" type="month" min="1980-02" max="2004-08" value="1979-02">
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select(':out-of-range')
# [<input id="7" max="2004-08" min="1980-02" type="month" value="1979-02"/>]

:placeholder-shown:

Выбирает элемент <input> или <textarea>, который в данный момент отображает текст - заполнитель с помощью атрибута placeholder.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<input id="0" placeholder="This is some text">
<textarea id="1" placeholder="This is some text"></textarea>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select(':placeholder-shown')
# [<input id="0" placeholder="This is some text"/>, 
# <textarea id="1" placeholder="This is some text"></textarea>]

:read-only:

Выбирает элементы (<input> или <textarea>), которые пользователь не может редактировать. Это относится не только к элементам формы, но и к любому элементу, который может редактироваться пользователем, например к элементу <p> с установленным на нем contenteditable.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<input id="0">
<input id="1" disabled>
<input id="2" type="number" readonly>
<textarea id="3"></textarea>
<p id="4">Not editable</p>
<p id="5" contenteditable="true">Editable text</p>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('body :read-only')
# [<input disabled="" id="1"/>, 
# <input id="2" readonly="" type="number"/>, 
# <p id="4">Not editable</p>]

:read-write:

Выбирает элементы (<input> или <textarea>), доступные для редактирования пользователем. Это относится не только к элементам формы, но и к любому элементу, который может быть отредактирован пользователем, например, к элементу <p> с установленным на нем значением contenteditable.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<input id="0">
<input id="1" disabled>
<input id="2" type="number" readonly>
<textarea id="3"></textarea>
<p id="4">Not editable</p>
<p id="5" contenteditable="true">Editable text</p>
</html>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('body :read-write')
# [<input id="0"/>, 
# <textarea id="3"></textarea>, 
# <p contenteditable="true" id="5">Editable text</p>]

:required:

Выбирает любой элемент <input>, <select> или <textarea>, для которого установлен атрибут required.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<form>
<input type="name" required>
<input type="checkbox" required>
<input type="email">
<textarea name="name" cols="30" rows="10" required></textarea>
<select name="nm" required>
    <!-- options -->
</select>
</form>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select(':required')
# [<input required="" type="name"/>, 
# <input required="" type="checkbox"/>, 
# <textarea cols="30" name="name" required="" rows="10"></textarea>, 
# <select name="nm" required="">
#     <!-- options -->
# </select>]

:scope:

Псевдокласс :scope представляет элемент, для которого вызывается match, select, или filter. Например, если вызвать объект BeautifulSoup, представляющий весь документ, то псевдокласс :scope просто выберет весь HTML-документ.

>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
   <div>Here is some text.</div>
   <div>Here is some more text.</div>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select_one('body').select(':scope > div')
# [<div>Here is some text.</div>, <div>Here is some more text.</div>]

:where():

Выбирает элемент, но только если он соответствует хотя бы одному селектору в списке селекторов. BeautifulSoup4 не заботится о специфичности, поэтому :where() по сути является просто псевдонимом для :is().

Синтаксис:

  • :where(selector1, selector2)
>>> from bs4 import BeautifulSoup as bs
>>> html = """
<body>
<p id="0">Some text <span id="1"> in a paragraph</span>.
<a id="2" href="http://google.com">Link.</a></p>
</body>
"""
>>> soup = bs(html, 'html.parser')
>>> soup.select('[id]:where(a, span)')
# [<span id="1"> in a paragraph</span>, 
# <a href="http://google.com" id="2">Link.</a>]