Pular para o conteúdo
MÓDULO 4.4

🔭 Passo a passo #2: vigia da web caçando oportunidades

Modelo local é ilimitado — então pode vigiar a web o dia inteiro sem medidor rodando. Aqui você monta um worker que lê fontes permitidas, deixa o LLM pontuar cada item como possível oportunidade de negócio e te entrega uma lista rankeada, com a fonte de cada uma — tudo dentro do ToS, nada de "scraping a qualquer custo".

6
Tópicos
~40
Minutos
Avançado
Nível
Prático
Tipo

Conteúdo detalhado

1

🎯 O objetivo

O alvo é um vigia que nunca dorme: um worker que lê fóruns, comunidades e feeds, identifica reclamações e desejos recorrentes — as "dores" — e te entrega uma lista do que pode virar produto, rankeada por potencial e com link para a origem. Em vez de você rolar Reddit por horas, o modelo local faz a leitura pesada e só te chama quando achou algo de verdade.

🆕 Novo aqui?

Uma "dor" é um problema que as pessoas reclamam repetidamente ("perco tempo fazendo X à mão", "nenhuma ferramenta resolve Y"). Quando a mesma dor aparece muitas vezes e ninguém resolve bem, isso é um sinal de oportunidade — a matéria-prima de um produto. O vigia existe pra capturar esses sinais em escala.

🔑 A ideia central

O vigia tem quatro responsabilidades, nesta ordem:

  • Coletar de fontes permitidas (RSS, JSON oficial, APIs) — sem violar regra de ninguém.
  • Pontuar cada item com o LLM: é dor real? que produto resolveria? nota de 0 a 10.
  • Ranquear e deduplicar, guardando a fonte de cada sinal pra você poder conferir.
  • Rodar sozinho a cada N minutos e só te avisar do que passou do corte.
Coleta
fonte permitida
Score
LLM 0–10
Ranking
com fonte
24/7
sem medidor
2

⚖️ Ética e regras (leia antes de coletar)

Antes de qualquer linha de código: vigiar a web não é raspar tudo a qualquer custo. Cada site tem termos de uso (ToS) e um arquivo robots.txt que dizem o que você pode acessar. Respeitar isso não é só "ser legal" — é o que mantém seu worker sustentável, fora de bloqueio e dentro da lei.

🚨 Box de alerta: as regras inegociáveis

  • Use a API/feed oficial quando existir. Reddit, YouTube, Stack Overflow, Hacker News e muitos fóruns expõem JSON/RSS oficial — prefira sempre isso a raspar HTML.
  • Respeite ToS e robots.txt. Se o termo proíbe coleta automatizada, não colete. Plataformas como o X/Twitter restringem fortemente — não force.
  • Faça rate limit. Espace as requisições (ex.: 1 a cada 2–5 s), nunca martele o servidor. Identifique-se com um User-Agent real e contato.
  • Nada de dados pessoais nem login de terceiros. Colete só conteúdo público e agregue tendência — não persiga indivíduos.

✓ Coleta responsável

  • RSS/JSON oficial ou API com chave
  • User-Agent identificável + rate limit
  • Cache local pra não repuxar o mesmo
  • Só conteúdo público, guardando a fonte

✗ Coleta problemática

  • Burlar login, paywall ou captcha
  • Ignorar robots.txt / ToS
  • Disparar milhares de requisições/min
  • Coletar dados pessoais de indivíduos

💡 Dica prática

Comece pelo que é explicitamente oferecido: o Reddit serve JSON em qualquer página (basta acrescentar .json) e RSS (.rss); o Hacker News tem a Firebase API; muitos blogs e fóruns têm /feed. Com fontes oficiais você nunca fica na dúvida se está pisando na bola.

3

📥 Coleta da fonte permitida

Primeiro passo concreto: puxar itens de uma fonte oficial e normalizar tudo para um formato único — assim o resto do pipeline não precisa saber de onde veio. Vamos usar o JSON oficial do Reddit como exemplo, gravando uma linha por item (formato JSONL).

⌨️ Copy-run: coletar e normalizar

Objetivo: baixar os posts novos de um subreddit pela fonte oficial e gravar um item limpo por linha. Precisa de curl e jq.

# Identifique-se e respeite o rate limit (fonte oficial: .json do Reddit)
UA="vigia-local/1.0 (contato: voce@exemplo.com)"
# Puxa os 25 posts mais novos e normaliza para 1 JSON por linha
curl -s -A "$UA" \
  "https://www.reddit.com/r/SaaS/new.json?limit=25" \
  | jq -c '.data.children[].data
      | {fonte:"reddit/r/SaaS", id, titulo:.title,
         texto:.selftext, url:("https://reddit.com"+.permalink)}' \
  > coletado.jsonl
# Educado: aguarde antes da próxima fonte
sleep 3

Como verificar: rode wc -l coletado.jsonl (deve mostrar ~25) e head -1 coletado.jsonl | jq — cada linha tem titulo, texto e url de origem.

💡 Dica prática

Normalizar é o segredo de poder somar fontes sem reescrever nada. Amanhã você troca a coleta por um feed RSS (/feed) ou pela API do Hacker News, mantendo as mesmas chaves (fonte, id, titulo, texto, url). O LLM e o ranking nem percebem a diferença.

4

🧠 Análise com o modelo local

Agora o coração: para cada item coletado, peça ao modelo local que classifique e devolva JSON estruturado. A chave é forçar saída em JSON (Ollama aceita format:"json") e usar temperatura baixa pra resposta consistente. Isso transforma texto solto em dados que o ranking entende.

⌨️ Copy-run: pontuar um item via API local

Objetivo: mandar um item para a API local (OpenAI-compatível, da Trilha 3) e receber {dor_real, dor, produto, score}.

# $TXT = título + texto de UM item coletado
TXT="Cansei de versionar prompt no Notion, perco os bons"
# Pede classificação ESTRUTURADA (JSON) ao modelo local
curl -s http://localhost:11434/v1/chat/completions \
  -d "$(jq -n --arg t "$TXT" '{
    model:"qwen2.5:7b-instruct", temperature:0.2, format:"json",
    messages:[
      {role:"system",
       content:"Você é analista de oportunidades. Responda SÓ JSON."},
      {role:"user", content:("Texto: "+$t+
       "\nFormato: {\"dor_real\":bool,\"dor\":\"\",
       \"produto\":\"\",\"score\":0-10}")}
    ]}')" \
  | jq -r '.choices[0].message.content'
# → {"dor_real":true,"dor":"versionar prompts","produto":"Git p/ prompts","score":8}

Como verificar: a saída tem que ser um JSON válido com score entre 0 e 10. Se vier texto solto, reforce no prompt "responda SÓ JSON" e confirme que passou format:"json".

dor_real
true/false
dor
resumo do problema
produto
o que resolveria
score
0–10 potencial

💡 Dica prática

Peça também um campo justificativa curta: além de melhorar a nota (o modelo "pensa" antes), te dá uma linha pra ler no relatório sem reabrir a fonte. E dê exemplos no system prompt do que é nota 2 vs nota 9 — calibra o score muito mais que ajustar a temperatura.

5

📊 Ranqueando e guardando

Com cada item pontuado, o worker vira um curador: ordena por score, joga fora o que repetiu, corta o que ficou abaixo do limiar e grava só o que vale, sempre com o link da fonte. A disciplina aqui é o que separa um relatório útil de uma enxurrada de ruído.

1

Ordenar por score

Maior potencial no topo. sort_by(-.score) resolve em uma linha de jq.

2

Deduplicar

A mesma dor aparece em vários posts. unique_by(.id) e, idealmente, juntar itens com dor parecida.

3

Cortar abaixo do limiar

Mantenha só dor_real == true e score >= 7. O corte é seu botão de sinal/ruído.

4

Gravar com citação

Cada oportunidade carrega a url de origem — sem fonte, é palpite, não sinal.

📄 O arquivo de saída: oportunidades.md

Objetivo: um markdown legível, rankeado, que você abre de manhã e bate o olho. Cada item com dor, produto e fonte.

# Oportunidades — 2026-06-29
 
## (score 9) Versionar prompts é um caos
- **Dor:** times perdem prompts bons em chats e docs soltos.
- **Produto:** "Git para prompts" com diff e rollback.
- **Fonte:** https://reddit.com/r/SaaS/comments/abc123
 
## (score 8) Onboarding de cliente é manual demais
- **Dor:** founders refazem o mesmo passo a passo à mão.
- **Produto:** checklist de onboarding automatizado.
- **Fonte:** https://reddit.com/r/Entrepreneur/comments/def456

Como verificar: abra o oportunidades.md e clique numa fonte — ela tem que levar exatamente ao post que gerou o sinal. Sem isso, você não consegue validar nem citar.

✓ Notificar

  • Passou do corte e é novo (não estava no relatório de ontem)
  • Dor recorrente em mais de uma fonte
  • Tem fonte clicável pra você validar

✗ Silenciar (ruído)

  • Score abaixo do limiar ou dor_real:false
  • Duplicata de algo já reportado
  • Desabafo sem produto possível por trás
6

🔁 Rodando contínuo

Junte as três etapas — coleta, pontuação, ranking — num só script e agende com cron (Trilha 4.2). O pipeline completo flui da esquerda para a direita: as fontes alimentam a coleta, o LLM local pontua, o ranking filtra e a saída é seu relatório do dia.

Fontes RSS · API oficial Coleta normaliza LLM local score 0–10 Ranking dedup + corte oportunidades .md rankeado ⟳ cron: repete a cada N minutos, sem custo por chamada

Leia da esquerda para a direita: o fluxo (em âmbar) sai das fontes permitidas, passa por três estágios de processamento (em ciano) e termina no relatório do dia. O cron embaixo fecha o ciclo — por ser local, repetir o dia todo só custa eletricidade.

⌨️ Copy-run principal: vigia.sh

Objetivo: o pipeline inteiro num script — coleta, pontua com o modelo local, ranqueia e grava o markdown datado.

#!/usr/bin/env bash
set -euo pipefail
UA="vigia-local/1.0 (contato: voce@exemplo.com)"
HOJE=$(date +%F); SAIDA="oportunidades-$HOJE.md"
# 1) COLETA (fonte permitida)
curl -s -A "$UA" "https://www.reddit.com/r/SaaS/new.json?limit=25" \
  | jq -c '.data.children[].data | {id, titulo:.title,
    texto:.selftext, url:("https://reddit.com"+.permalink)}' > coletado.jsonl
# 2) PONTUA cada item com o modelo local (saída JSON)
> pontuado.jsonl
while IFS= read -r linha; do
  txt=$(jq -r '.titulo + " — " + (.texto // "")' <<< "$linha")
  resp=$(curl -s http://localhost:11434/v1/chat/completions \
    -d "$(jq -n --arg t "$txt" '{model:"qwen2.5:7b-instruct",
      temperature:0.2, format:"json", messages:[{role:"user",
      content:("SÓ JSON {\"dor_real\":bool,\"dor\":\"\",
      \"produto\":\"\",\"score\":0-10}: "+$t)}]}')" \
    | jq -r '.choices[0].message.content')
  jq -c --argjson c "$resp" '. + $c' <<< "$linha" >> pontuado.jsonl
  sleep 1
done < coletado.jsonl
# 3) RANQUEIA, deduplica e corta score < 7
jq -s 'unique_by(.id) | map(select(.dor_real and .score >= 7))
  | sort_by(-.score)' pontuado.jsonl > ranqueado.json
# 4) GRAVA markdown com citação de fonte
{ echo "# Oportunidades — $HOJE"; echo;
  jq -r '.[] | "## (score \(.score)) \(.dor)\n- **Produto:** \(.produto)\n- **Fonte:** \(.url)\n"' ranqueado.json;
} > "$SAIDA"
echo "Gravado: $SAIDA ($(jq length ranqueado.json) itens)"
# 5) AGENDA: a cada 30 min (crontab -e)
# */30 * * * * cd ~/vigia && /bin/bash vigia.sh >> vigia.log 2>&1

Como verificar: rode bash vigia.sh uma vez à mão — deve imprimir "Gravado:" e criar o oportunidades-AAAA-MM-DD.md. Só depois adicione a linha do cron. Acompanhe o vigia.log nas primeiras rodadas.

Auto-checagem (opcional): por que começar a coleta por uma fonte oficial (RSS/JSON/API), em vez de raspar o HTML a qualquer custo?

Coleta
curl + jq
Pontua
API local JSON
Ranqueia
dedup + corte
Agenda
cron N min

📌 Resumo do módulo

O vigia coleta, pontua, ranqueia e roda sozinho — texto solto vira lista de oportunidades com fonte.
Ética primeiro — APIs/RSS oficiais, ToS, robots.txt e rate limit. Nada de scraping a qualquer custo.
JSON estruturado é a cola — pedir score 0–10 em JSON deixa o ranking trivial.
Local destrava o 24/7 — repetir a cada N min só custa energia; cron fecha o ciclo.

Próximo módulo:

4.5 — Seu buddy local com nome, cara e voz