beautifulsoup
Расположение элементов
Поиск…
Найдите текст после элемента в 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()