Building a Labubu bot s tep-by-step tutorial

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

  1. 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. 
  2. 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. 
  1. 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.

Share article: