Python
Что такое парсер сайта: примеры, ограничения и первый план
Парсер сайта нужен, когда данные на странице повторяются по одной структуре: карточки товаров, новости, вакансии, публикации, строки каталога. Хорошая первая версия не пытается собрать весь интернет. Она берет одну понятную страницу, находит нужные элементы и сохраняет результат так, чтобы его можно было проверить
Важно начать с границ. Парсер сайта не должен обходить авторизацию, капчу, платный доступ, техническую защиту и правила площадки. Если есть официальный API, CSV-выгрузка или кабинет с отчетом, часто лучше использовать их. HTML-разбор нужен там, где такой способ разрешен, стабилен и действительно помогает решить задачу
Что должен уметь первый парсер сайта
Первая версия должна делать пять вещей:
- Получить HTML из локального файла или разрешенного источника
- Найти повторяющиеся элементы
- Достать из них нужные поля
- Очистить текст от лишних пробелов
- Сохранить результат в CSV
Этого достаточно, чтобы понять основу. Расписание, интерфейс, авторизация, прокси, сложные обходы и большие базы данных на старте только мешают. Если маленький пример не получается объяснить словами, большая версия будет ломаться еще быстрее
По этой теме полезно отдельно посмотреть Составьте еженедельное расписание занятий, чтобы расширить контекст и сравнить подходы
По этой теме полезно отдельно посмотреть Аннотации типов для декораторов в Python, чтобы расширить контекст и сравнить подходы
Минимальный пример с заголовком
Самый короткий пример показывает сам принцип: получить страницу и достать заголовок
import requests
from bs4 import BeautifulSoup
response = requests.get("https://example.com", timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser")
heading = soup.find("h1")
if heading:
print(heading.get_text(strip=True))
else:
print("Заголовок h1 не найден")
Этот код еще не похож на рабочий парсер каталога. Он достает только один элемент. Зато на нем видно три базовых шага: загрузка, разбор HTML и проверка результата. Дальше можно перейти к более полезному примеру — карточкам и CSV
Перед следующим шагом полезно специально сломать пример: заменить h1 на несуществующий тег, отключить интернет или поставить неправильный адрес. Так читатель увидит, что парсеру нужны проверки, а не только строка, которая сработала в идеальных условиях. В реальной задаче источник может вернуть пустую страницу, другой статус, другую кодировку или HTML без ожидаемого блока
Если это понятно с самого начала, дальнейший пример с карточками воспринимается не как магия, а как обычная последовательность проверяемых действий
Для читателя здесь есть простая практическая польза: после этого блока он может открыть терминал, создать один файл, запустить код и получить видимый результат. Это лучше, чем общее описание парсинга, потому что сразу появляются вопросы по делу: какие элементы искать, что делать с пустыми полями, где хранить результат и как понять, что таблица не врет. Именно эти вопросы превращают тему из справки в рабочий навык
Как собрать мини-парсер карточек
Первый пример с example.com показывает идею, но для пользы лучше разобрать карточки и сохранить результат. Ниже мини-парсер, который работает локально: он не отправляет запросы на чужие сайты, но показывает настоящую механику HTML-парсинга
Подготовка занимает пару минут. Удобнее работать в отдельной папке, чтобы не смешивать учебный файл с другими проектами
python3 -m venv .venv
source .venv/bin/activate
pip install beautifulsoup4
Если вы работаете на Windows, команда активации будет другой:
.venv\Scripts\activate
Для первого запуска лучше не трогать чужой сайт. Возьмите локальный файл, выгрузку или тестовый ответ API. Так вы спокойно проверите логику: программа находит нужные поля, не падает на пустом значении и сохраняет результат в таблицу
Создайте файл catalog.html рядом со скриптом. Внутри будет маленький фрагмент разметки, похожий на карточки товаров на сайте. Это не копия конкретного сайта, а безопасный учебный макет
<div class="item">
<a class="title" href="/item/coffee">Кофе арабика 1 кг</a>
<span class="price">790 ₽</span>
<span class="status">в наличии</span>
</div>
<div class="item">
<a class="title" href="/item/tea">Чай сенча 200 г</a>
<span class="price">420 ₽</span>
<span class="status">под заказ</span>
</div>
<div class="item">
<a class="title" href="/item/cocoa">Какао 500 г</a>
<span class="price"></span>
<span class="status">нет цены</span>
</div>
Теперь создайте файл parser.py:
import csv
from pathlib import Path
from bs4 import BeautifulSoup
HTML_FILE = Path("catalog.html")
CSV_FILE = Path("site_items.csv")
def clean_text(value: str | None) -> str:
return " ".join((value or "").split())
def parse_items(html: str) -> list[dict[str, str]]:
soup = BeautifulSoup(html, "html.parser")
rows = []
for card in soup.select(".item"):
title = card.select_one(".title")
price = card.select_one(".price")
status = card.select_one(".status")
rows.append({
"title": clean_text(title.get_text() if title else ""),
"link": title.get("href", "") if title else "",
"price": clean_text(price.get_text() if price else ""),
"status": clean_text(status.get_text() if status else ""),
})
return rows
def save_csv(rows: list[dict[str, str]]) -> None:
with CSV_FILE.open("w", newline="", encoding="utf-8") as file:
writer = csv.DictWriter(file, fieldnames=["title", "link", "price", "status"])
writer.writeheader()
writer.writerows(rows)
html = HTML_FILE.read_text(encoding="utf-8")
rows = parse_items(html)
if not rows:
raise SystemExit("Не найдено ни одной карточки")
empty_prices = [row for row in rows if not row["price"]]
if empty_prices:
print(f"Внимание: без цены найдено {len(empty_prices)} строки")
save_csv(rows)
print(f"Сохранено строк: {len(rows)}")
print(f"Файл результата: {CSV_FILE.resolve()}")
Запуск:
python parser.py
После запуска появится файл site_items.csv. Откройте его и проверьте три вещи: все ли названия попали в таблицу, не потерялись ли ссылки, видно ли строку без цены. Эта строка специально оставлена в примере, потому что настоящий парсер обязан замечать неполные данные, а не молча складывать их в отчет
Как перейти от учебного файла к разрешенному сайту
Когда локальный пример понятен, можно думать о реальном источнике. Порядок такой:
- Проверьте правила сайта, пользовательское соглашение, robots.txt и наличие API или выгрузки
- Убедитесь, что данные открыты и их можно собирать для вашей задачи
- Сначала получите одну страницу вручную и сохраните ее как HTML
- Настройте селекторы на сохраненном файле
- Только после этого добавляйте загрузку страницы через
requests - Поставьте таймаут, понятный
User-Agent, паузы и обработку ошибок - Сравните 10 строк с источником глазами
В коде загрузка разрешенной страницы может выглядеть так:
import requests
url = "https://example.com/catalog"
headers = {"User-Agent": "Mozilla/5.0 (compatible; learning-parser/1.0)"}
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
html = response.text
Этот фрагмент не заменяет проверку правил. Он только показывает, где в учебной версии появится получение HTML из сети. Если сайт дает API или CSV, лучше начать с них: результат обычно стабильнее, а поддерживать такой вариант проще
Какие проверки добавить сразу
- страница вернула успешный статус;
- найдено больше нуля карточек;
- в каждой строке есть название;
- ссылка не пустая, если она нужна для проверки;
- цена очищена от лишних пробелов;
- пустые цены видны отдельным предупреждением;
- результат сохранен в CSV;
- несколько строк вручную совпали с исходником
Если эти проверки есть, парсер уже можно обсуждать как рабочую первую версию. Без них это просто кусок кода, который однажды напечатал красивый результат
Как организовать рабочую папку
Чтобы пример по теме парсера сайта не остался отдельным фрагментом, заведите маленькую рабочую папку. В ней должны быть входной файл site_sample.html, скрипт, CSV-результат и короткая заметка о запуске
parser-demo/
parser.py
catalog.html
site_items.csv
README.md
В README.md достаточно указать источник данных, разрешенный способ получения, ожидаемые поля и команду запуска. Для темы парсера сайта это важнее длинного описания: через неделю вы быстро поймете, что именно проверяет скрипт
Для первого рабочего варианта источник должен быть понятным: локальный HTML-файл, сохраненная разрешенная страница или API. Этот подход сначала отрабатывает селекторы на локальном файле, а не на живом сайте. Если пример сразу требует авторизации, обхода защиты, сложного браузерного управления и десятков настроек, он слишком тяжелый для старта. Сначала нужна маленькая версия, которую можно объяснить словами
Как проверить результат
Для темы парсера сайта успешный запуск означает не просто созданный файл. Откройте site_parser_result.csv рядом с исходником site_sample.html и вручную проверьте несколько строк: первую, последнюю и одну из середины
В каждой строке должно быть понятно, откуда взялись поля title и url. Если значение пустое, странное или повторяется, не прячьте его в общей таблице. Лучше вывести предупреждение или сохранить отдельный список строк для ручной проверки
Мини-валидатор под эту задачу
Для первой версии хватит простой проверки: обязательное поле заполнено, дополнительное поле не потерялось, дубль не прошел незаметно. Такой валидатор не заменяет просмотр результата, но быстро показывает, где таблица стала сомнительной
def validate_rows(rows, primary_field="title", secondary_field="url"):
errors = []
seen = set()
for number, row in enumerate(rows, start=1):
primary_value = str(row.get(primary_field, "")).strip()
secondary_value = str(row.get(secondary_field, "")).strip()
if not primary_value:
errors.append(f"Строка {number}: пустое поле {primary_field}")
if not secondary_value:
errors.append(f"Строка {number}: пустое поле {secondary_field}")
key = primary_value.lower()
if key and key in seen:
errors.append(f"Строка {number}: возможный дубль {primary_value}")
seen.add(key)
return errors
Для парсера сайта эта проверка закрывает главный риск первой версии: изменение разметки, относительные ссылки и лишние элементы страницы. Если ошибок много, не расширяйте сбор. Сначала разберитесь, почему базовые поля не держатся стабильно
Что добавить во вторую версию
Когда первая таблица проверена руками, можно добавлять улучшения. Для парсера сайта полезны лог запуска, отдельный файл ошибок, сохранение исходного ответа, проверка дублей по надежному ключу и понятное имя результата, чтобы новый запуск не перетирал старый файл
Не добавляйте расписание, интерфейс и десятки настроек до того, как стало ясно, что маленькая версия решает задачу. Иначе вы будете отлаживать оболочку вокруг данных, которым еще нельзя доверять
Где граница безопасной работы
Главный фокус здесь — собрать только разрешенные открытые поля и сразу видеть пустой результат. Перед переходом к живому источнику проверьте правила доступа, наличие API или выгрузки, ограничения по частоте и состав данных. Если появляются персональные данные, закрытые страницы, авторизация или техническая защита, задачу нужно пересобрать более аккуратно
Хорошая первая версия должна быть узкой: понятный источник, понятные поля, проверяемый CSV и честно записанные ограничения. Такой инструмент проще поддерживать и легче объяснить другому человеку
Критерии готовности
- входной файл
site_sample.htmlописан рядом со скриптом - результат сохраняется в
site_parser_result.csv - поле
titleне бывает пустым без предупреждения - поле
urlпроверяется отдельно - дубли либо удаляются, либо помечаются
- несколько строк сверены вручную
- ограничения источника записаны обычным языком
- следующий шаг понятен и не требует переписывать все заново
Часто задаваемые вопросы
Что такое парсер сайта?
Это программа, которая получает страницу, находит нужные элементы в HTML и превращает их в структуру данных
Нужно ли сразу парсить живой сайт?
Нет. Для обучения лучше начать с локального HTML-файла, а к живому сайту переходить только после проверки правил доступа
Какая библиотека нужна для старта?
Для простого HTML достаточно Python и BeautifulSoup. Для запросов к разрешенному источнику часто добавляют requests
Что сохранять в первую очередь?
Минимальный набор: название, ссылка, цена или дата, а также статус проверки, чтобы видеть пустые и сомнительные строки
Когда нужен Playwright или Selenium?
Когда данные действительно загружаются через JavaScript и правила источника позволяют автоматизированное открытие страниц