Как скрейпить Walmart: полное руководство по товарным данным

Практическое руководство по скрейпингу Walmart: структура каталога, обход Akamai и PerimeterX, парсинг __NEXT_DATA__, residential-прокси для извлечения цен, наличия и данных продавцов.

Как скрейпить Walmart: полное руководство по товарным данным

Скрейпинг Walmart: API или HTML?

Если вы пытаетесь получить Walmart product data в масштабе, перед вами два пути. Первый — Walmart Developer API (через Affiliate-программу). Он удобен для базовых запросов, но ограничен: не все поля доступны, лимиты жёсткие, а доступ требует одобрения. Второй — скрейпинг HTML-страниц. Он даёт полный контроль над данными, но сталкивается с мощной антибот-защитой.

Оптимальный вариант для CPG-команд и retail intelligence — парсинг встроенного JSON (__NEXT_DATA__) в HTML-страницах Walmart через residential-прокси. Вы получаете те же данные, что видит браузер, без overhead headless-рендеринга и без зависимости от хрупких CSS-селекторов.

Структура каталога Walmart

Walmart организует каталог через три основных типа страниц. Понимание их URL-паттернов — первый шаг к эффективному скрейпингу.

Страницы товаров (Item Pages)

URL-паттерн:

https://www.walmart.com/ip/{slug}/{itemId}

Пример: https://www.walmart.com/ip/Apple-AirPods-Pro/173434858

Здесь itemId — уникальный числовой идентификатор товара. Slug может меняться, но itemId стабилен. Если у вас есть список itemId, вы можете напрямую формировать URL без поиска. Это самый эффективный способ массового сбора данных.

Категорийные страницы

URL-паттерн:

https://www.walmart.com/cp/{category-slug}/{categoryId}

Пример: https://www.walmart.com/cp/electronics/3944

Категорийные страницы содержат списки товаров с базовой информацией: название, цена, рейтинг, изображение. Они удобны для обнаружения новых товаров в категории.

Поиск

URL-паттерн:

https://www.walmart.com/search?q={query}&sort=price_low&facet=brand:Apple

Ключевые параметры запроса:

  • q — поисковый запрос
  • sort — сортировка: price_low, price_high, rating, best_seller
  • facet — фильтры: бренд, ценовой диапазон, рейтинг
  • page — номер страницы (пагинация)

CSS-селекторы для страниц поиска и категорий:

  • Название товара: [data-testid="product-title"]
  • Цена: [data-testid="price-wrap"] .price-characteristic
  • Рейтинг: [data-testid="product-star-rating"]
  • Ссылка на товар: [data-testid="product-title"] a[href]

Но вместо парсинга DOM мы рекомендуем извлекать данные из __NEXT_DATA__ — это надёжнее и проще.

Антибот-стек: Akamai + PerimeterX

Чтобы скрейпить Walmart, нужно понимать, что именно вас блокирует. Walmart использует двухуровневую защиту от автоматизированных запросов.

Akamai Bot Manager

Akamai анализирует TLS-fingerprint, HTTP/2 fingerprint, порядок заголовков и паттерны поведения. Сенсорный JavaScript Akamai собирает данные о браузере: Canvas fingerprint, WebGL-рендер, список шрифтов, разрешение экрана, производительность. На основе этих данных формируется cookie _abck, который проверяется при каждом запросе. Если fingerprint не проходит проверку — вы получаете 403 или редирект на challenge-страницу.

PerimeterX (ныне HUMAN)

PerimeterX работает как второй слой, особенно на страницах поиска и категорий. Он генерирует JavaScript-challenge и проверяет _px3 cookie. PerimeterX активнее на страницах с высокой коммерческой ценностью — поиск, категории электроники, игрушки в сезон праздников.

Почему нужны residential-прокси

Datacenter-IP-адреса блокируются Akamai практически сразу — они попадают в списки известных хостинг-провайдеров. Walmart proxy должен быть residential или mobile:

  • Residential-прокси — IP-адреса реальных пользователей. Akamai пропускает их с высокой вероятностью. Оптимальный баланс цены и эффективности.
  • Mobile-прокси — ещё лучше для обхода, но дороже и медленнее. Идеальны для критичных задач.
  • Datacenter-прокси — подходят только для невысоких нагрузок или тестирования. Блокируются быстро.

Геолокация также важна: Walmart показывает разные цены и ассортимент для разных регионов США. С ProxyHat вы можете указать штат: user-country-US-state-TX:PASSWORD@gate.proxyhat.com:8080

Подробнее о типах прокси — в нашем сравнении residential и datacenter прокси.

Парсинг __NEXT_DATA__: самый простой путь

Walmart использует Next.js, и каждая страница содержит тег:

<script id="__NEXT_DATA__" type="application/json">{...}</script>

Внутри — полное JSON-представление данных страницы. Это избавляет от необходимости парсить DOM: все нужные данные уже в структурированном виде.

Преимущества подхода:

  • Не нужен headless-браузер — достаточно HTTP-запроса
  • Данные уже в JSON-формате — нет хрупких CSS-селекторов
  • Включает цену, наличие, рейтинг, информацию о продавце
  • Не ломается при изменении дизайна сайта

Иерархия данных в __NEXT_DATA__:

  • props.pageProps.initialData.data.product — основная информация о товаре
  • priceInfo — текущая цена, скидки, диапазоны
  • availabilityState — статус наличия (IN_STOCK, OUT_OF_STOCK)
  • averageRating / numberOfReviews — рейтинг и отзывы
  • sellerId / sellerName — информация о продавце
  • buyBoxProducts — массив всех предложений (1P + 3P)

Python: получение и парсинг __NEXT_DATA__

Первый пример — базовый запрос через residential-прокси ProxyHat:

import requests

PROXY = "http://user-country-US:YOUR_PASSWORD@gate.proxyhat.com:8080"
PROXIES = {"http": PROXY, "https": PROXY}

HEADERS = {
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/125.0.0.0 Safari/537.36"
    ),
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Referer": "https://www.walmart.com/",
}

def fetch_item_page(item_id: str) -> str:
    url = f"https://www.walmart.com/ip/{item_id}"
    response = requests.get(url, headers=HEADERS, proxies=PROXIES, timeout=30)
    response.raise_for_status()
    return response.text

Второй пример — извлечение и парсинг __NEXT_DATA__:

import json
from bs4 import BeautifulSoup

def extract_next_data(html: str) -> dict:
    soup = BeautifulSoup(html, "html.parser")
    script_tag = soup.find("script", id="__NEXT_DATA__")
    if not script_tag:
        raise ValueError("__NEXT_DATA__ не найден — возможно, страница заблокирована")
    return json.loads(script_tag.string)

def parse_product(next_data: dict) -> dict:
    try:
        product = next_data["props"]["pageProps"]["initialData"]["data"]["product"]
    except KeyError:
        raise ValueError("Структура __NEXT_DATA__ изменилась или данные отсутствуют")

    price_info = product.get("priceInfo", {})
    current_price = price_info.get("currentPrice", {})

    return {
        "item_id": product.get("itemId"),
        "name": product.get("name"),
        "brand": product.get("brand"),
        "price": current_price.get("price"),
        "currency": current_price.get("currencyUnit", "USD"),
        "availability": product.get("availabilityState", "UNKNOWN"),
        "rating": product.get("averageRating"),
        "review_count": product.get("numberOfReviews"),
        "seller_id": product.get("sellerId"),
        "seller_name": product.get("sellerName"),
        "is_marketplace": product.get("isMarketplaceItem", False),
    }

Пример результата (сокращённо):

{
  "item_id": "173434858",
  "name": "Apple AirPods Pro",
  "brand": "Apple",
  "price": 189.00,
  "currency": "USD",
  "availability": "IN_STOCK",
  "rating": 4.5,
  "review_count": 12847,
  "seller_id": "F55CDC31AB754BB68E0183D932CB3514",
  "seller_name": "Walmart.com",
  "is_marketplace": false
}

Marketplace (3P) vs 1P: как различать

Walmart Marketplace — платформа для сторонних продавцов. Для CPG-аналитики критически важно различать товары Walmart (1P) и товары маркетплейса (3P), поскольку цены, наличие и условия доставки могут кардинально отличаться.

Ключевые поля в __NEXT_DATA__:

  • isMarketplaceItemtrue для товаров 3P-продавцов
  • sellerId — для Walmart.com обычно F55CDC31AB754BB68E0183D932CB3514
  • sellerName"Walmart.com" для 1P
  • fulfillmentType"WARRANTED" для 1P, "MARKETPLACE" для 3P

Извлечение всех предложений для товара

На странице товара может быть несколько предложений от разных продавцов. Они находятся в массиве buyBoxProducts:

def parse_all_offers(product: dict) -> list[dict]:
    offers = product.get("buyBoxProducts", [])
    results = []
    for offer in offers:
        price_info = offer.get("priceInfo", {})
        current_price = price_info.get("currentPrice", {})
        results.append({
            "seller_id": offer.get("sellerId"),
            "seller_name": offer.get("sellerName"),
            "price": current_price.get("price"),
            "availability": offer.get("availabilityState"),
            "fulfillment": offer.get("fulfillmentType"),
            "is_marketplace": offer.get("isMarketplaceItem", False),
            "shipping": offer.get("shippingPrice", {}).get("price", 0),
        })
    return results

Для retail-intelligence команд это ключевой инструмент: один и тот же товар может продаваться Walmart напрямую по $189 и десятком 3P-продавцов по $175–$220. Мониторинг всех предложений даёт полную картину конкурентного ландшафта и MAP-нарушений.

Ограничения скорости и планирование запросов

Walmart не публикует официальные лимиты для скрейперов, но эмпирические наблюдения показывают следующие пороги:

Тип запросаОриентировочный лимитРекомендуемая задержка
Страницы товаров~30–50 req/min с одного IP2–3 секунды
Поиск~10–20 req/min с одного IP5–8 секунд
Категорийные страницы~15–25 req/min с одного IP4–6 секунд

Эти лимиты зависят от IP-репутации, времени суток и общей нагрузки. Превышение приводит к 429 Too Many Requests или 403 с Akamai-challenge.

Rate-limit-aware скрейпинг

import time
import random
from datetime import datetime

class WalmartScheduler:
    def __init__(self, max_rpm: int = 40):
        self.max_rpm = max_rpm
        self.request_timestamps: list[float] = []

    def wait_if_needed(self):
        now = time.time()
        self.request_timestamps = [
            t for t in self.request_timestamps if now - t < 60
        ]
        if len(self.request_timestamps) >= self.max_rpm:
            sleep_time = 60 - (now - self.request_timestamps[0]) + 1
            print(f"[{datetime.now():%H:%M:%S}] Rate limit — ожидание {sleep_time:.0f}с")
            time.sleep(sleep_time)
        # Рандомизация для естественного паттерна
        time.sleep(random.uniform(2.0, 4.0))
        self.request_timestamps.append(time.time())

    def fetch_with_retry(self, url: str, max_retries: int = 3) -> str:
        for attempt in range(max_retries):
            try:
                self.wait_if_needed()
                resp = requests.get(url, headers=HEADERS, proxies=PROXIES, timeout=30)
                if resp.status_code == 200:
                    return resp.text
                elif resp.status_code == 429:
                    backoff = 30 * (2 ** attempt)
                    print(f"429 — экспоненциальная задержка {backoff}с")
                    time.sleep(backoff)
                elif resp.status_code == 403:
                    print("403 — IP заблокирован, необходима ротация прокси")
                    time.sleep(10)
                else:
                    resp.raise_for_status()
            except requests.RequestException as e:
                print(f"Ошибка: {e}, попытка {attempt + 1}/{max_retries}")
                time.sleep(5)
        raise Exception(f"Не удалось получить {url} после {max_retries} попыток")

Для массового сбора данных используйте ротацию sticky-сессий ProxyHat: каждая сессия держит один IP на 10–30 минут, что имитирует реальное поведение пользователя и снижает риск блокировки.

# Sticky-сессия на 30 минут с гео-таргетингом
PROXY = "http://user-country-US-session-mybatch01:YOUR_PASSWORD@gate.proxyhat.com:8080"

Сравнение подходов к скрейпингу Walmart

ПодходСложностьПолнота данныхСтабильностьСтоимость
Walmart Developer APIНизкаяОграниченные поляВысокаяБесплатно / Affiliate
__NEXT_DATA__ парсингСредняяПолные данные товараСредняяПрокси
DOM-парсинг HTMLВысокаяПолные, но хрупкиеНизкаяПрокси
Headless-браузерВысокаяПолные + динамическиеСредняяПрокси + инфраструктура

Рекомендация: для большинства CPG- и retail-intelligence задач парсинг __NEXT_DATA__ через residential-прокси — оптимальный вариант. Вы получаете полные структурированные данные без overhead headless-браузеров. Headless-браузер нужен только если Akamai-challenge не пропускает обычные HTTP-запросы даже через residential-прокси.

Подробнее о вариантах использования — в нашем разделе Web Scraping и SERP Tracking.

Практические рекомендации

  • Всегда используйте residential-прокси — datacenter-IP блокируются Akamai в течение первых нескольких запросов. Начните с тарифов ProxyHat.
  • Ротируйте sticky-сессии — сессии на 10–30 минут лучше, чем ротация каждого запроса, так как это имитирует реальное поведение.
  • Рандомизируйте задержки — равномерные интервалы в 2 секунды выглядят как бот. Добавьте случайную вариацию ±50%.
  • Кэшируйте itemId — если вы мониторите одни и те же товары, храните маппинг itemId → URL.
  • Проверяйте __NEXT_DATA__ первым — если тег отсутствует, страница вероятно заблокирована. Не тратьте время на парсинг DOM.
  • Мониторьте все предложения — для CPG-аналитики важны не только цены Walmart, но и 3P-продавцов.
  • Соблюдайте robots.txt — Walmart указывает ограничения в robots.txt. Уважайте их для этичного скрейпинга.
Для масштабного мониторинга цен Walmart используйте residential-прокси с гео-таргетингом — Walmart показывает разные цены и доступность товаров в зависимости от региона. С ProxyHat вы можете указать штат: user-country-US-state-TX:PASSWORD@gate.proxyhat.com:8080. Доступные локации смотрите на странице локаций.

Ключевые выводы

  • Walmart использует Akamai + PerimeterX — residential-прокси обязательны для обхода. Datacenter-IP не работают.
  • __NEXT_DATA__ — самый простой путь к структурированным данным о товарах без headless-браузера.
  • Различайте 1P и 3P по полю isMarketplaceItem — для CPG-аналитики это критично.
  • Держите скорость ниже 40–50 req/min на IP и рандомизируйте задержки для естественного паттерна.
  • При 403/429 — ротируйте IP и применяйте экспоненциальный backoff. Sticky-сессии ProxyHat помогают сохранить IP на 10–30 минут.

Готовы начать?

Доступ к более чем 50 млн резидентных IP в 148+ странах с AI-фильтрацией.

Смотреть ценыРезидентные прокси
← Вернуться в Блог