Важное предупреждение !!!
Данная статья носит исключительно информационный и образовательный характер. Она не является юридической консультацией и не может использоваться как руководство к действию в вопросах, связанных с парсингом, сбором данных и соблюдением законодательства.
Все примеры и рекомендации приведены для ознакомления с технической стороной процесса. Решение о законности парсинга в каждом конкретном случае зависит от множества факторов: юрисдикции, содержания сайта, способа сбора данных и целей использования информации. Для получения юридически обоснованного ответа обращайтесь к квалифицированным специалистам.
Перед началом прочтения статьи, ОБЯЗАТЕЛЬНО ознакомтесь со статьей «Что такое парсинг сайтов: законно ли это?«
Автор и администрация сайта не несут ответственности за использование материалов данной статьи в коммерческих или иных целях, а также за любые последствия, связанные с применением описанных методов.
Привет! Мы уже научились искать элементы по тегам, классам и id. Но HTML — это дерево. Иногда нужно двигаться вверх к родителю, вниз к детям или вбок к соседям. В этом помогают CSS-селекторы и навигация по DOM-дереву.
В этой статье мы разберём:
- Навигацию по DOM-дереву
- Родители, дети, соседи
- CSS-селекторы в BeautifulSoup
- Что нужно знать перед началом
- Основная часть
- Структура DOM-дерева
- Дети и потомки
- Родители
- Соседи (siblings)
- CSS-селекторы в BeautifulSoup
- Получение атрибутов
- Пример из реальной жизни
- Задачи для закрепления
- Нюансы и подводные камни
- Текстовые узлы между тегами
- parents vs parent
- .attrs возвращает словарь
- Частые ошибки и как их избежать
- Ошибка 1: previous_sibling вместо find_previous_sibling
- Ошибка 2: Путаница между .select() и .find_all()
- Ошибка 3: Неправильный CSS-селектор
- Шпаргалка
- Заключение / Выводы
- КВИЗ
- Что дальше?
Что нужно знать перед началом
Для этого урока тебе понадобится:
- Установленный BeautifulSoup (статья 2)
- Базовое понимание HTML-структуры
Совет: DOM (Document Object Model) — это представление HTML-документа в виде дерева. Понимание этого дерева — ключ к эффективному парсингу.
Основная часть
Структура DOM-дерева
HTML-документ можно представить как дерево:
html
├── head
│ └── title
└── body
├── h1
├── div
│ ├── p
│ └── p
└── footer
└── p<!DOCTYPE html>
<html>
<head>
<title>Заголовок</title>
</head>
<body>
<h1>Привет</h1>
<div class="content">
<p>Абзац 1</p>
<p>Абзац 2</p>
</div>
<footer>
<p>Подвал</p>
</footer>
</body>
</html>Дети и потомки
Дети (children) — элементы, находящиеся непосредственно внутри родителя.
Потомки (descendants) — все элементы внутри родителя, включая вложенные.
from bs4 import BeautifulSoup
html = """
<div class="content">
<p>Первый абзац</p>
<p>Второй абзац</p>
<div>
<p>Вложенный абзац</p>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
div = soup.find("div", class_="content")
# Дети (только прямые)
children = list(div.children)
for child in children:
if child.name:
print(child.name) # p, p, div
# Потомки (все, включая вложенные)
descendants = div.find_all("p")
for p in descendants:
print(p.text)
# Первый абзац
# Второй абзац
# Вложенный абзацСовет:
childrenвозвращает итератор, а не список. Используйlist()для преобразования.
Родители
Движение вверх по дереву.
html = """
<div class="container">
<div class="content">
<p id="target">Целевой абзац</p>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
p = soup.find("p", id="target")
# Родитель (непосредственно выше)
parent = p.parent
print(parent.name) # div
print(parent.get("class")) # ['content']
# Все родители
for ancestor in p.parents:
print(ancestor.name) # div, div, body, html, [document]Совет:
parentsвозвращает итератор всех предков до корня документа.
Соседи (siblings)
Движение вбок по дереву.
html = """
<p>Первый абзац</p>
<p class="middle">Средний абзац</p>
<p>Третий абзац</p>
"""
soup = BeautifulSoup(html, "html.parser")
middle = soup.find("p", class_="middle")
# Предыдущий сосед
prev = middle.previous_sibling
print(prev.text) # Первый абзац
# Следующий сосед
next_p = middle.next_sibling
print(next_p.text) # Третий абзацВажно: Между тегами могут быть текстовые узлы (переводы строк, пробелы). Иногда нужно использовать
next_siblingнесколько раз илиfind_next_sibling().
# Поиск следующего элемента-тега
next_p = middle.find_next_sibling("p")
print(next_p.text) # Третий абзацCSS-селекторы в BeautifulSoup
CSS-селекторы позволяют искать элементы так же, как в стилях.
html = """
<div id="main">
<p class="title">Заголовок</p>
<div class="content">
<p>Абзац 1</p>
<p class="highlight">Абзац 2</p>
</div>
</div>
"""
soup = BeautifulSoup(html, "html.parser")
# По id
element = soup.select_one("#main")
print(element.name) # div
# По классу
elements = soup.select(".content p")
for el in elements:
print(el.text)
# Абзац 1
# Абзац 2
# Вложенные селекторы
title = soup.select_one("#main .title")
print(title.text) # Заголовок
# Атрибуты
links = soup.select("a[href]")Совет:
select_one()возвращает первый найденный элемент,select()— список .
Получение атрибутов
html = """
<a href="https://example.com" target="_blank">Ссылка</a>
<img src="image.jpg" alt="Картинка">
"""
soup = BeautifulSoup(html, "html.parser")
# Получение атрибута
link = soup.find("a")
print(link.get("href")) # https://example.com
print(link["href"]) # https://example.com
print(link.attrs) # {'href': 'https://example.com', 'target': '_blank'}
img = soup.find("img")
print(img.get("src")) # image.jpg
print(img.get("alt")) # Картинка
# Безопасное получение
href = link.get("href", "")
print(href) # https://example.comВажно: Используй
.get()для безопасного получения атрибута — если атрибута нет, вернётсяNone(или значение по умолчанию).
Пример из реальной жизни
Парсинг карточек товаров:
import requests
from bs4 import BeautifulSoup
url = "https://example-shop.com/products"
response = requests.get(url)
soup = BeautifulSoup(response.text, "html.parser")
# Находим все карточки товаров
products = soup.select(".product-card")
for product in products:
# Название товара
name = product.select_one(".product-name")
# Цена
price = product.select_one(".product-price")
# Ссылка
link = product.select_one("a")
print(name.text.strip())
print(price.text.strip())
print(link.get("href"))
print("-" * 40)Задачи для закрепления
Задача 1. Найди всех прямых потомков тега <div>.
Задача 2. Найди родителя элемента с классом «target».
Задача 3. Найди предыдущий и следующий абзац относительно выбранного.
Задача 4. Используй CSS-селектор для поиска всех ссылок внутри <div> с классом «menu».
Задача 5. Получи атрибут src у изображения.
Ответы:
Задача 1.
div = soup.find("div")
children = div.find_all(recursive=False)Задача 2.
element = soup.find(class_="target")
parent = element.parentЗадача 3.
p = soup.find("p")
prev = p.find_previous_sibling("p")
next_p = p.find_next_sibling("p")Задача 4.
links = soup.select(".menu a")Задача 5.
img = soup.find("img")
src = img.get("src")Нюансы и подводные камни
Текстовые узлы между тегами
html = "<p>Абзац</p>\n<p>Следующий</p>"
soup = BeautifulSoup(html, "html.parser")
p = soup.find("p")
print(p.next_sibling) # '\n' (текстовый узел)Используй find_next_sibling() для поиска следующего тега.
parents vs parent
parent— один элемент (непосредственный родитель)parents— итератор всех предков
.attrs возвращает словарь
print(element.attrs) # {'class': ['content'], 'id': 'main'}Частые ошибки и как их избежать
Ошибка 1: previous_sibling вместо find_previous_sibling
Для поиска именно тега используй find_previous_sibling("tag").
Ошибка 2: Путаница между .select() и .find_all()
select() — CSS-селекторы, find_all() — поиск по тегам/классам.
Ошибка 3: Неправильный CSS-селектор
Проверяй синтаксис: .class, #id, tag, tag.class.
Шпаргалка
| Что нужно | Как пишется |
|---|---|
| Прямые дети | element.children |
| Все потомки | element.find_all() |
| Родитель | element.parent |
| Все предки | element.parents |
| Следующий сосед-тег | element.find_next_sibling("tag") |
| Предыдущий сосед-тег | element.find_previous_sibling("tag") |
| CSS-селектор (первый) | soup.select_one(".class") |
| CSS-селектор (все) | soup.select(".class") |
| Получить атрибут | element.get("href") |
Заключение / Выводы
Сегодня мы:
- Научились перемещаться по DOM-дереву
- Работали с родителями, детьми и соседями
- Использовали CSS-селекторы для гибкого поиска
- Получали атрибуты элементов








