Envie alertas de vagas com Claude e Apify

O que é e por que usar

Enviar alertas de vagas com Claude e Apify é montar um pipeline em que o Apify coleta anúncios de emprego de portais como LinkedIn, Indeed, Gupy ou InfoJobs, o Claude lê cada descrição, classifica o encaixe com o perfil do candidato e resume os pontos fortes e fracos — e o resultado chega no seu canal (Telegram, Slack, e-mail) minutos depois da publicação. Em vez de você abrir cinco abas todos os dias e reler dezenas de descrições genéricas, o sistema entrega apenas o que faz sentido, com justificativa.

O ganho é mensurável. Um profissional de tecnologia sênior que busca vagas remotas costuma gastar entre 40 e 60 minutos por dia filtrando anúncios manualmente. Com triagem automática, esse tempo cai para 5 a 10 minutos: você lê apenas as 3 a 5 vagas que passaram pelo filtro semântico, em vez das 40 que apareceram na busca. Além disso, a latência entre a publicação da vaga e o alerta cai de horas (quando você lembra de olhar) para minutos.

A combinação funciona bem porque cada peça faz o que faz melhor: o Apify resolve o problema chato de scraping em portais que mudam layout com frequência, oferecendo Actors prontos e mantidos; o Claude resolve o problema de interpretação, entendendo “vaga de dados com foco em engenharia, não em BI” ou “aceita PJ, mas exige presencial em São Paulo”. A orquestração fica no n8n, que dispara o fluxo em cron, trata duplicatas e entrega os alertas.

a sign on the side of a building that says avenue des champs elysees

Pré-requisitos

  • Conta no Apify com pelo menos um Actor de vagas salvo (o plano gratuito dá US$ 5 de crédito mensal, suficiente para ~1.000 resultados em testes).
  • Chave da API da Anthropic (Claude) — o modelo claude-sonnet-4-5 é o equilíbrio recomendado entre custo e qualidade para triagem de texto.
  • Instância do n8n (self-hosted ou cloud) rodando com acesso a HTTP Request e Cron.
  • Um canal de entrega: bot do Telegram, webhook do Slack ou SMTP configurado.
  • Conhecimento básico de JSON e de como passar variáveis entre nós do n8n.
  • Um “perfil de candidato” escrito em texto — cargo-alvo, senioridade, stack, modelo de trabalho aceito, faixa salarial mínima. Isso vira o prompt de sistema do Claude.

Exemplo Prático: triagem diária de vagas de Product Designer para uma designer freelancer em Florianópolis

Cenário: Marina é Product Designer freelancer, mora em Florianópolis, aceita apenas vagas remotas (ou híbridas em Floripa), com foco em produtos B2B SaaS, e recusa vagas que exijam “disponibilidade para viagens frequentes” ou que peçam “domínio de front-end”. Ela costuma buscar no LinkedIn por “Product Designer” e recebe 60 a 90 resultados por dia, dos quais talvez 4 interessem. Ela quer receber, todo dia às 8h, uma mensagem no Telegram com as vagas que passaram no filtro, ordenadas por aderência, cada uma com um resumo de 3 linhas e o motivo da recomendação.

O que será automatizado:

  1. Coleta diária no LinkedIn (via Actor curious_coder/linkedin-jobs-scraper) com a query “Product Designer remote Brazil”.
  2. Deduplicação contra um banco de vagas já vistas (Google Sheets ou Postgres no n8n).
  3. Chamada ao Claude com o perfil da Marina + descrição da vaga, retornando JSON estruturado com score (0–100), resumo, motivos e red_flags.
  4. Filtro de score ≥ 70.
  5. Envio no Telegram em uma única mensagem consolidada por dia.

Resultado esperado: Marina acorda com 3 a 6 vagas no Telegram, cada uma com resumo, motivo e alerta de red flag. O custo diário estimado é de US$ 0,02 a US$ 0,05 em tokens do Claude (60 vagas × ~800 tokens de entrada) e cerca de US$ 0,10 em créditos do Apify. Total mensal: abaixo de US$ 5.

Configuração Passo a Passo

1. Criar o Actor no Apify e testar a saída

No console do Apify, abra o Actor curious_coder/linkedin-jobs-scraper, clique em Try it e configure:

{
  "queries": ["Product Designer remote Brazil"],
  "location": "Brazil",
  "maxResults": 50,
  "publishedAt": "r86400"
}

Rode uma vez e inspecione o dataset. Cada item traz campos como title, companyName, descriptionText, postedAt, jobUrl, workplaceType. Guarde o Actor ID e o token de API (Account → Integrations).

2. Montar o fluxo no n8n — nó Cron

Adicione um nó Schedule Trigger com expressão cron 0 8 * * * (todo dia às 8h, fuso America/Sao_Paulo). Se preferir rodar a cada 6 horas para pegar vagas no mesmo dia, use 0 */6 * * *.

3. Nó HTTP Request — disparar o Actor

Tipo: HTTP Request. Método: POST. URL:

https://api.apify.com/v2/acts/curious_coder~linkedin-jobs-scraper/runs?token={{$env.APIFY_TOKEN}}

Body (JSON): o mesmo payload do passo 1. Ative Send Body e JSON. A resposta traz um data.id (run ID) — capture com {{$json.data.id}}.

4. Nó Wait + nó HTTP Request — buscar o dataset

Adicione um Wait de 90 segundos (o Actor costuma terminar em 30–60s para 50 resultados). Depois, outro HTTP Request:

GET https://api.apify.com/v2/actor-runs/{{$node["Apify Run"].json.data.id}}/dataset/items?token={{$env.APIFY_TOKEN}}&format=json

Isso retorna um array de vagas. Use um nó Split In Batches (batch size 1) para processar uma a uma e evitar estourar o contexto do Claude.

5. Deduplicação com Google Sheets

Antes do Claude, consulte a aba vagas_vistas por jobUrl. Se já existir, use um nó IF para descartar. Se não, siga em frente e adicione a URL à planilha depois do processamento. Alternativa mais robusta: nó Postgres com INSERT ... ON CONFLICT DO NOTHING.

6. Nó HTTP Request — chamar o Claude

Método POST, URL https://api.anthropic.com/v1/messages, headers:

{
  "x-api-key": "{{$env.ANTHROPIC_KEY}}",
  "anthropic-version": "2023-06-01",
  "content-type": "application/json"
}

Body:

{
  "model": "claude-sonnet-4-5",
  "max_tokens": 500,
  "system": "Você é um recrutador técnico. Avalie a vaga para o perfil abaixo e responda SOMENTE em JSON válido: {score: 0-100, resumo: string (max 3 linhas), motivos: string[], red_flags: string[]}. Perfil: Product Designer freelancer, Florianópolis, aceita remoto ou híbrido em Floripa, foco em B2B SaaS, recusa viagens frequentes e vagas que exijam front-end.",
  "messages": [
    {
      "role": "user",
      "content": "Título: {{$json.title}}\nEmpresa: {{$json.companyName}}\nModelo: {{$json.workplaceType}}\nDescrição:\n{{$json.descriptionText}}"
    }
  ]
}

Resposta esperada (campo content[0].text):

{
  "score": 82,
  "resumo": "Vaga de Product Designer em SaaS B2B de logística, 100% remota, stack Figma + pesquisa qualitativa.",
  "motivos": ["Remoto", "B2B SaaS", "Foco em discovery"],
  "red_flags": ["Pede disponibilidade para 1 viagem/trimestre"]
}

Use um nó Code para fazer JSON.parse($json.content[0].text) e mesclar com os campos da vaga.

7. Nó IF — filtrar score

Condição: {{$json.score}} >= 70. A saída true segue para o Telegram; a false vai para um NoOp (descarte).

8. Nó Telegram — enviar alerta consolidado

Use Aggregate antes para juntar todas as vagas aprovadas em um único item. Depois, nó Telegram → Send Message, chat ID da Marina, texto:

🔎 {{$json.count}} vagas aderentes hoje:

{{$json.items.map(v => `• ${v.title} @ ${v.companyName} (score ${v.score})\n${v.resumo}\n${v.jobUrl}`).join("\n\n")}}

9. Gravar no Sheets e fechar o ciclo

Após o envio, um nó Google Sheets → Append grava jobUrl, score, data na aba vagas_vistas, garantindo que amanhã essas vagas não voltem.

Dicas e Variações

  • Cache de prompt: ative cache_control no bloco de sistema do Claude se rodar mais de 20 vagas por execução — reduz o custo em até 90% nos tokens de entrada repetidos.
  • Múltiplas fontes: rode Actors do Indeed, Gupy e Trampos em paralelo (nós HTTP Request lado a lado) e una tudo com um Merge antes do Claude.
  • Score adaptativo: peça ao Claude também um campo categoria (“sonho”, “vale conversar”, “descartar”) e use isso para escolher o canal — sonho vai para Telegram + e-mail, vale conversar só Telegram.
  • Feedback loop: adicione um botão no Telegram (inline keyboard) para marcar “gostei/não gostei”. Grave em uma planilha e use como few-shot no prompt da semana seguinte.
  • Reduza custo do Apify: limite maxResults a 40 e use publishedAt: "r86400" (últimas 24h) — você paga por resultado, não por execução.
a white street sign sitting in front of a building

Erros Comuns e Como Evitá-los

  • Confiar no texto bruto do Claude: se você esquecer o JSON.parse no nó Code, o {{$json.content[0].text}} chega como string e o IF de score compara string com número. Sempre valide com JSON.parse dentro de try/catch.
  • Estourar o limite de tokens do Claude: descrições do LinkedIn chegam a 4.000 tokens. Trunque para 3.000 caracteres no nó Code antes de enviar (descriptionText.slice(0, 3000)) — o topo sempre traz o essencial.
  • Rodar sem deduplicação: sem a checagem por jobUrl, você recebe a mesma vaga todo dia e o alerta perde valor. Deduplicação é obrigatória, não opcional.
  • Actor do Apify quebrado: portais mudam layout. Monitore a taxa de descriptionText vazio — se passar de 20%, troque de Actor ou abra issue no mantenedor.
  • Rate limit do Telegram: 30 mensagens por segundo no mesmo chat. Agregue antes de enviar (nó Aggregate) em vez de disparar um Telegram por vaga.
  • Prompt de sistema vago: “avalie se é boa vaga” gera score inconsistente. Seja específico sobre modelo de trabalho, localização, senioridade e red flags explícitas.

Próximos Passos

Comece pequeno: rode o pipeline uma vez manualmente (nó Execute Workflow no n8n) com maxResults: 20 e apenas a query principal. Revise os scores do Claude contra sua própria avaliação em 10 vagas — se a correlação estiver abaixo de 70%, ajuste o prompt de sistema antes de ativar o Cron. Depois, ative o Schedule Trigger, adicione a segunda fonte (Indeed ou Gupy) e implemente o feedback loop no Telegram. Em uma semana você terá dados suficientes para calibrar o threshold de score (comece em 70, teste 60 e 80) e medir quantas vagas realmente viram conversa. Se quiser ir além, conecte o mesmo fluxo ao Notion para gerar um CRM pessoal de candidaturas, com status por vaga e data de follow-up automática.

Gostou do conteúdo? Inscreva-se para receber as novidades:

CATEGORIES:

rotinas

Tags:

Comments are closed