Парсинг сайтов на Python: как победить бесконечную прокрутку без браузера

📝 Кратко: При работе с современными лентами новостей или каталогами обычный сбор HTML не помогает. Мы разберем профессиональный парсинг сайтов на Python, научимся перехватывать токены пагинации и имитировать бесконечную прокрутку без тяжелых браузеров.
Схема работы пагинации через токены cursor и offset: парсинг сайтов на python

Приветствую читателей моего блога! Каждый, кто хоть раз пробовал собирать данные с крупных маркетплейсов или соцсетей, сталкивался с «бесконечной стеной». Вы запускаете скрипт, он забирает первые 10-20 товаров, и на этом всё — дальше пустота. Вы открываете код страницы, а там вместо списка товаров какой-то непонятный JavaScript. Это и есть бесконечная прокрутка (Infinite Scroll).

Раньше мы обсуждали автоматизацию браузера на Python с Playwright
, и это рабочий метод, но он медленный, как черепаха. Сегодня я научу вас делать парсинг сайтов на Python по-умному: мы будем имитировать действия браузера через прямые запросы. Это в десятки раз быстрее, стабильнее и потребляет минимум памяти вашего компьютера или сервера.

Почему классический парсинг «ломается» на бесконечном скролле?

Когда мы используем классический подход (запрос к URL и разбор через BeautifulSoup), мы получаем только тот HTML-код, который сервер отдает при первой загрузке. В 2026 году почти никто не отдает весь каталог сразу — это слишком тяжело для сервера. Вместо этого сайт загружает «скелет», а затем, когда вы крутите колесико мыши вниз, скрипт на странице отправляет скрытый запрос за следующей порцией данных. Если вы просто делаете requests.get(url), вы никогда не увидите эти данные, потому что ваш скрипт не умеет «скроллить» и не знает, какой именно запрос нужно отправить.

Многие новички решают проблему в лоб: запускают Selenium или Playwright, пишут цикл, который имитирует нажатие клавиши Page Down, и ждут. Это работает, но если вам нужно спарсить 100 000 позиций, такой парсер будет работать сутки, постоянно зависать и «съест» всю оперативную память. Профессиональный парсинг сайтов на Python строится на реверс-инжиниринге: мы находим тот самый запрос, который подгружает данные, и просто повторяем его в цикле с нужными параметрами. Это позволяет получать чистый JSON-ответ, который даже парсить не нужно — он уже готов к работе.

Механика Infinite Scroll: ищем Cursor и Offset

Чтобы повторить запрос браузера, нам нужно понять его логику. Откройте панель разработчика (F12), перейдите во вкладку Network и выберите фильтр Fetch/XHR. Теперь прокрутите страницу вниз. Вы увидите, как в списке появляются новые запросы. Обычно они возвращают JSON. Самое важное здесь — это параметры запроса (Query String Parameters). Чаще всего сайты используют один из двух методов пагинации:

  1. Offset-based пагинация: В запросе вы увидите параметры вроде limit=20 и offset=40. Здесь всё просто: limit — это сколько товаров за раз, а offset — это сколько товаров пропустить. Чтобы «скроллить» дальше, мы просто увеличиваем offset в цикле: 0, 20, 40, 60…
  2. Cursor-based пагинация: Это более сложный и современный метод. В ответе сервера приходит специальный ключ (токен), например: "next_cursor": "YXJ0aWNsZTM0". Чтобы получить следующую порцию данных, вы должны отправить этот ключ в следующем запросе. Это похоже на эстафету, где каждый запрос передает палочку следующему.

📚 Документация: Requests: HTTP for Humans «Библиотека Requests позволяет отправлять HTTP/1.1 запросы с использованием простых методов. Вам не нужно вручную добавлять параметры к URL или кодировать данные форм — всё это делается автоматически через словарь params».

Реальный кейс: Парсинг бесконечной ленты новостей

Давайте разберем это на примере. Представьте сайт-агрегатор (у вас свой который вы хотите парсить), который подгружает новости по мере скролла. Мы выяснили в Network, что данные приходят к примеру с адреса api.news-site.com/v1/articles?limit=10&cursor=.... Наша задача — написать скрипт, который будет забирать новости одну за другой, пока не достигнет конца ленты или нашего лимита. При реализации такого проекта важно следить за чистотой кода, в чем вам помогут наши практические советы по чистому коду на Python.

Подготовка сессии и заголовков

Сайты часто проверяют User-Agent и другие заголовки, чтобы отсечь ботов. Мы будем использовать requests.Session(), чтобы сохранять куки, так как некоторые API не отдают данные без валидной сессии. Если сайт требует авторизации, вам пригодится наш метод про извлечение cookies Chrome на Python, чтобы ваш скрипт выглядел как ваш реальный браузер.

import requests
import time

def scrape_infinite_scroll(max_pages=10):
    base_url = "https://api.news-site.com/v1/articles"
    
    # Заголовки обязательны для имитации реального пользователя
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
        "Accept": "application/json"
    }
    
    # Начальные параметры (cursor пустой для первой страницы)
    params = {
        "limit": 10,
        "cursor": ""
    }
    
    all_data = []
    session = requests.Session()

    for page in range(max_pages):
        print(f"Загрузка страницы {page + 1}...")
        
        try:
            # Делаем запрос к API
            response = session.get(base_url, headers=headers, params=params, timeout=10)
            response.raise_for_status()
            
            # Парсим JSON-ответ
            json_data = response.json()
            items = json_data.get("data", [])
            
            if not items:
                print("Данные закончились.")
                break
                
            all_data.extend(items)
            
            # Получаем токен для следующей страницы (Cursor)
            next_cursor = json_data.get("meta", {}).get("next_cursor")
            
            if not next_cursor:
                print("Это была последняя страница.")
                break
            
            # Обновляем токен для следующей итерации цикла
            params["cursor"] = next_cursor
            
            # Пауза — вежливость парсера (защита от бана)
            time.sleep(1.5)
            
        except Exception as e:
            print(f"Ошибка на итерации {page}: {e}")
            break
            
    return all_data

Глубокий разбор кода: как это работает?

Давайте разберем, что происходит в этом коде. Мы используем цикл for, чтобы ограничить количество запросов (всегда полезно иметь «аварийный выход»), но внутри мы управляем логикой через params["cursor"]. В каждом ответе от сервера мы ищем ключ next_cursor. Если он есть, мы подставляем его в параметры следующего запроса. Это и есть имитация скролла: браузер делает ровно то же самое, когда вы доходите до конца страницы.

Если вы работаете с огромными объемами данных, например, парсите товары с пагинацией для интернет-магазина, вам может понадобиться ускорение. В таких случаях рекомендую изучить многопоточность и асинхронность в Python, чтобы отправлять запросы параллельно. Однако с бесконечным скроллом на основе cursor это сделать сложнее, так как каждый следующий запрос зависит от предыдущего.

Как обрабатывать ошибки и обходить блокировки

Парсинг сайтов на Python — это всегда игра в «кошки-мышки» с антифрод-системами. Если вы будете слать запросы слишком часто, API выдаст ошибку 429 Too Many Requests или вовсе забанит ваш IP. Чтобы этого избежать:

  • Ротация User-Agent: Используйте библиотеку fake-useragent, чтобы каждый запрос шел от «нового» браузера.
  • Использование прокси: Если нужно собрать миллионы строк, без прокси не обойтись. О том, как их подключать, мы писали в статье про смену User-Agent и работу с прокси.
  • Обработка JSON: Всегда проверяйте структуру ответа. Иногда сервер вместо данных может прислать сообщение о капче. Кстати, если вы столкнулись с ней, посмотрите наш гайд по автоматическому решению капчи.

Полный код проекта для парсинга бесконечной ленты

Ниже представлен финальный вариант скрипта. Я добавил в него базовую обработку ошибок и сохранение результата в JSON-файл. Это готовый шаблон, который вы можете адаптировать под любой сайт, просто заменив api_url и структуру парсинга полей.

import requests
import time
import json

def fetch_all_items(api_url, max_requests=20):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...",
        "Accept": "application/json"
    }
    
    params = {"limit": 50, "offset": 0}
    results = []
    
    with requests.Session() as session:
        for i in range(max_requests):
            print(f"Запрос #{i+1}, смещение {params['offset']}...")
            
            try:
                response = session.get(api_url, headers=headers, params=params, timeout=10)
                if response.status_code != 200:
                    break
                
                data = response.json()
                items = data.get("items", [])
                
                if not items:
                    break
                
                results.extend(items)
                
                # Пример для Offset-пагинации
                params["offset"] += 50
                
                time.sleep(1) # Будьте вежливы к серверу
                
            except Exception as e:
                print(f"Ошибка: {e}")
                break
                
    return results

if __name__ == "__main__":
    TARGET_API = "https://api.test-site.com/get-data"
    final_data = fetch_all_items(TARGET_API)
    
    with open("results.json", "w", encoding="utf-8") as f:
        json.dump(final_data, f, ensure_ascii=False, indent=4)
    
    print(f"Готово! Сохранено объектов: {len(final_data)}")

Заключение

Парсинг сайтов на Python с бесконечной прокруткой кажется сложным только до тех пор, пока вы не заглянете во вкладку Network. Понимание того, как данные перемещаются между сервером и клиентом, дает вам суперсилу: вы можете собирать информацию быстрее, чище и эффективнее, чем 90% других разработчиков.

Не пытайтесь заставить браузер делать лишнюю работу — общайтесь с сервером напрямую. Постоянно экспериментируйте с API разных сайтов, и вы увидите, что большинство современных веб-приложений открыты для исследования гораздо больше, чем кажется на первый взгляд. Для управления своими скриптами и их зависимостями не забывайте использовать uv — современный менеджер пакетов, это сэкономит вам массу времени.

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

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