Monitor local para acompanhar anuncios publicos de cards Rayquaza na Liga Pokemon e no CardTrader. O projeto entra no detalhe de cada card, salva todas as ofertas em SQLite, destaca novidades e mostra progresso do scraper em tempo real via SSE.
Este projeto coleta apenas dados publicamente visiveis por navegacao normal.
- Nao burla captcha, login ou protecoes.
- Respeita delays configuraveis entre paginas e detalhes.
- Salva logs e screenshots quando algum card falha.
- Deve ser usado de forma responsavel e conforme os termos dos sites monitorados.
- Coleta cards Rayquaza nas URLs configuradas para Liga Pokemon e CardTrader.
- Entra na pagina de detalhe de cada card para buscar lojas, vendedores e ofertas.
- Salva cards, ofertas, execucoes e historico de preco em SQLite.
- Detecta novos anuncios por
is_newefirst_seen_run_id. - Prioriza cards novos na fila de scraping para encontrar novidades mais cedo.
- Atualiza a interface em tempo real durante a coleta via SSE.
- Mostra uma tela unica de
Anuncios, com filtroNovos anunciosmarcado por padrao. - Insere novos anuncios na interface sem esperar o monitor terminar.
- Converte precos para BRL com cache diario de cambio.
- Node.js
- TypeScript
- Playwright
- SQLite (
better-sqlite3) - Express
- Vite + React
- dotenv
- zod
- date-fns
- tsx
- concurrently
npm install
npm run playwright:installCrie um .env a partir de .env.example.
DATABASE_PATH=./storage/monitor.sqlite
HEADLESS=true
SLOW_MO=0
REQUEST_DELAY_MS=6000
LIGA_MAX_VER_MAIS_CLICKS=100
CARDTRADER_MAX_PAGES=200
MONITOR_STATUS_POLL_INTERVAL_MS=1500
DETAIL_CONCURRENCY=1
CARD_DETAIL_TIMEOUT_MS=45000
SCRAPER_FAST_MODE=false
PORT=3333
VITE_API_URL=
ENABLE_BACKGROUND_SCHEDULER=true
MONITOR_INTERVAL_MINUTES=10
RUN_ON_BOOT=true
ENABLE_REMOTE_ACCESS=true
REMOTE_ACCESS_MODE=cloudflare_tunnel
APP_PUBLIC_URL=
API_PUBLIC_URL=
CLOUDFLARED_BIN=cloudflared
CLOUDFLARE_TUNNEL_TARGET=http://localhost:3333
CLOUDFLARE_TUNNEL_HOSTNAME=
NTFY_ENABLED=false
NTFY_BASE_URL=https://ntfy.sh
NTFY_TOPIC=
NTFY_PRIORITY=default
TELEGRAM_ENABLED=false
TELEGRAM_BOT_TOKEN=
TELEGRAM_CHAT_ID=Use VITE_API_URL= vazio para producao local e Cloudflare Tunnel. Assim o frontend chama /api na mesma origem publica. No modo npm run dev, o Vite faz proxy de /api para http://localhost:3333.
npm run db:initCria o SQLite local, aplica o schema e migra colunas novas sem destruir dados antigos.
npm run monitorExecuta uma coleta unica. As ofertas novas sao persistidas imediatamente e aparecem na API/interface durante a execucao.
npm run dev- API Express:
http://localhost:3333 - Interface Vite/React:
http://localhost:5173
npm run build
npm run startOu:
npm run prod:serveEm producao local, o Express serve backend e frontend na mesma porta:
http://localhost:3333
Scripts auxiliares:
powershell -ExecutionPolicy Bypass -File scripts/run-local-prod.ps1
powershell -ExecutionPolicy Bypass -File scripts/run-local-prod.ps1 -UsePm2
npm run startup:installbash scripts/run-local-prod.sh
bash scripts/run-local-prod.sh --pm2No Windows, npm run startup:install cria uma tarefa no Agendador de Tarefas para iniciar a aplicacao em producao quando o usuario fizer login. A tarefa usa scripts/start-on-login.ps1, reaproveita o build existente e grava logs em storage/startup-task.log.
Para remover:
npm run startup:removeO backend possui scheduler interno.
ENABLE_BACKGROUND_SCHEDULER=trueliga o agendador.MONITOR_INTERVAL_MINUTES=10roda a cada 10 minutos por padrao.RUN_ON_BOOT=truedispara uma coleta ao subir a API.- O backend bloqueia execucoes simultaneas.
- O Dashboard mostra se o agendador esta ativo e a proxima execucao.
Controle via API:
GET /api/monitor/status
POST /api/monitor/run
POST /api/monitor/pause
POST /api/monitor/resumePara deixar rodando enquanto o PC estiver ligado:
npm run build
npm run pm2:startComandos:
npm run pm2:logs
npm run pm2:restart
npm run pm2:stopO processo PM2 se chama pokemon-rayquaza-monitor e usa ecosystem.config.js.
O projeto envia notificacoes quando um anuncio novo e salvo.
Provider recomendado:
NTFY_ENABLED=true
NTFY_BASE_URL=https://ntfy.sh
NTFY_TOPIC=seu-topico-secreto
NTFY_PRIORITY=defaultNo celular, instale o app ntfy e assine o mesmo topico. No desktop, voce pode usar o web app do ntfy ou o Telegram Desktop, se ativar Telegram.
Telegram opcional:
TELEGRAM_ENABLED=true
TELEGRAM_BOT_TOKEN=123456:ABC...
TELEGRAM_CHAT_ID=123456789Teste manual:
curl -X POST http://localhost:3333/api/notifications/testO Dashboard mostra ntfy/Telegram habilitado ou desabilitado e quantas notificacoes foram enviadas na ultima execucao.
Guia completo: docs/NOTIFICATIONS.md.
O caminho preferencial e Cloudflare Tunnel apontando para:
CLOUDFLARE_TUNNEL_TARGET=http://localhost:3333Teste rapido:
powershell -ExecutionPolicy Bypass -File scripts/setup-cloudflared.ps1 -RunQuickTunnelbash scripts/setup-cloudflared.sh --run-quick-tunnelPara dominio fixo, configure CLOUDFLARE_TUNNEL_HOSTNAME e APP_PUBLIC_URL no .env.
Guia completo: docs/CLOUDFLARE_TUNNEL.md.
Nao e necessario usar VM agora. O projeto ficou preparado para uma VM Linux futura com:
scripts/vm-bootstrap.shscripts/vm-update.sh- docs/ORACLE_VM_DEPLOY.md
Guia local/PM2: docs/LOCAL_ACCESS.md.
A antiga tela de "Novos Anuncios" virou Anuncios.
- A rota principal e
/offerse a alias amigavel e/anuncios. - A tela abre com
newOnly=trueeactiveOnly=true. - O checkbox
Novos anunciosvem marcado por padrao. - Ao desmarcar esse filtro, a tela passa a mostrar todos os anuncios ativos.
- Enquanto o monitor roda, os novos anuncios entram no topo da tabela em tempo real.
O backend expoe:
GET /api/monitor/statusGET /api/monitor/eventsPOST /api/monitor/runPOST /api/monitor/pausePOST /api/monitor/resumeGET /api/notifications/statusPOST /api/notifications/test
O frontend usa Server-Sent Events (SSE) para atualizar:
- etapa atual do monitor
- fonte atual
- card atual
- cards processados
- ofertas encontradas
- novos anuncios encontrados
- status do agendador e proxima execucao
- lista compacta de "Novos cadastrados agora"
Se a conexao SSE cair, a interface faz fallback para polling leve.
first_seen_atguarda quando a oferta apareceu pela primeira vez.first_seen_run_idguarda em qual execucao ela nasceu.is_newe marcado para ofertas vistas pela primeira vez na execucao mais recente.- Mudanca de preco nao cria nova oferta: atualiza
last_price_centse adiciona item emprice_history. - Ofertas que somem nao sao removidas na hora.
missing_countaumenta a cada execucao em que a oferta nao aparece.is_activeso virafalsedepois de 3 execucoes consecutivas sem aparecer.
language_rawecondition_rawsempre preservam o texto original do DOM.- O projeto normaliza idiomas para codigos internos como
PORTUGUESE,ENGLISH,JAPANESE,SPANISH,ITALIAN,FRENCHeGERMAN. - O projeto normaliza estados para
M,NM,EX,SP,MP,PL,POeUNKNOWN.
DETAIL_CONCURRENCY=1e o padrao seguro.- Pode subir para
2ou3quando quiser acelerar com cuidado. REQUEST_DELAY_MS=6000mantem uma pausa maior entre detalhes para reduzir risco de rate limit.CARD_DETAIL_TIMEOUT_MSimpede que um card lento trave a execucao inteira.SCRAPER_FAST_MODE=truereduz delays, mas ainda mantem uma navegacao responsavel.- Cards novos entram primeiro na fila para a interface mostrar novidades mais cedo.
src/
api/ # rotas Express
app/ # interface React (Vite)
config/ # variaveis de ambiente
db/ # schema, migracoes e repositorios
domain/ # tipos compartilhados
normalizers/ # idioma, estado, texto, preco e chaves canonicas
services/ # monitor, diff, run, progresso em tempo real
sources/ # scrapers por fonte
scripts/ # db:init, monitor
storage/ # SQLite, screenshots e cache de cambio
docs/ # documentacao adicional
Endpoints principais:
GET /api/dashboardGET /api/healthGET /api/cardsGET /api/cards/:idGET /api/cards/:id/offersGET /api/offersGET /api/offers/newGET /api/offers/recent-newGET /api/monitor/statusGET /api/monitor/eventsGET /api/runsPOST /api/monitor/runPOST /api/monitor/pausePOST /api/monitor/resume
Mais detalhes em docs/API.md.
- Se a coleta vier vazia, confira o terminal e a pasta
storage/screenshots/. - Se algum site mudar o DOM, ajuste
selectors.tsemapper.tsda fonte correspondente. - Se o Chromium ainda nao estiver instalado, rode
npm run playwright:install. - Se a interface nao atualizar em tempo real, confira
GET /api/monitor/events. - Se quiser reduzir a carga no site, mantenha
DETAIL_CONCURRENCY=1eSCRAPER_FAST_MODE=false. - Se um site bloquear a navegacao automatizada, o monitor registra o erro, salva screenshot e continua nas outras fontes.
Leia CONTRIBUTING.md antes de abrir PRs ou alterar scrapers.