Гид по технологиям

Как собрать кастомный датасет через веб‑скрапинг — пример на IMDb

8 min read Data Engineering Обновлено 31 Dec 2025
Веб‑скрапинг: создать датасет на примере IMDb
Веб‑скрапинг: создать датасет на примере IMDb

Экран компьютера с кодом

В эпоху решений на основе данных качественные датасеты — основа. Иногда готовых публичных наборов недостаточно. В таких случаях веб‑скрапинг помогает собрать кастомные данные прямо с сайтов. Эта статья показывает подход на примере IMDb (Internet Movie Database): от выбора источника до экспорта CSV и базовой валидации.

Содержание

  • Обзор методов сбора данных
  • Почему выбрать веб‑скрапинг
  • Поиск и анализ источника (IMDb)
  • Настройка окружения и зависимости
  • Полный пример скрипта на Python
  • Создание и очистка датасета в Pandas
  • Альтернативные библиотеки и способы
  • Этические и юридические аспекты, robots.txt
  • Надёжность, масштабирование и безопасность
  • Тесты, критерии приёмки и чек‑листы ролей
  • Краткая справочная информация и рекомендации

Обзор методов сбора данных

Существуют разные подходы к сбору данных: ручной ввод, API, публичные датасеты и веб‑скрапинг. Коротко:

  • Ручной ввод: подходит для небольших наборов и когда данные недоступны другими способами. Медленно и подвержено ошибкам.
  • API: структурированный, часто актуальный доступ. Ограничения — квоты, авторизация, формат и покрытие данных.
  • Публичные датасеты: экономят время, но могут не соответствовать точным требованиям или обновляться редко.
  • Веб‑скрапинг: гибкий и масштабируемый способ извлечения данных со страниц, когда API нет или ограничен.

Важно: выбор метода зависит от задачи, объёма данных и юридических ограничений.

Почему выбирать веб‑скрапинг

Веб‑скрапинг даёт контроль над тем, какие поля собирать и как их структурировать. Вы можете объединять данные с нескольких страниц и сайтов, нормализовать поля под единую схему и автоматически обновлять датасет по расписанию. При этом нужен код, знание HTML и внимание к этике и законам.

Выбор и идентификация источника

Первый шаг — определить сайт с нужными данными. Убедитесь, что вы соблюдаете условия использования сайта. В примере используем IMDb. Откройте в браузере страницу с нужными списками — например, результаты по релизам за год — и воспользуйтесь инструментами разработчика, чтобы найти HTML‑элементы, содержащие нужные поля.

Результаты IMDb для фильмов 2023 года

Для анализа DOM: правый клик → «Inspect», найдите теги, классы и атрибуты, которые содержат заголовки, рейтинги, описания и т. п.

Использование инструментов разработчика для инспекции сайта

В примере элемент заголовка фильма находится внутри класса lister-item-header. Анализируйте каждый признак, который будете извлекать.

Настройка окружения

Создайте изолированное виртуальное окружение. Установите нужные пакеты:

pip install requests beautifulsoup4 pandas

Используемые библиотеки:

  • requests — для HTTP‑запросов.
  • beautifulsoup4 — для парсинга HTML и извлечения данных.
  • pandas — для хранения, очистки и экспорта датасета.
  • time и re — встроенные модули Python для пауз и регулярных выражений.

Полный код можно хранить в репозитории и документировать версии зависимостей (requirements.txt).

Пример скрипта: структура и ключевые функции

Ниже — минимальный рабочий пример. Код можно расширять: обработка исключений, логирование, многопоточность/асинхронность и т. д.

import requests
from bs4 import BeautifulSoup
import time
import pandas as pd
import re

Функция для получения и парсинга HTML:

def get_soup(url, params=None, headers=None):
    response = requests.get(url, params=params, headers=headers)
    soup = BeautifulSoup(response.content, "html.parser")
    return soup

Функция извлечения полей из блока фильма (пример для структуры IMDb):

def extract_movie_data(movie):
    title = movie.find("h3", class_="lister-item-header").find("a").text
    rating = movie.find("div", class_="ratings-imdb-rating").strong.text
    description = movie.find("div", class_="lister-item-content").find_all("p")[1].text.strip()
    genre_element = movie.find("span", class_="genre")
    genre = genre_element.text.strip() if genre_element else None
    release_date = movie.find("span", class_="lister-item-year text-muted unbold").text.strip()
    director_stars = movie.find("p", class_="text-muted").find_all("a")
    directors = [person.text for person in director_stars[:-1]]
    stars = [person.text for person in director_stars[-1:]]
    movie_data = {
        "Title": title,
        "Rating": rating,
        "Description": description,
        "Genre": genre,
        "Release Date": release_date,
        "Directors": directors,
        "Stars": stars
    }
    return movie_data

Основная функция скрейпера с пагинацией и задержками:

def scrape_imdb_movies(year, limit):
    base_url = "https://www.imdb.com/search/title"
    headers = {"Accept-Language": "en-US,en;q=0.9"}
    movies = []
    start = 1
    while len(movies) < limit:
        params = {
            "release_date": year,
            "sort": "num_votes,desc",
            "start": start
        }
        soup = get_soup(base_url, params=params, headers=headers)
        movie_list = soup.find_all("div", class_="lister-item mode-advanced")
        if len(movie_list) == 0:
            break
        for movie in movie_list:
            movie_data = extract_movie_data(movie)
            movies.append(movie_data)
            if len(movies) >= limit:
                break
        start += 50  # IMDb показывает по 50 позиций на страницу
        time.sleep(1)  # Задержка, чтобы не нагружать сервер
    return movies

Запуск скрейпа (пример):

# Scrape 1000 movies released in 2023 (or as many as available)
movies = scrape_imdb_movies(2023, 1000)

Вывод в Google Colab с результатами скрейпинга

Создание датасета и предобработка

Собранные словари удобно конвертировать в DataFrame и затем очистить.

df = pd.DataFrame(movies)

Пример базовой очистки:

df = df.dropna()
df['Release Year'] = df['Release Date'].str.extract(r'(\d{4})')
df['Release Year'] = pd.to_numeric(df['Release Year'], errors='coerce').astype('Int64')
df = df.drop(['Release Date'], axis=1)
df['Rating'] = pd.to_numeric(df['Rating'], errors='coerce')
df['Title'] = df['Title'].apply(lambda x: re.sub(r'\W+', ' ', x))

Экспорт в CSV:

df.to_csv("imdb_movies_dataset.csv", index=False)

Предпросмотр первых строк:

df.head()

Вывод первых пяти строк датасета

Проверка качества и валидация данных

Базовые проверки после сбора:

  • Отсутствуют ли дубликаты (например, по Title + Release Year)?
  • Соответствует ли тип столбцов ожидаемому (числа как float/int, даты как datetime)?
  • Нет ли очевидных выбросов (рейтинг > 10, год в будущем)?
  • Покрывают ли поля те признаки, которые требуются для анализа?

Пример быстрых проверок в Pandas:

assert df['Rating'].between(0, 10).all()
assert df['Release Year'].min() > 1800

Критерии приёмки

  • Набор содержит >= N записей (по вашей задаче).
  • Все обязательные поля (Title, Rating, Release Year) заполнены в ≥95% записей.
  • Типы столбцов корректны и позволяют аналитическую обработку.

Альтернативные библиотеки и подходы

Если сайт активно использует JavaScript или динамическую подгрузку, requests + BeautifulSoup может не подойти. Варианты:

  • Selenium / Playwright — автоматизация браузера, выполняют JS. Подходит для сложных сценариев, но тяжелее в масштабировании.
  • Scrapy — фреймворк для масштабируемого краулинга, встроенная поддержка пайплайнов и экспорта.
  • Requests‑HTML — упрощённый рендеринг JS (ограниченно).
  • API‑first подход — прежде чем скрапить, проверьте, нет ли неофициального/официального API.

Когда скрапинг не подходит: если сайт запрещает сбор данных в правилах, если данные доступны по платному API с неприемлемыми условиями, или если объём и частота запросов создают риск блокировки.

Этические и юридические аспекты

  • Всегда проверяйте условия использования сайта (Terms of Service) и robots.txt. robots.txt указывает, какие пути разрешены для ботов, но не заменяет юридические условия.
  • Не извлекайте персональные данные без правовой основы. Если собираете персональные данные пользователей, учитывайте требования локального законодательства (например, GDPR для EU).
  • Уважайте нагрузку на сайт: добавляйте адекватные задержки, используйте кэширование и уменьшайте частоту запросов.

Важное: при сомнениях — спросите владельца сайта или используйте официальные каналы доступа к данным.

Техники надёжности, масштабирования и защиты

  • Заголовки и сессии: используйте requests.Session() и задавайте корректный User‑Agent.
  • Паузы и экспоненциальный бэкофф при ошибках (429, 503).
  • Ротация прокси и IP — только при необходимости и с учётом правил сайта.
  • Ограничение параллелизма: Scrapy и другие фреймворки позволяют контролировать скорость.
  • Логирование и метрики: фиксируйте успешные и ошибочные запросы, время отклика и число записей.
  • Хранение исходного HTML — полезно для репликации и отладки.

Рекомендуемая заглушка User‑Agent:

headers = {
    "User-Agent": "MyDataCollectionBot/1.0 (+https://yourdomain.example)",
    "Accept-Language": "en-US,en;q=0.9"
}

Обработка JavaScript, CAPTCHAs и анти‑ботов

  • Для JS‑рендеринга используйте Playwright или Selenium. Playwright легче масштабировать в headless‑режиме.
  • Если сайт использует CAPTCHAs, интеграция обхода часто нарушает правила и может быть незаконной. Рассмотрите официальные API или договорённости.

Тесты и критерии приёмки

Набор тестов при автоматическом запуске:

  • Smoke test: скрипт получает хотя бы одну страницу и извлекает 5 элементов.
  • Schema test: структура колонок соответствует контракту (названия и типы).
  • Consistency test: количество записей не падает кардинально от одной прогонки к другой.
  • Regression: при изменении HTML страница, тесты должны сигнализировать о поломке парсинга.

Пример теста на уровень данных (pytest‑style):

def test_min_records(df):
    assert len(df) >= 100

Роли и чек‑листы

Developer (тот, кто пишет скрипт):

  • Проанализировать DOM и составить селекторы
  • Добавить обработку ошибок и логирование
  • Написать unit‑тесты для extract_movie_data

Data Engineer:

  • Описать схему датасета
  • Настроить пайплайн ETL и расписание
  • Обеспечить хранение исходного HTML и резервные копии

Data Analyst / Scientist:

  • Проверить полноту и качество полей
  • Добавить метрики покрытия данных
  • Подготовить датасет для моделирования

Мини‑методология («быстрый» SOP)

  1. Определить поля и источники.
  2. Исследовать DOM и протестировать ручные запросы.
  3. Реализовать get_soup + extract функции.
  4. Добавить задержки, заголовки и обработку ошибок.
  5. Собрать небольшой сэмпл и проверить данные.
  6. Написать тесты и запустить на весь объём.
  7. Экспортировать CSV/паркет и документировать схему.

План действий при инциденте (runbook)

  • Симптом: скрипт падает с пустым movie_list.
    1. Проверить HTTP‑код ответа и HTML (логировать response.status_code).
    2. Сохранить HTML для анализа и сравнить с эталоном.
    3. Проверить изменения селекторов в DOM.
    4. Если проблема на стороне сервера (5xx) — применить backoff и повтор.
    5. При 403/429 — уменьшить скорость, проверить User‑Agent, возможны блокировки.

Факты и численные подсказки (факт‑бокс)

  • Стандартная страница IMDb для поиска содержит до 50 фильмов.
  • Задержка 1–3 секунды между запросами обычно снижает риск временной блокировки.
  • Сохранение исходного HTML для 1000 страниц потребует порядка десятков мегабайт (в зависимости от страницы).

Безопасность и конфиденциальность

  • Храните ключи и учётные данные вне кода (переменные окружения, секреты CI).
  • Удаляйте персональные данные, если они не нужны. При хранении PII соблюдайте законы о защите данных.

Короткая галерея пограничных случаев

  • Пагинация поменяла параметр start → парсер перестаёт находить записи.
  • Поле «рейтинг» отсутствует у малораскрученных фильмов → нужно обрабатывать None.
  • Структура «директора/актеры» меняется для короткометражек → гибкий парсинг.

Словарь (1‑строчные определения)

  • DOM — модель документа HTML, состоит из узлов и атрибутов.
  • Selector — CSS/XPath выражение для поиска элементов в HTML.
  • User‑Agent — строка, идентифицирующая клиента при HTTP‑запросе.
  • Backoff — стратегия увеличения задержек при повторных ошибках.

Совместимость, миграция и примечания локализации

  • При смене user‑agent и заголовков Accept‑Language результаты могут отличаться (локализованные названия). Для стабильности укажите Accept‑Language.
  • При масштабировании на облако используйте контейнеры и очередь задач (Celery/Cloud Tasks).

Краткие рекомендации по SEO и публикации результата

  • Документируйте схему CSV и примеры записей.
  • Укажите источник и дату сбора данных в README.
  • Соблюдайте лицензионные и юридические условия при публикации датасета.

Короткий вывод

Веб‑скрапинг — мощный инструмент создания кастомных датасетов. Он требует внимательности к DOM, управлению нагрузкой на сайт и соблюдению правил. Для устойчивых решений комбинируйте парсинг с тестами, логированием и политикой безопасности.

Что дальше (следующие шаги)

  • Автоматизируйте сбор: запланируйте CRON/CI‑job.
  • Добавьте мониторинг и оповещения на изменения структуры страниц.
  • Рассмотрите переход на Scrapy или Playwright при усложнении задач.

Заметки: перед массовым сбором данных проверьте юридические ограничения и при необходимости запросите разрешение у владельцев сайта.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как найти, что посмотреть на Netflix
Развлечения

Как найти, что посмотреть на Netflix

ISODisk: монтирование и рип ISO
Утилиты

ISODisk: монтирование и рип ISO

Возобновление чтения PDF в популярных ридерах
PDF

Возобновление чтения PDF в популярных ридерах

Сохранение и загрузка в Godot
Game Dev

Сохранение и загрузка в Godot

Изменить цвет фона в CSS — руководство
Frontend

Изменить цвет фона в CSS — руководство

Obsidian: заметки, Markdown и второй мозг
Продуктивность

Obsidian: заметки, Markdown и второй мозг