Guia Prático de Raspagem de Dados do Walmart em 2025

Aprenda a extrair dados de produtos do Walmart contornando Akamai e PerimeterX, parseando __NEXT_DATA__ com Python e usando proxies residenciais para obter preços, estoque e vendedores Marketplace.

Guia Prático de Raspagem de Dados do Walmart em 2025

API ou HTML? A escolha que define sua estratégia de scraping no Walmart

Se você está lendo este artigo, provavelmente já tentou raspar dados do Walmart e bateu de frente com um bloqueio Akamai. A primeira pergunta que toda equipe de inteligência de varejo deve responder é: vou consumir endpoints de API ou parsear o HTML renderizado?

A resposta curta para o Walmart: HTML com extração do JSON embutido em __NEXT_DATA__ é o caminho mais confiável. O Walmart não oferece uma API pública para catálogo, e os endpoints internos que alimentam o front-end são protegidos por tokens de sessão vinculados ao navegador. Tentar chamar essas APIs diretamente exige engenharia reversa constante — um jogo de gato-e-rato que consome mais recursos do que vale.

A abordagem pragmática: carregue a página via proxy residencial, extraia o bloco <script id="__NEXT_DATA__"> do HTML e parseie o JSON. Você obtém exatamente os mesmos dados que a API interna serviria, sem precisar reverse-engineerar headers dinâmicos.

Estrutura do catálogo do Walmart — URLs que você precisa conhecer

O Walmart organiza seu catálogo em três superfícies principais. Cada uma tem um padrão de URL previsível:

Páginas de produto (item pages)

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

  • slug — texto SEO do nome do produto (pode ser qualquer coisa, o servidor ignora)
  • itemId — identificador numérico único; é o único campo obrigatório

Exemplo real: https://www.walmart.com/ip/Apple-AirPods-Pro-2nd-Generation/1752637026

O itemId é a chave primária. Se você trocar o slug por texto aleatório, a página carrega normalmente. Isso significa que você pode construir URLs diretamente a partir de uma lista de IDs.

Páginas de categoria

Formato: https://www.walmart.com/c/{categorySlug}

Categorias de topo como electronics, home, toys têm páginas que listam subcategorias e produtos em destaque. São úteis para descoberta de IDs, mas a paginação via infinite scroll é carregada por chamadas AJAX que exigem sessões autenticadas.

Páginas de busca

Formato: https://www.walmart.com/search?q={query}&sort={sortType}&page={pageNum}

Parâmetros úteis:

  • sort=price_low, sort=price_high, sort=best_seller, sort=rating
  • page=1, page=2… — paginação simples
  • affinityOverride=default — remove personalização de resultados

Akamai + PerimeterX: por que você precisa de proxies residenciais

O Walmart emprega uma stack anti-bot em duas camadas:

CamadaTecnologiaO que detectaConsequência
Edge / CDNAkamai Bot ManagerAssinatura de TLS (JA3), comportamento de conexão, IPs de datacenter conhecidosHTTP 403 sem corpo, ou challenge page
AplicaçãoPerimeterX (agora HUMAN)Fingerprint de navegador, mouse/scroll events, inconsistências de JSCaptcha interativo ou bloco silencioso

Na prática, isso significa que:

  • IPs de datacenter são bloqueados na borda — você nem chega ao PerimeterX. O Akamai rejeita ranges de IPs de provedores como AWS, GCP, DigitalOcean antes mesmo de avaliar o request.
  • Proxies de datacenter rotativos funcionam por minutos — até o Akamai catalogar o range. Depois, taxa de sucesso cai para <5%.
  • Proxies residenciais com rotação por request são o único caminho viável para scraping em escala. Cada request sai de um IP diferente associado a um ISP residencial real.

Regra prática: se você está raspando mais de ~200 páginas/hora no Walmart, proxies residenciais não são opcionais — são infraestrutura.

Para sessões que exigem persistência (como adicionar ao carrinho ou verificar estoque por CEP), use sessões sticky com proxies residenciais, mantendo o mesmo IP por 10–30 minutos.

__NEXT_DATA__: o caminho mais fácil para extrair dados de produto

O Walmart usa Next.js no front-end. O framework injeta um bloco <script id="__NEXT_DATA__" type="application/json"> no HTML com todo o estado da página serializado como JSON. Isso inclui:

  • Preço atual e histórico recente
  • Status de estoque (in-stock, out-of-stock, limited)
  • Avaliações (rating médio, contagem de reviews)
  • Dados do vendedor (Walmart 1P ou Marketplace 3P)
  • Opções de envio e estimativas de entrega
  • Variações (tamanhos, cores, modelos)

O seletor CSS para localizar o bloco:

script#__NEXT_DATA__

O XPath equivalente:

//script[@id='__NEXT_DATA__']/text()

Exemplo truncado da estrutura do JSON:

{
  "props": {
    "pageProps": {
      "initialData": {
        "data": {
          "product": {
            "id": "1752637026",
            "name": "Apple AirPods Pro 2nd Generation",
            "priceInfo": {
              "currentPrice": { "price": 189.00, "currencyUnit": "USD" },
              "priceRange": "189.00"
            },
            "availabilityStatus": "IN_STOCK",
            "averageRating": 4.6,
            "numberOfReviews": 15234,
            "sellerId": "0",
            "sellerName": "Walmart.com",
            "shipMethods": [...],
            "variants": [...]
          }
        }
      }
    }
  }
}

Compare isso com parsear o HTML renderizado manualmente — você teria que lidar com classes CSS que mudam semanalmente, seletores frágeis e dados espalhados por diferentes componentes React. Com __NEXT_DATA__, você acessa a fonte estruturada diretamente.

Python: buscando e parseando __NEXT_DATA__ com proxies residenciais

Abaixo, um script completo que faz request via proxy residencial ProxyHat, extrai e parseia o __NEXT_DATA__ e retorna um dicionário limpo com os campos mais relevantes.

import requests
import json
from urllib.parse import quote

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

HEADERS = {
    "User-Agent": (
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/126.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",
}

def fetch_product(item_id: str, session_id: str = None) -> dict:
    """Busca página de produto e extrai __NEXT_DATA__."""
    url = f"https://www.walmart.com/ip/product/{item_id}"
    
    # Usa sessão sticky se fornecida, senão rotação por request
    if session_id:
        proxy = f"http://user-country-US-session-{session_id}:PASSWORD@gate.proxyhat.com:8080"
        proxies = {"http": proxy, "https": proxy}
    else:
        proxies = PROXIES
    
    resp = requests.get(url, headers=HEADERS, proxies=proxies, timeout=30)
    resp.raise_for_status()
    
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(resp.text, "html.parser")
    
    script_tag = soup.find("script", id="__NEXT_DATA__")
    if not script_tag:
        raise ValueError("__NEXT_DATA__ não encontrado na página")
    
    data = json.loads(script_tag.string)
    return data

def parse_product(next_data: dict) -> dict:
    """Extrai campos-chave do JSON __NEXT_DATA__."""
    try:
        product = next_data["props"]["pageProps"]["initialData"]["data"]["product"]
    except KeyError:
        raise ValueError("Estrutura inesperada em __NEXT_DATA__")
    
    price_info = product.get("priceInfo", {})
    current = price_info.get("currentPrice", {})
    
    return {
        "item_id": product.get("id"),
        "name": product.get("name"),
        "price": current.get("price"),
        "currency": current.get("currencyUnit", "USD"),
        "availability": product.get("availabilityStatus"),
        "rating": product.get("averageRating"),
        "review_count": product.get("numberOfReviews"),
        "seller_id": product.get("sellerId"),
        "seller_name": product.get("sellerName"),
        "is_marketplace": product.get("sellerId", "0") != "0",
    }

# --- Uso ---
if __name__ == "__main__":
    raw = fetch_product("1752637026")
    result = parse_product(raw)
    print(json.dumps(result, indent=2))

Pontos importantes sobre este script:

  • O country-US no username do proxy garante IP residencial americano — essencial, pois o Walmart redireciona tráfego internacional e exibe preços/catálogos diferentes.
  • O header User-Agent deve ser de um navegador desktop recente. Não use strings genéricas como python-requests/2.x.
  • O Accept-Encoding: gzip, deflate, br é necessário porque o Akamai usa compressão Brotli como fingerprint.

Exemplo com curl

curl -x http://user-country-US:PASSWORD@gate.proxyhat.com:8080 \
  -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" \
  -H "Accept: text/html,application/xhtml+xml" \
  -H "Accept-Language: en-US,en;q=0.9" \
  "https://www.walmart.com/ip/product/1752637026"

Marketplace (3P) vs catálogo 1P — como diferenciar

O Walmart opera dois modelos de venda:

  • 1P (first-party) — o Walmart é o vendedor. sellerId = "0" e sellerName = "Walmart.com". Preços e estoque são controlados diretamente pelo Walmart.
  • 3P (Marketplace) — vendedores terceiros. sellerId é um número não-zero. O produto pode ter múltiplos offers de diferentes vendedores.

No __NEXT_DATA__, a diferença aparece em dois lugares:

  1. No campo sellerId do objeto principal do produto.
  2. No array offers (quando presente), que lista todos os vendedores Marketplace para o mesmo item.

Para equipes de inteligência de varejo, isso é crucial:

  • Monitorar apenas 1P dá a visão da estratégia de precificação do próprio Walmart.
  • Incluir 3P revela a competitividade de preço no Marketplace — essencial para marcas CPG que vendem via distribuidores.
  • Produtos 3P podem ter preços artificialmente baixos (loss leaders) que distorcem análises se não forem filtrados.
def classify_seller(product_data: dict) -> dict:
    """Classifica se o produto é 1P ou 3P e extrai offers."""
    seller_id = product_data.get("seller_id", "0")
    is_3p = seller_id != "0"
    
    result = {
        "is_marketplace": is_3p,
        "seller_name": product_data.get("seller_name"),
        "seller_id": seller_id,
    }
    
    # Se houver offers múltiplos no JSON bruto
    raw_offers = product_data.get("_raw", {}).get("offers", [])
    if raw_offers:
        result["offer_count"] = len(raw_offers)
        result["lowest_offer_price"] = min(
            float(o.get("priceInfo", {}).get("currentPrice", {}).get("price", float("inf")))
            for o in raw_offers
        )
    
    return result

Agendamento com consciência de rate limits

O Walmart não publica limites de taxa oficiais. Por observação empírica, estes são os thresholds que provocam bloqueios:

SuperfícieLimite observadoConsequência ao exceder
Páginas de produto~50 requests/min por IPCaptcha PerimeterX após 2-3 minutos sustained
Páginas de busca~20 requests/min por IP403 silencioso ou redirect para challenge page
APIs internas (AJAX)~10 requests/min por IPBloqueio imediato — fingerprint diferente de browser

Estratégia de agendamento recomendada:

  1. Rotação de IP por request — cada request usa um IP residencial diferente via ProxyHat. Isso distribui o volume entre milhares de IPs.
  2. Delay entre requests — mesmo com rotação, adicione 2–5 segundos de delay aleatório. Isso reduz a chance de padrões de acesso serem detectados no nível do datacenter.
  3. Janelas de coleta — para monitoramento de preço, colete em intervalos de 1–4 horas. Para verificação de estoque, intervalos de 15–30 minutos são suficientes.
  4. Backoff exponencial — ao receber 403 ou captcha, aplique backoff de 30s → 60s → 120s antes de tentar com novo IP.
import time
import random
import requests
from datetime import datetime

PROXY_URL = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"
PROXIES = {"http": PROXY_URL, "https": PROXY_URL}
HEADERS = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "Accept": "text/html,application/xhtml+xml",
    "Accept-Language": "en-US,en;q=0.9",
}

def scrape_with_backoff(item_ids: list[str], max_retries: int = 3):
    results = []
    for i, item_id in enumerate(item_ids):
        url = f"https://www.walmart.com/ip/product/{item_id}"
        for attempt in range(max_retries):
            try:
                resp = requests.get(url, headers=HEADERS, proxies=PROXIES, timeout=30)
                if resp.status_code == 200:
                    # Processar __NEXT_DATA__ como no exemplo anterior
                    results.append({"item_id": item_id, "status": "success"})
                    break
                elif resp.status_code == 403:
                    wait = 30 * (2 ** attempt) + random.uniform(0, 10)
                    print(f"403 para {item_id}, aguardando {wait:.0f}s...")
                    time.sleep(wait)
                else:
                    print(f"Status {resp.status_code} para {item_id}")
                    break
            except requests.RequestException as e:
                print(f"Erro em {item_id}: {e}")
                time.sleep(10)
        
        # Delay entre requests para evitar padrões detectáveis
        delay = random.uniform(2.0, 5.0)
        time.sleep(delay)
    
    return results

# Executar coleta
item_ids = ["1752637026", "5432876543", "9876543210"]
scrape_with_backoff(item_ids)

Comparação: proxies residenciais vs datacenter vs mobile para Walmart

CaracterísticaDatacenterResidencialMobile
Taxa de sucesso no Walmart<5%85–95%90–98%
Velocidade médiaRápido (<1s)Moderado (1–3s)Lento (2–5s)
Custo por GBMenorMédioMaior
Ideal paraTestes unitáriosScraping em escalaMobile-specific ou máxima stealth
Risco de bloqueioAltíssimoBaixoMuito baixo

Para a maioria dos casos de uso em Walmart product data, proxies residenciais com rotação por request oferecem o melhor equilíbrio entre custo e confiabilidade. Proxies mobile são reservados para cenários específicos onde o tráfego mobile precisa ser simulado — por exemplo, verificar preços exibidos no app mobile vs desktop.

Considerações éticas e legais

Antes de escalar qualquer operação de scraping no Walmart, considere:

  • robots.txt — o Walmart proíbe scraping de /ip/ e /search no robots.txt. Respeitar ou não depende do seu caso de uso e jurisdição.
  • Termos de uso — os ToS do Walmart proíbem acesso automatizado. Violar ToS pode ter consequências legais dependendo da sua localização.
  • GDPR/CCPA — se você coleta dados de usuários (reviews com PII, por exemplo), está sujeito a regulamentações de privacidade.
  • Rate limits — mesmo com proxies residenciais, respeite limites razoáveis. Não tente DDoS o Walmart.

A recomendação: colete apenas os dados necessários para sua análise, armazene o mínimo possível, e nunca redistribua dados protegidos por direitos autorais (imagens de produto, descrições completas) sem autorização.

Principais conclusões

  • Use __NEXT_DATA__ — não parseie HTML manualmente. O JSON embutido dá acesso a todos os dados de produto de forma estruturada e estável.
  • Proxies residenciais são obrigatórios — o Akamai bloqueia IPs de datacenter na borda. Sem IP residencial, você nem chega ao conteúdo.
  • Diferencie 1P de 3PsellerId = "0" é Walmart direto. Qualquer outro ID é Marketplace. Misturar os dois distorce análises de preço.
  • Rate limiting empático — 50 req/min/IP para produtos, 20 para busca. Use rotação + delays aleatórios.
  • Backoff exponencial — ao receber 403, não insista. Aplique backoff e tente com IP diferente.

Se sua equipe precisa de Walmart proxy confiável para raspagem em escala, a ProxyHat oferece proxies residenciais com geo-targeting por país e cidade, rotação por request e sessões sticky — exatamente o que você precisa para contornar Akamai e PerimeterX. Para mais detalhes sobre casos de uso, veja nosso guia de web scraping com proxies.

Pronto para começar?

Acesse mais de 50M de IPs residenciais em mais de 148 países com filtragem por IA.

Ver preçosProxies residenciais
← Voltar ao Blog