Как спарсить товары с пагинацией: пошаговый пример на Python

🛒 Кратко: Научитесь парсить каталоги с пагинацией: автоматически перелистывайте страницы, собирайте товары и сохраняйте в CSV — без дублей и ошибок.
Как спарсить товары с пагинацией на Python

Если вы когда-нибудь пытались собрать список товаров с сайта — будь то электроника, одежда или книги — вы наверняка столкивались с пагинацией: «Страница 1, 2, 3…».

Вручную копировать сотни страниц с карточками — не вариант. Но с Python это решается за 20 строк кода.

В этой статье я покажу пошагово, как

  • Найти ссылку на следующую страницу
  • Автоматически перелистывать все страницы
  • Извлекать название, цену и URL товара
  • Сохранить всё в CSV без дубликатов

Всё — на реальном демо-сайте, с объяснением каждой строки кода.

Выбор демо-сайта и структура пагинации

Используем официальный учебный ресурс:
👉 https://books.toscrape.com/

Там:

  • Чёткая пагинация внизу страницы
  • Каждый товар — карточка с названием, ценой и ссылкой
  • Нет JavaScript — подходит для requests + BeautifulSoup

URL пагинации выглядит так:

  • Страница 1: https://books.toscrape.com/
  • Страница 2: https://books.toscrape.com/catalogue/page-2.html
  • Страница 3: https://books.toscrape.com/catalogue/page-3.html

💡 Но так же в некоторых случаях пагинация может быть через ?page=2 — мы разберём оба подхода.

Шаг 1. Установка и подготовка

Установите зависимости

pip install requests beautifulsoup4 pandas
  • requests — загрузка страниц
  • beautifulsoup4 — парсинг HTML
  • pandas — удобное сохранение в CSV

Импорты и переменные

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

BASE_URL = "https://books.toscrape.com/"

Шаг 2. Парсинг одной страницы

Как найти структуру карточки товара

  1. Откройте сайт → ПКМ на книге → «Просмотреть код»
  2. Вы увидите:
<article class="product_pod">
  <h3><a href="..." title="A Light in the...">A Light in the...</a></h3>
  <p class="price_color">£51.77</p>
</article>

Код для извлечения данных

def parse_page(url):
    response = requests.get(url)
    soup = BeautifulSoup(response.content, "html.parser")
    products = []
    
    for item in soup.select("article.product_pod"):
        title = item.h3.a["title"]
        price = item.select_one("p.price_color").text
        link = BASE_URL + item.h3.a["href"]
        products.append({"title": title, "price": price, "link": link})
    
    return products

📚 select() использует CSS-селекторы — самый удобный способ навигации по DOM.

Шаг 3. Определение количества страниц

Вариант 1. Через номер последней страницы

На books.toscrape.com внизу есть ссылки вида:

<li class="current">Page 1 of 17</li>

Извлекаем число:

def get_total_pages(base_url):
    response = requests.get(base_url)
    soup = BeautifulSoup(response.content, "html.parser")
    current = soup.select_one("li.current")
    if current:
        text = current.text.strip()
        # "Page 1 of 17" → разбиваем и берём последнее число
        return int(text.split()[-1])
    return 1

Вариант 2. Через отсутствие кнопки «Next»

Если на странице нет ссылки «Next» — значит, это последняя.

def has_next_page(soup):
    return soup.select_one("li.next") is not None

Этот метод универсален для сайтов вроде ?page=1, ?page=2.

Шаг 4. Цикл по всем страницам

all_products = []
total_pages = get_total_pages(BASE_URL)

print(f"Всего страниц: {total_pages}")

for page in range(1, total_pages + 1):
    if page == 1:
        url = BASE_URL
    else:
        url = f"https://books.toscrape.com/catalogue/page-{page}.html"
    
    print(f"Парсинг страницы {page}...")
    products = parse_page(url)
    all_products.extend(products)
    
    # Вежливая пауза
    time.sleep(1)

print(f"Всего товаров собрано: {len(all_products)}")

⚠️ time.sleep(1) — уважение к серверу. Без паузы вас могут заблокировать.

Шаг 5. Сохранение в CSV

df = pd.DataFrame(all_products)
df.to_csv("books.csv", index=False, encoding="utf-8-sig")
print("&#x2705; Данные сохранены в books.csv")

Флаг utf-8-sig гарантирует, что кириллица откроется корректно в Excel.

Обработка ошибок и улучшения

Защита от падений

Оберните каждую страницу в try/except:

try:
    products = parse_page(url)
    all_products.extend(products)
except Exception as e:
    print(f"Ошибка на странице {page}: {e}")
    continue

Уникальность товаров

Иногда пагинация дублирует карточки. Уберите дубли по ссылке:

df = df.drop_duplicates(subset=["link"])

Адаптация под другие сайты

Если пагинация через ?page=2:

# Пример: https://shop.com/products?page=1
for page in range(1, 21):  # если знаете, что максимум 20
    url = f"https://shop.com/products?page={page}"
    # ... парсинг

Или динамически:

page = 1
while True:
    url = f"https://shop.com/products?page={page}"
    response = requests.get(url)
    if "Нет товаров" in response.text or response.status_code != 200:
        break
    # парсим
    page += 1

Заключение

Надеюсь мои примеры вам помогут и сможете:

✅ Определять тип пагинации
✅ Автоматически перелистывать все страницы
✅ Извлекать данные из карточек
✅ Сохранять результат в CSV с поддержкой кириллицы
✅ Добавлять защиту от ошибок и дублей

Этот шаблон работает на любом каталоге — от маркетплейсов до новостных лент, может с небольшими правками под ваши потребности. Главное у вас есть основа!

🐍 Сохраните код — и вы сможете собирать данные с любого пагинированного сайта за минуты.

🔁 Если вы парсите сайты, посмотрите также:
python парсинг js сайта — сбор данных с динамических страниц через Playwright
python парсинг таблицы html — извлечение таблиц в DataFrame
python скачать изображения с сайта — автоматическая загрузка медиа
💬 Остались вопросы? Пишите в комментариях — с радостью уточню, дополню или помогу с вашим кодом.
📢 Подписывайтесь на Telegram-канал PythonAuto, чтобы не пропустить новые гайды по автоматизации, парсингу и Python.
👉 Ваш интерес — лучшая мотивация для новых статей!

Оставьте комментарий