Uma dúzia de ovos Lucerne em uma unidade do Safeway em Washington, D.C. foi oferecida no Instacart por $3.99, $4.28, $4.59, $4.69 e $4.79. Mesma loja, mesmo momento, compradores diferentes. Qual desses cinco números deve entrar no seu painel de preços?
O Desafio
No setor de supermercados, a inteligência de preços deixa de ser apenas "obter a página do produto, fazer o parse do preço". O preço de um item de supermercado pertence a uma loja, frequentemente a uma zona de entrega e, cada vez mais, a quem está visualizando a página.
Comece pela loja. O guia de comparação de preços de supermercado da Scrapfly mostra um galão de leite a $3.98 em um Walmart e a $4.29 em outro a 20 milhas de distância, e alerta que uma sessão sem localização de loja recebe dados padrão que podem não corresponder a nenhuma loja real. O guia de entrega de supermercados de 2026 da ScrapeInsight observa o mesmo cenário um nível abaixo: $3.99 em uma zona de entrega, $4.49 a poucos quilômetros de distância. O estudo de caso do ShopGrok da Bright Data descreve como a precificação no varejo australiano passou a depender do código postal ao longo dos quase quatro anos de operação da empresa.
Depois, há o comprador. Em dezembro de 2025, Groundwork Collaborative, Consumer Reports e More Perfect Union submeteram 437 compradores a testes ao vivo em quatro cidades, montando carrinhos idênticos no Instacart nas mesmas lojas e no mesmo horário. 74% dos itens apareceram com mais de um preço. Onde os preços divergiram, a diferença média entre o menor e o maior valor foi de 13%, e os carrinhos completos variaram cerca de 7%.
Junte tudo isso e você terá a falha que torna os dados de supermercados caros. Perca o contexto da loja e nada quebra. O site não retorna um erro. Ele retorna um preço perfeitamente válido para uma loja que você não solicitou, com um SKU, um número e um timestamp que passam em qualquer verificação de null que você tiver.
Já escrevemos sobre a versão em que um bloqueio se parece com um ponto de dados. Esta aqui é mais difícil de identificar, porque a página é de fato uma página de preços. Só não é a sua.
Valide a Loja Dentro da Resposta
A maioria dos coletores envia a seleção da loja (um cookie, um parâmetro de query, um header) e confia nisso. O hábito mais robusto é exigir que a resposta comprove essa informação. Se a página identifica a loja para a qual foi renderizada, como um store ID nos dados embutidos ou o nome da loja no banner de retirada, esse marcador passa a ser o seu critério de sucesso. No FourA, isso é feito com uma única chamada do Proxy Finder:
import requests
r = requests.post(
"https://api.foura.ai/api/proxy",
headers={"X-API-Key": "pk_live_..."},
json={
"maxTries": 6,
"request": {
"method": "GET",
"url": "https://grocer.example/product/0001234",
"headers": [["Cookie", "store=1234"]],
"validate": {
"status": {"accept": [200]},
"data": {
"accept": ["\"storeId\":\"1234\""],
"fail": ["Just a moment", "Access Denied"]
}
}
}
}
).json()
if "error" in r:
report = r.get("attemptReport", {})
print(report.get("summary", r["error"]))
if report.get("contentRejected", 0) > report.get("defense", 0) + report.get("noResponse", 0):
print("the site answered for another store: check the store selection")
else:
page, exit_id = r["data"], r["proxy"]
Três detalhes nessa request são fáceis de errar.
accept passa quando qualquer uma de suas strings aparece na página. Se você colocar um marcador de preço ao lado do marcador de loja, uma página da loja errada passa direto, porque ela também tem um preço. Mantenha o marcador de loja sozinho em accept e coloque as strings de desafio em fail.
Seu próprio header Cookie altera o comportamento dos retries. Quando um site recusa o browser que apresentamos, o Proxy Finder normalmente muda para outra família de browsers na tentativa seguinte. Não quando o seu cookie está anexado. Uma sessão fica vinculada à assinatura que a gerou, então uma request que carrega o próprio cookie mantém o browser com o qual começou. Se o site de uma rede se mostrar exigente com browsers, escolha um explicitamente com browser profiles em vez de depender da rotação.
E uma tarefa com falha mostra exatamente qual falha você teve. Toda response com falha do Proxy Finder carrega um attemptReport. defense conta respostas onde uma verificação de bot foi reconhecida, noResponse conta saídas que nunca chegaram ao site e contentRejected conta páginas que retornaram HTTP 200 sem verificação de bot e foram descartadas apenas pela sua regra de conteúdo. Para um coletor de supermercados, essa última contagem significa algo específico: o site respondeu, mas não para a sua loja. Mais saídas não vão resolver isso. O guia de relatórios de tentativas cobre as outras contagens.
Mantenha o Comprador Fixo, ou Meça a Variação
As descobertas do Instacart adicionam uma segunda variável, e existem duas maneiras honestas de lidar com isso.
Para um painel de preços, mantenha a coleta de cada loja em uma única identidade. Repita a saída que funcionou (r["proxy"], um ID opaco) via Single com o mesmo cookie, e armazene esse ID junto com o header de response X-FourA-Request-Id em cada linha. Quando um preço saltar, você saberá diferenciar uma alteração na loja de uma mudança de sessão.
Para pesquisa de preços, faça o oposto de propósito. Colete amostras do mesmo SKU na mesma loja por meio de várias sessões independentes e mantenha a distribuição, não apenas a primeira resposta. Um painel que relata um único número onde os compradores veem cinco não é preciso. É pura sorte.
Resultados
Pense em uma rede regional monitorando 120 lojas concorrentes em 2.500 SKUs, atualizados diariamente (cenário ilustrativo baseado em referências do setor). São 300.000 leituras de página por dia, e em qualquer noite algumas delas retornarão para a loja errada: o formato de um cookie mudou, uma loja fechou, um site começou a priorizar a localização por IP em vez do cookie.
- Páginas da loja errada falham na coleta. Elas nunca viram linhas, portanto uma variação de preço no painel é uma variação naquela loja específica.
- As falhas chegam categorizadas. Uma taxa alta de
contentRejectedvai para quem gerencia a seleção de lojas,defensealto é um problema de acesso,noResponsealto são saídas. Três responsáveis, três correções, e ninguém perde a manhã tentando adivinhar a causa. - Cada linha é rastreável. Um ID de saída e um ID de request por observação transformam a dúvida "esse pico é real?" em uma simples consulta.
- A variação se torna um número real. Para os SKUs amostrados entre sessões, você pode reportar o intervalo que os compradores realmente encontram, em vez de apenas uma leitura isolada.
Onde isso atinge o limite: preços para membros e programas de fidelidade ficam protegidos por contas, e experimentos vinculados a um usuário logado não aparecem em sessões anônimas. Coletar esses dados é uma questão de termos de serviço antes de ser um desafio de engenharia. Além disso, o identificador da loja depende da sua precisão ao escolhê-lo. Obtenha-o direto do código-fonte da página, não de memória, e valide-o novamente sempre que a rede alterar o layout.
Conclusão
O preço de um produto de supermercado costumava ser um dado fixo sobre o item. Hoje, é um dado sobre o produto, a loja e o comprador. Um coletor que registra apenas o primeiro gera ruído em um schema muito bem organizado.
Se a precificação individual continuar se expandindo, a pergunta dos compradores de dados de supermercado mudará de "quanto custa?" para "quanto custa aqui e qual é a variação?" Portanto, os coletores confiáveis não serão os que têm mais saídas. Serão aqueles cujas requests conseguem apontar exatamente a qual loja pertencem, com comprovação.