In this Article
Não conseguiu obter uma caixa Labubu? Isso não é nenhuma surpresa: as figuras de edição limitada são agora alvo de fãs, colecionadores e revendedores, e a compra online é muitas vezes a única maneira. Nessas circunstâncias, é quase impossível comprar uma figura manualmente, e um bot especial é a resposta. Este guia discute todas as armadilhas de comprar Labubu com um bot e fornece uma solução pronta.
Por que usar o bot Labubu não é negociável?
Labubu, um monstro de pelúcia, tornou-se popular em 2019 após o início da colaboração entre seu criador, Kashing Lung, e Pop Mart. O varejista chinês é um fabricante exclusivo, oferecendo o Labubu principalmente em caixas cegas. Além disso, as caixas são agrupadas em linhas temáticas, incluindo colaborações de edição limitada com outras marcas, e as linhas geralmente apresentam uma figura “secreta” rara que não foi anunciada. Adicione o fato de que as quedas do Pop Mart não acontecem em um horário fixo – em vez disso, os fãs precisam rastrear padrões e estar constantemente atentos. Isso cria uma onda selvagem e comprar um brinquedo se torna uma briga. Isso não é apenas uma figura de linguagem – Pop Mart parou de vender caixas Labubu em algumas de suas lojas off-line devido a incidentes com clientes que levaram a ferimentos físicos. Embora as compras online sejam muito mais seguras, elas ainda exigem velocidade e precisão, e até mesmo pequenos erros, como clicar acidentalmente no link errado, podem fazer com que você não tenha nenhum brinquedo.
O bot especial
, por outro lado, evita muitos problemas:
- Monitora as novidades, eliminando a necessidade de verificar manualmente se o brinquedo está em estoque;
- Automatiza o processo de compra – basta finalizar a compra;
- Conclui ações rapidamente – e a velocidade é o fator mais crucial na compra de Labubu;
- Elimina a possibilidade de erros humanos, como pressionar acidentalmente o botão errado.
É justo usar um bot?
Botting não é proibido; no entanto, você deve seguir
Termos de serviço de Pop Mart e não implementar práticas ilegais. Além disso, você não deve usar bots para obter dados confidenciais ou danificar o site. DataImpulse incentiva você apenas a agir de forma ética e a não assumir responsabilidade por quaisquer atividades ilegais.
Então, vamos prepará-lo para o próximo lançamento.
Construindo um bot Labubu usando Python
Antes de começar a codificar, você precisa prestar atenção aos principais fatores que determinam o sucesso do seu bot:
- Projetando uma lógica;
- Tratamento de prompts de verificação, pop-ups e limitações baseadas em localização;
- Imitando o comportamento humano real – definir intervalos entre solicitações, etc.;
- Escolha de ferramentas adicionais;
- Revisar e atualizar um bot, pois Pop Mart apresenta regularmente novas atualizações e seu bot deve ser capaz de lidar com elas.
Resolveremos esses problemas passo a passo.
Introdução
Visita
- o site oficial Python e baixe a versão (ou atualização) mais recente. Durante a instalação, certifique-se de adicionar Python ao seu PATH, para que possa executá-lo através do terminal.
- Execute os seguintes comandos para instalar as bibliotecas necessárias:
pip install playwright httpx python-dotenv
Ele instalará pacotes 3 Python:
- Playwright – ferramenta de automação de navegador;
- httpx – cliente HTTP para Python; suporta HTTP/1.1 & HTTP/2, solicitações assíncronas, proxies, etc;
- python-dotenv – carrega variáveis de ambiente de um .env e é adequado para armazenar detalhes confidenciais (como senhas e tokens) fora do seu código.
- Use este comando para fazer download dos binários do navegador:
playwright install
Crie um bot Telegram e um canal
Precisamos de um bot Telegram para receber notificações quando uma nova versão estiver disponível. Dessa forma, você pode se manter ocupado com sua vida e não perder uma gota.
Aqui são instruções sobre como fazer isso e obter uma chave API.
Em seguida, você precisa criar um canal público e adicionar seu bot como administrador.
Desenvolvendo um bot
Geralmente, a estrutura do bot é assim:
labububot/
├─ main.py
├─ runner.py
├─config.py
├─ scraping.py
├─ telegram_utils.py
├─ estado.py
├─ labubu_state.json
├─ .env
Vamos explicar para que precisamos de cada peça.
runner.py orquestra a lógica do bot. Ele é executado em um loop contínuo em um intervalo definido. Este trecho de código carrega o estado atual, coleta informações do produto, verifica a disponibilidade, envia notificações Telegram e salva as atualizações no arquivo labubu_state.json
Arquivo , que é criado automaticamente.
import asyncio
from playwright.async_api import async_playwright
from state import load_state, save_state
from scraping import gather_products_once
from telegram_utils import render_message, send_telegram, now_iso
from config import INTERVAL_SECONDS
async def run():
state = load_state()
async with async_playwright() as pw:
print("[START] Labubu stock watcher started.")
while True:
try:
items = await gather_products_once(pw)
for it in items:
url = it["url"]
prev = state.get(url, {}).get("in_stock")
state[url] = {"in_stock": it["in_stock"], "name": it["name"], "price": it["price"]}
if it["in_stock"] and prev is not True:
msg = render_message(it)
await send_telegram(msg)
save_state(state)
print(f"[OK] Cycle finished: {len(items)} item(s). {now_iso()}")
except Exception as e:
print(f"[FATAL] {e}")
await asyncio.sleep(INTERVAL_SECONDS)
config.py centraliza todas as constantes e configurações dependentes. Ele define quais páginas Pop Mart verificar, define onde armazenar dados e baixa informações confidenciais, como detalhes de proxy e a chave API do bot Telegram, de um
Arquivo .env .
import os
from pathlib import Path
from dotenv import load_dotenv
SEARCH_PAGES = [
"https://www.popmart.com/us/search/LABUBU",
"https://www.popmart.com/us/new-arrivals",
"https://www.popmart.com/us/collection/11/the-monsters",
]
load_dotenv()
INTERVAL_SECONDS = int(os.getenv("INTERVAL_SECONDS", "120"))
TELEGRAM_BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
TELEGRAM_CHAT_ID = os.getenv("TELEGRAM_CHAT_ID")
PROXY_SERVER = os.getenv("PROXY_SERVER")
PROXY_USERNAME = os.getenv("PROXY_USERNAME")
PROXY_PASSWORD = os.getenv("PROXY_PASSWORD")
HEADLESS = os.getenv("HEADLESS", "1") != "0"
STATE_FILE = Path("labubu_state.json")
.env armazena dados confidenciais. Armazenar esses detalhes em um arquivo separado, em vez de codificá-los, melhora seu nível de segurança e facilita a alteração de senhas ou qualquer outra coisa, se necessário. Esse arquivo também define em qual modo (sem cabeça ou não) o navegador é executado e configura o intervalo de extração. Lembre-se de inserir suas credenciais e dados reais. Você pode copie suas credenciais DataImpulse na aba do plano escolhido.
TELEGRAM_BOT_TOKEN=your_token
TELEGRAM_CHAT_ID=@name
INTERVAL_SECONDS=90
PROXY_SERVER=proxy_server
PROXY_USERNAME=proxy_login
PROXY_PASSWORD=proxy_password
HEADLESS=1
scraping.py está no centro da raspagem. Ele usa Playwright para monitorar a disponibilidade do produto em páginas Pop Mart definidas, extrair informações de destino e analisar dados estruturados em um .json .
import re
from urllib.parse import urljoin
from playwright.async_api import async_playwright
from config import SEARCH_PAGES, PROXY_SERVER, PROXY_USERNAME, PROXY_PASSWORD, HEADLESS
async def extract_products_from_search(page) -> list[dict]:
products, seen = [], set()
anchors = await page.locator('a[href*="/products/"]').all()
for a in anchors:
href = await a.get_attribute("href")
if not href or "/products/" not in href:
continue
url = urljoin(page.url, href)
if url in seen:
continue
name = (await a.text_content() or "").strip()
if not name or len(name) < 3:
try:
name = (await a.locator("..").text_content() or "").strip()
except Exception:
pass
if "labubu" in (name or "").lower() or "labubu" in url.lower() or "the-monsters" in url.lower():
products.append({"name": name, "url": url})
seen.add(url)
return products
async def parse_ld_json(page):
try:
content = await page.locator('script[type="application/ld+json"]').nth(0).text_content()
import json as _json
data = _json.loads(content)
if isinstance(data, list):
for item in data:
if isinstance(item, dict) and "offers" in item:
offers = item["offers"]
if isinstance(offers, dict):
return {
"availability": offers.get("availability"),
"price": offers.get("price"),
"priceCurrency": offers.get("priceCurrency"),
}
elif isinstance(data, dict) and "offers" in data:
offers = data["offers"]
return {
"availability": offers.get("availability"),
"price": offers.get("price"),
"priceCurrency": offers.get("priceCurrency"),
}
except Exception:
pass
return {}
async def check_product_stock(page, url: str) -> dict:
await page.goto(url, wait_until="domcontentloaded")
await page.wait_for_timeout(1200)
title = (await page.title()) or ""
title = title.replace(" - POP MART", "").strip()
meta = await parse_ld_json(page)
availability = (meta.get("availability") or "") if meta else ""
price = meta.get("price") if meta else None
if not price:
try:
price_text = await page.locator('[class*="price"], .price, [data-test*="price"]').first.text_content()
if price_text:
price_clean = re.sub(r"[^\d\.,]", "", price_text)
price = price_clean if price_clean else None
except Exception:
pass
in_stock = None
try:
if await page.locator("text=ADD TO BAG").count():
in_stock = True
elif await page.locator("text=SOLD OUT").count():
in_stock = False
except Exception:
pass
if in_stock is None and availability:
in_stock = "InStock" in availability or "instock" in availability.lower()
if in_stock is None:
try:
btn_texts = [t.lower() for t in await page.locator("button, div[role=button]").all_text_contents()]
joined = " | ".join(btn_texts)
if "add to bag" in joined or "add to cart" in joined:
in_stock = True
elif "sold out" in joined or "out of stock" in joined:
in_stock = False
except Exception:
pass
return {
"url": url,
"name": title or "LABUBU",
"price": price,
"in_stock": bool(in_stock),
}
async def gather_products_once(pw) -> list[dict]:
browser = await pw.chromium.launch(headless=HEADLESS)
context_args = {}
if PROXY_SERVER:
context_args["proxy"] = {"server": PROXY_SERVER, "username":PROXY_USERNAME, "password":PROXY_PASSWORD}
context = await browser.new_context(**context_args)
page = await context.new_page()
pool = {}
for url in SEARCH_PAGES:
try:
await page.goto(url, wait_until="domcontentloaded")
await page.wait_for_timeout(1000)
await page.evaluate("window.scrollTo(0, document.body.scrollHeight)")
await page.wait_for_timeout(800)
prods = await extract_products_from_search(page)
for p in prods:
pool[p["url"]] = p
except Exception as e:
print(f"[WARN] Failed to open {url}: {e}")
results = []
for url in list(pool.keys()):
try:
res = await check_product_stock(page, url)
results.append(res)
except Exception as e:
print(f"[WARN] Failed to check {url}: {e}")
await context.close()
await browser.close()
return results
telegram_utils.py é responsável por enviar notificações Telegram quando o produto alvo estiver disponível.
import html
import httpx
from datetime import datetime, timezone
from config import TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID
def now_iso() -> str:
return datetime.now(timezone.utc).astimezone().isoformat(timespec="seconds")
async def send_telegram(text: str, disable_preview: bool = False) -> None:
if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID:
print("[WARN] TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID not set — message not sent.")
return
api_url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
payload = {
"chat_id": TELEGRAM_CHAT_ID,
"text": text,
"parse_mode": "HTML",
"disable_web_page_preview": disable_preview,
}
async with httpx.AsyncClient(timeout=20) as client:
r = await client.post(api_url, data=payload)
if r.status_code != 200:
print(f"[TG ERROR] {r.status_code}: {r.text}")
def render_message(item: dict) -> str:
title = html.escape(item.get("name") or "Labubu item")
price = item.get("price")
price_line = f"\n💵 Price: {price}" if price else ""
return (
f"🟢 LABUBU in stock\n"
f"{title}{price_line}\n"
f"🔗 {item['url']}\n"
f"🕒 {now_iso()}\n"
f"#Labubu #PopMart"
)
estado.py carrega e salva informações sobre o estado dos produtos em labubu_state.json
Arquivo .
import json
from config import STATE_FILE
def load_state() -> dict:
if STATE_FILE.exists():
try:
return json.loads(STATE_FILE.read_text("utf-8"))
except Exception:
return {}
return {}
def save_state(state: dict) -> None:
STATE_FILE.write_text(
json.dumps(state, ensure_ascii=False, indent=2),
encoding="utf-8"
)
main.py serve como ponto de entrada para todo o aplicativo. Assim como um botão “Ligar motor” dá partida em um carro, esse código dá partida em seu bot.
import asyncio
from runner import run
if __name__ == "__main__":
try:
asyncio.run(run())
except KeyboardInterrupt:
print("\n[STOP] Stopped by user.")
Para executar um arquivo (e iniciar um bot), digite este comando em um terminal:
python main.py
Ferramentas adicionais para um trabalho perfeito
Existem vários instrumentos que você pode implementar:
Estruturas de registro
- – rastreiam erros e monitoram a atividade geral do bot. É útil para depuração.
- Ferramentas de rastreamento de erros – capturam e relatam erros automaticamente em tempo real, permitindo que você resolva os problemas rapidamente.
- Serviços de monitoramento e alerta – controle o desempenho do bot e alerte sobre atividades incomuns ou tempo de inatividade.
- Isolamento de ambiente – os contêineres ajudam a criar ambientes isolados, simplificando assim a implantação.
Em nosso código, também usamos ferramentas como dotenv para proteger dados confidenciais, o que é especialmente importante hoje, com um número crescente de ataques e proxies. Os proxies são essenciais porque ajudam você a imitar o comportamento humano real, distribuindo seu tráfego por diferentes endereços IP. Eles também permitem que você use vários threads de conexão simultaneamente e aumentam suas chances de obter o Labubu. Em relação aos proxies, DataImpulse está pronto para ajudá-lo – envie-nos um email para [email protected] ou use o “Experimente agora” para começar conosco.
