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
Neste artigo

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.

Perguntas frequentes

É legal raspar dados do Walmart?

O Walmart proíbe scraping em seus Termos de Uso e no robots.txt. A legalidade depende da jurisdição — nos EUA, o caso hiQ vs. LinkedIn sugeriu que dados públicos podem ser scrapeados, mas isso não é uma garantia absoluta. Consulte um advogado antes de operar em escala. Em qualquer caso, respeite rate limits e não colete PII de reviews.

Por que preciso de proxies residenciais para raspar o Walmart?

O Walmart usa Akamai Bot Manager na borda da CDN, que bloqueia IPs de datacenter conhecidos (AWS, GCP, etc.) antes mesmo de avaliar o request. Proxies residenciais usam IPs de ISPs reais, tornando o tráfego indistinguível de usuários legítimos. Sem isso, a taxa de sucesso é inferior a 5%.

O que é __NEXT_DATA__ e por que é melhor que parsear HTML?

__NEXT_DATA__ é um bloco JSON injetado pelo framework Next.js no HTML da página. Ele contém todo o estado da página serializado — preços, estoque, ratings, seller info. Parsear esse JSON é mais estável e completo do que extrair dados de elementos HTML, cujas classes e estrutura mudam frequentemente.

Como diferenciar produtos 1P do Walmart Marketplace (3P)?

No __NEXT_DATA__, o campo sellerId indica o vendedor. Se sellerId = "0" e sellerName = "Walmart.com", é 1P (vendido diretamente pelo Walmart). Qualquer outro sellerId é um vendedor Marketplace (3P). Produtos 3P podem ter múltiplos offers no array de offers.

Qual o limite de requests por minuto para não ser bloqueado?

Empiricamente: ~50 requests/min por IP para páginas de produto, ~20 para páginas de busca. Exceder esses limites por mais de 2-3 minutos dispara captcha PerimeterX ou 403 silencioso. Use rotação de IP por request com proxies residenciais e delays aleatórios de 2-5 segundos entre requests.

Monitore preços e concorrentes sem ser bloqueado

Proxies residenciais confiáveis para dados de e-commerce. Cadastre-se e colete dados limpos.

Começar
← Voltar ao Blog