Скрейпинг 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_sellerfacet— фильтры: бренд, ценовой диапазон, рейтинг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__:
isMarketplaceItem—trueдля товаров 3P-продавцовsellerId— для Walmart.com обычноF55CDC31AB754BB68E0183D932CB3514sellerName—"Walmart.com"для 1PfulfillmentType—"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 с одного IP | 2–3 секунды |
| Поиск | ~10–20 req/min с одного IP | 5–8 секунд |
| Категорийные страницы | ~15–25 req/min с одного IP | 4–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 минут.






