Поиск…


Найдите текст после элемента в BeautifulSoup

Представьте, что у вас есть следующий HTML:

<div>
    <label>Name:</label>
    John Smith
</div>

И вам нужно найти текст «John Smith» после элемента label .

В этом случае вы можете найти элемент label по тексту, а затем использовать свойство .next_sibling :

from bs4 import BeautifulSoup

data = """
<div>
    <label>Name:</label>
    John Smith
</div>
"""

soup = BeautifulSoup(data, "html.parser")

label = soup.find("label", text="Name:")
print(label.next_sibling.strip())

Печатает John Smith .

Использование селекторов CSS для поиска элементов в BeautifulSoup

BeautifulSoup имеет ограниченную поддержку селекторов CSS , но охватывает наиболее часто используемые. Используйте метод select() чтобы найти несколько элементов и select_one() чтобы найти один элемент.

Основной пример:

from bs4 import BeautifulSoup

data = """
<ul>
    <li class="item">item1</li>
    <li class="item">item2</li>
    <li class="item">item3</li>
</ul>
"""

soup = BeautifulSoup(data, "html.parser")

for item in soup.select("li.item"):
    print(item.get_text())

Печать:

item1
item2
item3

Поиск комментариев

Чтобы найти комментарии в BeautifulSoup , используйте аргумент text (или string в последних версиях), проверяющий тип Comment :

from bs4 import BeautifulSoup
from bs4 import Comment

data = """
<html>
    <body>
        <div>
        <!-- desired text -->
        </div>
    </body>
</html>
"""

soup = BeautifulSoup(data, "html.parser")
comment = soup.find(text=lambda text: isinstance(text, Comment))
print(comment)

Распечатывает desired text .

Функции фильтра

BeautifulSoup позволяет фильтровать результаты, предоставляя функцию find_all и аналогичные функции. Это может быть полезно для сложных фильтров, а также для повторного использования кода.

Основное использование

Определите функцию, которая принимает элемент как единственный аргумент. Функция должна возвращать значение True если аргумент соответствует.

def has_href(tag):
    '''Returns True for tags with a href attribute'''
    return  bool(tag.get("href"))

soup.find_all(has_href) #find all elements with a href attribute
#equivilent using lambda:
soup.find_all(lambda tag: bool(tag.get("href")))

Другой пример, который находит теги с значением href которое не начинается с

Предоставление дополнительных аргументов функции фильтрации

Поскольку функция, переданная find_all может принимать только один аргумент, иногда полезно создавать «фабрики функций», которые создают функции, пригодные для использования в find_all . Это полезно для более гибкого использования функций поиска тегов.

def present_in_href(check_string):
    return lambda tag: tag.get("href") and check_string in tag.get("href")

soup.find_all(present_in_href("/partial/path"))

Доступ к внутренним тегам и их атрибутам изначально выбранного тега

Предположим, вы получили html после выбора с помощью soup.find('div', class_='base class') :

from bs4 import BeautifulSoup

soup = BeautifulSoup(SomePage, 'lxml')
html = soup.find('div', class_='base class')
print(html)

<div class="base class">
  <div>Sample text 1</div>
  <div>Sample text 2</div>
  <div>
    <a class="ordinary link" href="https://example.com">URL text</a>
  </div>
</div>

<div class="Confusing class"></div>
'''

И если вы хотите получить доступ к <a> тега href , вы можете сделать это следующим образом:

a_tag = html.a
link = a_tag['href']
print(link)

https://example.com

Это полезно, если вы не можете напрямую выбрать тег <a> потому что это attrs не дает вам уникальной идентификации, есть другие «близнецы» теги <a> в анализируемой странице. Но вы можете однозначно выбрать родительский тег, который содержит необходимый <a> .

Сбор необязательных элементов и / или их атрибутов из серии страниц

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

Более того, сам элемент, например, является самым обычным элементом на странице, другими словами, никакие конкретные атрибуты не могут его однозначно определить. Но вы видите, что вы можете правильно выбрать его родительский элемент, и вы знаете номер заказа требуемого элемента на соответствующем уровне вложенности.

from bs4 import BeautifulSoup

soup = BeautifulSoup(SomePage, 'lxml')
html = soup.find('div', class_='base class') # Below it refers to html_1 and html_2

Элемент Wanted не является обязательным, поэтому для html может быть 2 ситуации:

html_1 = '''
<div class="base class">    # №0
  <div>Sample text 1</div>  # №1
  <div>Sample text 2</div>  # №2  
  <div>!Needed text!</div>  # №3
</div>

<div>Confusing div text</div>  # №4
'''
        
html_2 = '''
<div class="base class">    # №0
  <div>Sample text 1</div>  # №1
  <div>Sample text 2</div>  # №2  
</div>

<div>Confusing div text</div>  # №4
'''

Если вы получили html_1 вы можете собрать !Needed text! от тега №3 следующим образом:

wanted tag = html_1.div.find_next_sibling().find_next_sibling() # this gives you whole tag №3

Он изначально получает №1 div , затем 2 раза переключается на следующий div на одном уровне гнездования, чтобы добраться до №3.

wanted_text = wanted_tag.text # extracting !Needed text!

Полезность этого подхода возникает, когда вы получаете html_2 - подход не даст вам ошибки, он даст None :

print(html_2.div.find_next_sibling().find_next_sibling())
None

Использование find_next_sibling() здесь имеет решающее значение, поскольку оно ограничивает поиск элементов соответствующим уровнем вложенности. Если вы будете использовать find_next() тогда будет find_next() тэг №4, и вы не захотите его:

print(html_2.div.find_next().find_next())
<div>Confusing div text</div>

Вы также можете исследовать find_previous_sibling() и find_previous() которые работают прямо противоположно.

Все описанные функции имеют свои многосторонние варианты, чтобы поймать все теги, а не только первые:

find_next_siblings()
find_previous_siblings()
find_all_next()
find_all_previous()


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow