Skip to content

hendrixfreire/linkedin-job-scraper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

11 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

LinkedIn Job Scraper

Scraper em Python para a API pΓΊblica Guest do LinkedIn que busca vagas de emprego, elimina duplicatas entre execuΓ§Γ΅es, e prepara um arquivo JSON para um agente LLM classificar e reportar.

Feito pra rodar em cron sem nenhuma infraestrutura β€” sem banco de dados, sem autenticaΓ§Γ£o, sem login no LinkedIn. Apenas arquivos em disco.

Funcionalidades

  • Sem autenticaΓ§Γ£o β€” usa a API pΓΊblica Guest do LinkedIn (scraping de HTML)
  • DeduplicaΓ§Γ£o tripla:
    1. IDs persistentes das vagas (seen.json)
    2. Chaves normalizadas tΓ­tulo + empresa (pega vagas repostadas com ID novo)
    3. LΓͺ os outputs anteriores do agente e pula vagas jΓ‘ reportadas
  • Scoring heurΓ­stico β€” prΓ©-calcula uma nota de 1-5 estrelas por vaga pra que o LLM sΓ³ reavalie casos borderline (~80% de economia de tokens)
  • CV Tailoring β€” tailor_cv.py adapta seu CV pra cada vaga. Com LLM_API_KEY setada, usa IA pra gerar um CV polido e otimizado (igual ao fluxo de produΓ§Γ£o). Sem chave, faz anΓ‘lise de keywords gratuita.
  • Tracking de yield por keyword β€” remove automaticamente keywords que nΓ£o produzem nada apΓ³s 15+ execuΓ§Γ΅es
  • Buscas paralelas com rate limiting β€” 3 threads, 300ms entre pΓ‘ginas, deadline de 4 minutos
  • Filtro por localizaΓ§Γ£o e senioridade β€” apenas Brasil/SΓ£o Paulo, remove jΓΊnior/estΓ‘gio
  • Dashboard de mΓ©tricas β€” vΓͺ yield por keyword, execuΓ§Γ΅es recentes, tamanho da base
  • Skill de setup guiado β€” entrevista o usuΓ‘rio e configura tudo automaticamente

Requisitos

  • Python 3.8+
  • Nenhuma dependΓͺncia externa (apenas stdlib)
  • Hermes Agent (opcional, mas recomendado pra automaΓ§Γ£o via cron e classificaΓ§Γ£o com LLM)

Guia Completo: Do Zero ao Cron Rodando

Este guia te leva do zero atΓ© um cron job rodando 3x ao dia que busca vagas no LinkedIn, classifica com LLM, e te manda no Telegram. SΓ£o 6 passos.

Passo 1 β€” Instalar o Hermes Agent

O Hermes Agent Γ© o orquestrador que vai rodar o scraper em cron e classificar as vagas com LLM.

Linux / macOS / WSL2 / Android (Termux):

curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash

Windows (PowerShell):

iex (irm https://hermes-agent.nousresearch.com/install.ps1)

O instalador cuida de tudo: Python, Node.js, ripgrep, ffmpeg, clone do repo, virtualenv e o comando global hermes.

Depois de instalar, configure um provider de LLM:

# Caminho fΓ‘cil: Nous Portal (OAuth, sem chaves de API)
hermes setup --portal

# OU caminho completo (traga suas prΓ³prias chaves)
hermes model

Mais detalhes na documentaΓ§Γ£o oficial do Hermes.

Passo 2 β€” Conectar o Telegram

Pra receber as vagas no Telegram, vocΓͺ precisa criar um bot e conectΓ‘-lo ao Hermes.

2.1 Criar o bot com o BotFather

  1. Abra o Telegram e procure por @BotFather (ou acesse t.me/BotFather)
  2. Envie /newbot
  3. Escolha um nome de exibiΓ§Γ£o (ex: "Meu Scraper de Vagas")
  4. Escolha um username ΓΊnico terminado em bot (ex: meu_scraper_vagas_bot)
  5. O BotFather responde com seu token de API, no formato:
    123456789:ABCdefGHIjklMNOpqrSTUvwxYZ
    
    Guarde este token β€” vocΓͺ vai usar no prΓ³ximo passo.

2.2 Descobrir seu User ID

  1. No Telegram, procure por @userinfobot (ou acesse t.me/userinfobot)
  2. Envie qualquer mensagem
  3. Ele responde com seu User ID (um nΓΊmero como 123456789) Guarde este ID β€” vocΓͺ vai usar para autorizar o bot a falar com vocΓͺ.

2.3 Conectar ao Hermes

Rode o wizard interativo:

hermes gateway setup

Selecione Telegram quando perguntado. O wizard vai pedir:

  • Bot Token: o token do passo 2.1
  • Allowed Users: seu User ID do passo 2.2

Ele escreve a configuraΓ§Γ£o em ~/.hermes/.env automaticamente.

2.4 Iniciar o gateway

hermes gateway

O bot deve ficar online em segundos. Mande uma mensagem no Telegram pro seu bot pra confirmar que ele responde.

πŸ’‘ Pra rodar o gateway em background permanentemente, veja o guia de messaging do Hermes.

Passo 3 β€” Baixar o script e a skill

Clone este repositΓ³rio:

git clone https://github.com/hendrixfreire/linkedin-job-scraper.git
cd linkedin-job-scraper

Agora copie a skill de setup pro diretΓ³rio de skills do Hermes:

# Criar o diretΓ³rio de skills se nΓ£o existir
mkdir -p ~/.hermes/skills

# Copiar a skill linkedin-job-setup
cp -r skills/linkedin-job-setup ~/.hermes/skills/

# Confirmar que copiou
ls ~/.hermes/skills/linkedin-job-setup/SKILL.md

A skill linkedin-job-setup Γ© uma entrevista guiada que coleta suas preferΓͺncias (cargo, senioridade, stack, localizaΓ§Γ£o, keywords) e configura o script automaticamente.

Passo 4 β€” Rodar a entrevista de configuraΓ§Γ£o (grill)

Abra um chat com seu bot no Telegram (ou rode hermes no terminal) e digite:

carregue a skill linkedin-job-setup e configure meu scraper de vagas

O agente vai te entrevistar com perguntas uma de cada vez:

  1. Nome β€” qual nome usar no cabeΓ§alho do arquivo de vagas
  2. Área principal β€” Data Engineer, Data Analyst, BI Manager, AI/ML, etc.
  3. Senioridade alvo β€” SΓͺnior, Manager, Director, etc.
  4. Excluir jΓΊnior/pleno? β€” sim/nΓ£o
  5. Stack de alta relevΓ’ncia β€” tecnologias e cargos que sΓ£o match perfeito
  6. Stack de mΓ©dia relevΓ’ncia β€” stack adjacente que vocΓͺ domina parcialmente
  7. Modalidades aceitas β€” remoto, hΓ­brido, presencial
  8. LocalizaΓ§Γ£o β€” Brasil remoto, SΓ£o Paulo, outra cidade
  9. Keywords customizadas β€” revisar/editar a lista gerada
  10. FrequΓͺncia do cron β€” 3x/dia, 2x/dia, 1x/dia

Pra cada pergunta, o agente mostra uma resposta recomendada em itΓ‘lico. Se vocΓͺ concordar, Γ© sΓ³ confirmar. Se quiser mudar, digite sua resposta.

Dica: se quiser acelerar, diga "faz tudo e manda pra validar" β€” o agente aplica todas as recomendaΓ§Γ΅es padrΓ£o de uma vez e te mostra o resultado.

Passo 5 β€” Script configurado e cron job criado

Depois da entrevista, o agente:

  1. Edita o linkedin_jobs.py com suas configuraΓ§Γ΅es:
    • Lista KEYWORDS personalizada
    • high_skills e mid_skills no heuristic_score() baseado na sua stack
    • Filtros de localizaΓ§Γ£o (build_searches) e modalidade (fetch_one)
    • USER_NAME no header do MD
  2. Cria o cron job no Hermes com:
    • Schedule escolhido (padrΓ£o: 0 8,13,18 * * * = 3x/dia Γ s 8h, 13h, 18h)
    • Prompt do agente classificador
    • Entrega no Telegram (deliver: origin)
  3. Roda o script uma vez pra validar
  4. Mostra o dashboard de mΓ©tricas pra confirmar que tudo funcionou

Passo 6 β€” Testes iniciais

ApΓ³s a configuraΓ§Γ£o, vocΓͺ deve ver no Telegram uma mensagem do bot com a primeira leva de vagas classificadas. Formato esperado:

πŸ” 7 vagas novas β€” 20/06/2026 15:00

1. ⭐⭐⭐⭐⭐ πŸ”₯ Senior Data Engineer
Empresa | SΓ£o Paulo, SP | Remoto
πŸ“… Postada hoje | Match: stack BigQuery + Python bate direto
[Ver vaga](https://www.linkedin.com/jobs/view/...)

2. ⭐⭐⭐⭐ Data Tech Lead
...

Se nΓ£o chegou nada em 10 minutos:

# Verificar o cron
hermes cron list

# Rodar manualmente
python3 ~/linkedin-job-scraper/linkedin_jobs.py

# Ver o JSON gerado
cat ~/linkedin-jobs/jobs_new.json

# Ver mΓ©tricas
python3 ~/linkedin-job-scraper/linkedin_metrics.py

Pronto! A partir daqui o cron roda sozinho 3x ao dia. VocΓͺ sΓ³ precisa ler o Telegram.

ConfiguraΓ§Γ£o Manual (sem skill)

Se prefere configurar manualmente sem usar a skill, tudo Γ© via variΓ‘veis de ambiente:

VariΓ‘vel PadrΓ£o DescriΓ§Γ£o
LINKEDIN_OUTPUT_DIR ~/linkedin-jobs Onde salvar os arquivos de saΓ­da
LINKEDIN_USER_NAME User Nome no cabeΓ§alho do jobs.md
LINKEDIN_CRON_OUTPUT_DIR (desativado) DiretΓ³rio com os .md de resposta do agente (ativa dedup entre runs)

Edite linkedin_jobs.py diretamente pra mudar keywords, filtros e heuristic_score.

Arquivos de SaΓ­da

Criados em LINKEDIN_OUTPUT_DIR (padrΓ£o: ~/linkedin-jobs/):

Arquivo DescriΓ§Γ£o
jobs_new.json Vagas novas pro agente classificar. Inclui heuristic_score e heuristic_reason. Array vazio [] quando nΓ£o hΓ‘ vagas.
jobs.md HistΓ³rico legΓ­vel. Append-only β€” nunca remove entradas.
seen.json Estado de dedup. ContΓ©m seen_ids (IDs numΓ©ricos) e seen_keys (strings tΓ­tulo||empresa).
keywords.json Tracking de yield por keyword.

Formato do jobs_new.json

[
  {
    "id": "4429960220",
    "title": "Senior AI Engineer",
    "company": "Emma of Torre.ai",
    "location": "Brazil",
    "work_mode": "Remote",
    "date_label": "1 hour ago",
    "url": "https://www.linkedin.com/jobs/view/4429960220",
    "description": "Responsibilities and more: We are hiring...",
    "heuristic_score": 5,
    "heuristic_reason": "high stack, senior+, remote/BR"
  }
]

Dashboard de MΓ©tricas

python3 linkedin_metrics.py

Exemplo:

============================================================
  LinkedIn Job Scraper β€” Dashboard de MΓ©tricas
  20/06/2026 15:00
============================================================

## Base de dados
  IDs rastreados: 313
  Chaves tΓ­tulo+empresa: 283
  Última atualização: 2026-06-20T15:01

## Yield por Keyword
  Keyword                         Runs  Yield     Última nova
  ------------------------------ ----- ------ ------------
  data engineer                      5    12 (2.4/run) 2026-06-20
  AI engineer                        5     8 (1.6/run) 2026-06-20
  BI manager                         5     0 (0 total) nunca

## ExecuΓ§Γ΅es recentes
        Data  Vagas Primeira vaga
  ------------ ------ ----------------------------------------
  2026-06-20 15-00      8 Senior Data Engineer
  Total de execuΓ§Γ΅es: 15

## Arquivo MD
  Vagas no MD: 313 (IDs ΓΊnicos: 313)
  Tamanho: 97KB, 3630 linhas

Filtros da API do LinkedIn

ReferΓͺncia pra customizar build_searches():

Filtro Valores DescriΓ§Γ£o
f_TPR r86400, r604800, r2592000 Tempo de publicaΓ§Γ£o: 24h, 7 dias, 30 dias
f_E 1-6 ExperiΓͺncia: 1=Intern, 2=Entry, 3=Associate, 4=Mid-Senior, 5=Director, 6=Executive
f_WT 1, 2, 3 Modalidade: 1=Presencial, 2=Remoto, 3=HΓ­brido
sortBy DD, R Ordenar por data decrescente, relevΓ’ncia
start 0, 25, 50, ... Offset de paginaΓ§Γ£o (25 por pΓ‘gina)

Como Funciona

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     SCRAPER (este repo)                      β”‚
β”‚                                                              β”‚
β”‚  1. Carrega seen.json (IDs + chaves)                        β”‚
β”‚  2. LΓͺ ΓΊltimos 3 outputs do agente (pula vagas reportadas)  β”‚
β”‚  3. Remove keywords improdutivas                            β”‚
β”‚  4. Busca na API Guest do LinkedIn (2 pΓ‘ginas Γ— N queries)  β”‚
β”‚  5. Dedup tripla: ID + tΓ­tulo/empresa + reportadas          β”‚
β”‚  6. Filtra: sΓ³ Brasil/SP, sem jΓΊnior                        β”‚
β”‚  7. Busca detalhes em paralelo (3 threads, mΓ‘x 8 vagas)     β”‚
β”‚  8. Salva: seen.json + keywords.json + jobs_new.json + jobs.md β”‚
β”‚                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                           β–Ό jobs_new.json
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    AGENTE LLM (Hermes cron)                  β”‚
β”‚                                                              β”‚
β”‚  1. LΓͺ jobs_new.json                                       β”‚
β”‚  2. Usa heuristic_score como ponto de partida              β”‚
β”‚  3. Reavalia casos borderline (2-4 estrelas)               β”‚
β”‚  4. Filtra pra 3+ estrelas                                 β”‚
β”‚  5. Ordena por data                                        β”‚
β”‚  6. Reporta ao usuΓ‘rio (Telegram)                          β”‚
β”‚  7. Salva resposta como .md em LINKEDIN_CRON_OUTPUT_DIR    β”‚
β”‚                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                           β–Ό prΓ³xima execuΓ§Γ£o do scraper lΓͺ isso
                      (volta ao topo)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                 CV TAILORING (tailor_cv.py)                  β”‚
β”‚                                                              β”‚
β”‚  1. LΓͺ seu CV (markdown) + jobs_new.json                   β”‚
β”‚  2. Extrai keywords de cada vaga (tools, conceitos, soft)  β”‚
β”‚  3. Compara com seu CV β€” match % por hard/soft skills      β”‚
β”‚  4. Modo analyze: mostra compatibilidade de todas as vagas β”‚
β”‚  5. Modo tailor: gera CV otimizado pra uma vaga especΓ­fica β”‚
β”‚  6. Gera prompt LLM pra tailoring profundo com IA          β”‚
β”‚                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Passo 7 β€” Tailor seu CV para cada vaga

Uma vez que as vagas comeΓ§aram a chegar no Telegram, vocΓͺ pode adaptar seu CV para cada vaga interessante usando o tailor_cv.py.

7.1 Configurar a chave de API (recomendado)

Com uma chave de API, o script chama um LLM diretamente e gera um CV polido, otimizado pra vaga β€” igual a um escritor de currΓ­culo profissional faria.

# Escolha UM dos providers abaixo:

# OpenAI
export LLM_API_KEY="sk-..."          # Sua chave de API

# OpenRouter (acesso a vΓ‘rios modelos)
export LLM_API_KEY="sk-or-..."       # Sua chave OpenRouter
export LLM_API_BASE="https://openrouter.ai/api/v1"
export LLM_MODEL="openai/gpt-4o-mini"

# Outro provider compatΓ­vel com OpenAI
export LLM_API_KEY="sua-chave"
export LLM_API_BASE="https://seu-endpoint.com/v1"
export LLM_MODEL="nome-do-modelo"
VariΓ‘vel PadrΓ£o DescriΓ§Γ£o
LLM_API_KEY (obrigatΓ³rio) Chave de API OpenAI-compatΓ­vel
LLM_API_BASE https://api.openai.com/v1 URL base da API (troque pra OpenRouter, Groq, etc.)
LLM_MODEL gpt-4o-mini Modelo a usar (gpt-4o-mini Γ© barato e bom pra CV)

πŸ’‘ Sem chave de API? O script funciona em modo gratuito: faz anΓ‘lise de keywords, mostra gaps e gera um prompt que vocΓͺ pode colar manualmente no ChatGPT ou Claude.

7.2 Preparar seu CV

Crie um arquivo markdown com seu currΓ­culo (ex: meu-cv.md). Use esta estrutura:

# Seu Nome

## InformaΓ§Γ΅es de Contato
- Email: seu@email.com
- LinkedIn: linkedin.com/in/seu-perfil
- LocalizaΓ§Γ£o: Sua Cidade - UF

## Headline / Posicionamento
Sua Γ‘rea | Skills principais | Diferencial

## Perfil Profissional
(3-5 linhas descrevendo sua trajetΓ³ria e especialidades)

## ExperiΓͺncia Profissional

### Cargo Atual
**EMPRESA** | mΓͺs/ano - atual | Cidade
- RealizaΓ§Γ£o 1 com resultado concreto
- RealizaΓ§Γ£o 2 com tecnologia usada
- RealizaΓ§Γ£o 3 com impacto no negΓ³cio

### Cargo Anterior
**EMPRESA** | mΓͺs/ano - mΓͺs/ano | Cidade
- ...

## Habilidades

### Habilidades TΓ©cnicas
- Skill 1
- Skill 2

### Habilidades de GestΓ£o
- Skill 1

## Ferramentas
- Ferramenta 1
- Ferramenta 2

## FormaΓ§Γ£o

### Curso
**Universidade** | ano - ano

## Idiomas
- Idioma: NΓ­vel

⚠️ O script nunca inventa experiΓͺncia. Ele sΓ³ reordena, destaca e sugere keywords que jΓ‘ estΓ£o no seu CV. Gaps sΓ£o sinalizados honestamente.

7.3 Gerar o CV otimizado

Quando uma vaga interessante chegar no Telegram, copie o ID (o nΓΊmero no link linkedin.com/jobs/view/XXXXX) e rode:

# ═══ OpΓ§Γ£o A: com LLM (recomendado) ═══
# Busca a vaga direto na API do LinkedIn + gera CV com IA
python3 tailor_cv.py meu-cv.md --job-id 4429960220

# Ou use o JSON do scraper (jΓ‘ tem tΓ­tulo, empresa e descriΓ§Γ£o)
python3 tailor_cv.py meu-cv.md --json ~/linkedin-jobs/jobs_new.json --job-id 4429960220

# ═══ OpΓ§Γ£o B: prompt manual (sem API key) ═══
# Gera um prompt que vocΓͺ cola no ChatGPT / Claude
python3 tailor_cv.py prompt meu-cv.md --job-id 4429960220

# ═══ OpΓ§Γ£o C: colar descriΓ§Γ£o da vaga ═══
# Pra vagas de outros sites (Gupy, Glassdoor, etc.)
python3 tailor_cv.py meu-cv.md --job-url https://exemplo.com/vaga
# β†’ Cole a descriΓ§Γ£o e pressione Ctrl+D

O script salva os arquivos em ~/linkedin-jobs/tailored/ (configurΓ‘vel via TAILOR_CV_DIR):

Arquivo Com LLM Sem LLM
cv_NomeVaga_Empresa.md βœ… CV pronto, polido, otimizado β€”
prompt_NomeVaga_Empresa.md β€” βœ… Prompt pra colar no ChatGPT/Claude

πŸ’‘ Dica: depois de gerar o CV, abra o arquivo, revise (o LLM pode ter ajustado o tom ou encurtado demais alguma experiΓͺncia) e converta pra PDF com o Google Docs, Word ou Pandoc.

7.4 Analisar todas as vagas de uma vez

python3 tailor_cv.py analyze meu-cv.md ~/linkedin-jobs/jobs_new.json

Mostra um ranking de compatibilidade com todas as vagas encontradas, com barra de progresso e gaps por vaga. RΓ‘pido, gratuito, nΓ£o precisa de API key.

7.5 Fluxo completo (do Telegram ao CV tailorado)

Telegram: "πŸ” 8 vagas novas β€” 23/06/2026 15:00"
         ↓
     VocΓͺ lΓͺ, acha uma vaga interessante
         ↓
     Copia o ID do link (linkedin.com/jobs/view/XXXXX)
         ↓
     python3 tailor_cv.py meu-cv.md --job-id XXXXX
         ↓
     Script busca descriΓ§Γ£o, chama LLM, gera CV tailado
         ↓
     Abre cv_NomeVaga_Empresa.md, revisa, exporta PDF
         ↓
     Candidata-se com CV otimizado pra ESSA vaga

7.6 Exemplo de saΓ­da

# Seu Nome β€” Tailored CV
> **Target:** Senior Data Engineer at TechCorp Brasil
> **Compatibility:** 68/100

## Professional Profile
Data engineer with 5+ years building lakehouse architectures...

## Professional Experience

### Data Engineer
**TechCorp** | 2022 - present
*Relevance: Direct match for the role's BigQuery + Python requirements*
- Built ETL pipelines processing 10TB/day using BigQuery and Python...

Como Funciona

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     SCRAPER (linkedin_jobs.py)               β”‚
β”‚                                                              β”‚
β”‚  1. Carrega seen.json (IDs + chaves)                        β”‚
β”‚  2. LΓͺ ΓΊltimos 3 outputs do agente (pula vagas reportadas)  β”‚
β”‚  3. Remove keywords improdutivas                            β”‚
β”‚  4. Busca na API Guest do LinkedIn (2 pΓ‘ginas Γ— N queries)  β”‚
β”‚  5. Dedup tripla: ID + tΓ­tulo/empresa + reportadas          β”‚
β”‚  6. Filtra: sΓ³ Brasil/SP, sem jΓΊnior                        β”‚
β”‚  7. Busca detalhes em paralelo (3 threads, mΓ‘x 8 vagas)     β”‚
β”‚  8. Salva: seen.json + keywords.json + jobs_new.json + jobs.md β”‚
β”‚                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                           β–Ό jobs_new.json
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    AGENTE LLM (Hermes cron)                  β”‚
β”‚                                                              β”‚
β”‚  1. LΓͺ jobs_new.json                                       β”‚
β”‚  2. Usa heuristic_score como ponto de partida              β”‚
β”‚  3. Reavalia casos borderline (2-4 estrelas)               β”‚
β”‚  4. Filtra pra 3+ estrelas                                 β”‚
β”‚  5. Ordena por data                                        β”‚
β”‚  6. Reporta ao usuΓ‘rio (Telegram)                          β”‚
β”‚  7. Salva resposta como .md em LINKEDIN_CRON_OUTPUT_DIR    β”‚
β”‚                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                           β–Ό prΓ³xima execuΓ§Γ£o do scraper lΓͺ isso
                      (volta ao topo)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                 CV TAILORING (tailor_cv.py)                  β”‚
β”‚                                                              β”‚
β”‚  1. VocΓͺ vΓͺ vaga no Telegram β†’ copia o ID                  β”‚
β”‚  2. tailor_cv.py busca descriΓ§Γ£o da vaga                   β”‚
β”‚  3. Com LLM_API_KEY β†’ chama IA e gera CV polido           β”‚
β”‚  4. Sem LLM_API_KEY β†’ anΓ‘lise de keywords gratuita        β”‚
β”‚  5. CV otimizado salvo em tailored/                        β”‚
β”‚                                                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

LimitaΓ§Γ΅es

  • Apenas API Guest β€” sem endpoints autenticados, sem status de candidatura, sem vagas salvas
  • Rate limiting β€” o LinkedIn pode bloquear se vocΓͺ bater muito na API. O scraper usa 300ms entre pΓ‘ginas e 2s de backoff em retries
  • Parsing de HTML β€” se o LinkedIn mudar a estrutura do HTML, os parsers de regex quebram. Abra uma issue se isso acontecer
  • MΓ‘x 8 vagas por execuΓ§Γ£o β€” pra ficar dentro do deadline de 4 minutos. Ajuste MAX_DETAIL em main() se precisar de mais
  • Focado no Brasil β€” filtros padrΓ£o focam em Brasil/SΓ£o Paulo. Edite build_searches() pra outras regiΓ΅es

Troubleshooting

"Nenhuma vaga nova" toda execuΓ§Γ£o

  • Verifique seen.json β€” pode ter crescido demais. O scraper exclui qualquer ID jΓ‘ visto. Pra resetar: delete seen.json e jobs.md.
  • Verifique keywords.json β€” keywords podem ter sido removidas. Reset: delete keywords.json.

API retorna resultados vazios

  • O LinkedIn pode estar limitando sua taxa. Espere 10-15 minutos.
  • A API Guest pode estar fora do ar. Teste a URL direto no navegador: https://www.linkedin.com/jobs-guest/jobs/api/seeMoreJobPostings/search?keywords=data+engineer&location=Brazil&start=0
  • Seu IP pode estar bloqueado. Tente uma VPN ou rede diferente.

Vagas duplicadas aparecendo

  • Certifique-se de que LINKEDIN_CRON_OUTPUT_DIR estΓ‘ definido se vocΓͺ usa um agente. Sem isso, o scraper nΓ£o sabe o que jΓ‘ foi reportado.
  • Verifique se o formato da resposta do agente bate com **N. ⭐⭐⭐ TΓ­tulo da Vaga** (o regex espera estrelas).

Bot do Telegram nΓ£o responde

  • Verifique o token: hermes gateway deve mostrar logs sem erro
  • Confirme que seu User ID estΓ‘ em TELEGRAM_ALLOWED_USERS em ~/.hermes/.env
  • Reinicie o gateway: hermes gateway

Cron job nΓ£o dispara

  • Verifique: hermes cron list
  • Rode manualmente pra testar: python3 ~/linkedin-job-scraper/linkedin_jobs.py
  • Cheque os logs: ~/.hermes/cron/output/<job_id>/

CV Tailoring: "Failed to fetch job description"

  • O LinkedIn pode estar bloqueando requests da sua mΓ‘quina. Espere alguns minutos.
  • Tente com --json jobs_new.json --job-id <id> (usa os dados do scraper, nΓ£o faz request novo).
  • Se o problema persistir, use --job-url e cole a descriΓ§Γ£o manualmente.

CV Tailoring: LLM nΓ£o gera CV (vai pro modo keyword)

  • Verifique se LLM_API_KEY estΓ‘ exportada: echo $LLM_API_KEY
  • Teste o endpoint manualmente: curl -s $LLM_API_BASE/chat/completions (se falhar, sua chave ou URL estΓ£o errados)
  • Troque o modelo: export LLM_MODEL="gpt-4o-mini" (mais barato e rΓ‘pido que GPT-4)

CV Tailoring: "CV file not found"

  • Certifique-se de que o arquivo markdown do CV existe no caminho especificado.
  • Use caminho absoluto: python3 tailor_cv.py ~/meu-cv.md --job-id 123
  • Siga o template da seΓ§Γ£o 7.2 pra criar seu CV no formato esperado.

ConfiguraΓ§Γ£o completa (env vars)

VariΓ‘vel PadrΓ£o Usada por
LLM_API_KEY (obrigatΓ³rio p/ LLM) tailor_cv.py
LLM_API_BASE https://api.openai.com/v1 tailor_cv.py
LLM_MODEL gpt-4o-mini tailor_cv.py
TAILOR_CV_DIR ~/linkedin-jobs/tailored/ tailor_cv.py
LINKEDIN_OUTPUT_DIR ~/linkedin-jobs linkedin_jobs.py, linkedin_metrics.py, tailor_cv.py
LINKEDIN_CRON_OUTPUT_DIR (desativado) linkedin_jobs.py
LINKEDIN_USER_NAME User linkedin_jobs.py

Contribuindo

  1. FaΓ§a um fork
  2. Crie sua branch de feature (git checkout -b feature/foo)
  3. Commit suas mudanΓ§as (git commit -am 'Add foo')
  4. Push pra branch (git push origin feature/foo)
  5. Crie um Pull Request

LicenΓ§a

MIT β€” veja LICENSE.

About

Python scraper for LinkedIn's public Guest API with triple deduplication, heuristic scoring, and keyword yield tracking. Stdlib only, no dependencies.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages