Skip to content

Repository files navigation

RaxyJobFinder

Buscador multicanal de vagas com rotação automática de proxies.

Raxy consulta LinkedIn, Gupy e Glassdoor em paralelo, rotaciona proxies automaticamente via bridges Xray/V2Ray, e aplica filtros inteligentes nas vagas encontradas — via CLI, SDK Python, API REST ou UI web.


Instalação

pip (recomendado)

pip install botasaurus dependency-injector beautifulsoup4 requests urllib3 rich prompt_toolkit PyYAML loguru redis
pip install /caminho/para/proxy_framework/
pip install -e .

Requer Python 3.10+ e o binário do Xray (ou V2Ray) no PATH ou apontado por $XRAY_PATH.

Docker

docker build -t raxy .

A imagem já empacota Python, dependências, Redis e o Xray-core. Use:

docker run --rm -it -v "$PWD/output:/app/output" raxy --keywords "Python" --portal linkedin

Nix (NixOS / nix-shell)

nix-shell
python buscador_vagas/buscador.py

O shell.nix configura o ambiente Python, baixa dependências faltantes e detecta automaticamente o Xray ou V2Ray do nixpkgs.


Quick Start

# Buscar vagas de Python no LinkedIn (padrão)
python buscador_vagas/buscador.py --keywords "Python" --location "São Paulo"

# Resultados salvos em:
#   output/linkedin/vagas.json      — vagas básicas no schema canônico
#   output/linkedin/detalhadas.json — vagas com descrição completa

API REST e UI Web

A API FastAPI expõe o SDK por HTTP e a UI web consome essa API em tempo real. O jeito mais simples de subir tudo é com Docker Compose:

docker compose up --build

Serviços:

Serviço URL Descrição
UI http://localhost:3000 Interface web estática em ui/index.html
API http://localhost:8000 API REST/SSE FastAPI
Docs http://localhost:8000/docs Swagger/OpenAPI automático
Redis localhost:6379 Pub/sub de eventos da busca

Endpoints principais:

Método Rota Uso
GET /health Status da API
POST /search Busca síncrona; responde só no fim
POST /search/stream Busca com eventos SSE em tempo real
GET /output/{portal}?kind=detalhadas Lê último JSON salvo (vagas ou detalhadas)

Exemplo de busca pela API:

curl -X POST http://localhost:8000/search \
  -H 'Content-Type: application/json' \
  -d '{
    "portal": "linkedin",
    "keywords": "Python",
    "location": "São Paulo",
    "details_limit": 10,
    "max_jobs": 20
  }'

Para rodar a API sem Docker Compose, mantenha Redis disponível e execute:

pip install -r api/requirements.txt
uvicorn api.main:app --host 0.0.0.0 --port 8000

A UI aponta por padrão para http://localhost:8000 (API_BASE em ui/index.html). Se a API rodar em outro host/porta, ajuste esse valor.


SDK Python (Programático)

Além da CLI, o Raxy oferece um SDK para uso diretamente em código Python. Importe JobFinder e obtenha os resultados como objetos tipados.

Instalação

pip install -e .  # ou pip install buscador_vagas/

Uso básico

from buscador_vagas import JobFinder

finder = JobFinder(portal="linkedin", keywords="Python", location="São Paulo")
jobs = finder.search(max_jobs=180)  # pagina ate 180 vagas; 0 = so primeira pagina

for job in jobs:
    print(job.summary.title, job.summary.company)

Com filtro por arquivo JSON

finder = JobFinder(
    portal="linkedin",
    keywords="Python",
    filters="filters/python.json",
)
jobs = finder.search()

Com filtro programático

from buscador_vagas import JobFinder, JobFilterSet

filtro = JobFilterSet.from_dict({
    "all": [
        {"fields": ["title"], "contains": "Python"},
        {"fields": ["criteria.Tipo"], "in": ["Remoto", "Híbrido"]},
    ]
})

finder = JobFinder(filters=filtro)
jobs = finder.search()

Filtro por chamada (sobrescreve o do construtor)

finder = JobFinder()

# só nesta busca aplica o filtro
jobs = finder.search(filters=filtro)

# próxima busca volta ao comportamento padrão (sem filtro)
jobs2 = finder.search()

Proxy, paginação e detalhes

finder = JobFinder(
    portal="gupy",
    keywords="Data Science",
    location="Rio de Janeiro",
    proxy_provider="brazil",          # proxies brasileiros
    proxy_sources=["https://meu-proxy.txt"],  # ou lista manual
    valid_count=25,                   # pool de bridges
    jobs_per_proxy=3,                 # rotaciona a cada 3 detalhes
    max_jobs=120,                     # paginação: até 120 vagas
    detail_threads=10,                # 10 threads para detalhes
    details_limit=20,                 # detalha só as 20 primeiras
    timeout=15.0,                     # timeout do proxy
    detail_timeout=8.0,               # timeout do detalhe
    silent=True,                      # sem output no terminal
)

jobs = finder.search(
    jobs_output="resultados/vagas.json",
    details_output="resultados/detalhadas.json",
    max_jobs=180,        # override por chamada
    details_limit=40,    # detalha ate 40; 0 = todas
)

Tipos retornados

search() retorna list[JobPosting], onde cada JobPosting contém:

Atributo Tipo Descrição
summary JobSummary Dados básicos da vaga (título, empresa, local, URL)
details JobDetails | None Descrição completa, critérios, texto de candidatura
detail_error str Mensagem de erro se o detalhamento falhou

Use job.to_dict() para serializar em dicionário (útil para JSON).

Todos os parâmetros do construtor

Parâmetro Padrão Descrição
portal "linkedin" linkedin, gupy ou glassdoor
keywords "Vagas" Termo de busca
location "Brasil" Localização
location_id None ID da localização (pula typeahead)
location_choice None Índice 1-based no typeahead
work_type "normal" Modelo de trabalho, exclusivo do LinkedIn: normal, remote/remoto ou hybrid/hibrido/híbrido
under_10_applicants False True para filtrar vagas do LinkedIn com menos de 10 candidaturas
recent_period "any" Periodo de publicacao, exclusivo do LinkedIn: any, day/24h, week ou month
proxy_sources None Lista de URLs/arquivos de proxy
proxy_provider "united-states" brazil, united-states, canada, etc.
valid_count 25 Bridges no pool
jobs_per_proxy 5 Vagas por proxy antes de rotacionar
max_count 177 Máximo de configs de proxy a carregar
threads 8 Workers para testar proxies
timeout 12.0 Timeout do proxy (segundos)
detail_timeout 15.0 Timeout do detalhe (segundos)
filters None JobFilterSet, caminho de arquivo, ou None
filters_path None Caminho do arquivo de filtro (alternativo)
details_limit 0 Máx. de vagas para detalhar (0 = todas)
start 0 Offset da paginação
max_jobs 0 Máx. de vagas via paginação (0 = só 1ª página)
detail_threads 5 Threads paralelas para detalhes
gd_cookie "" Cookie do Glassdoor
silent True False para mostrar output no terminal
view None Objeto view customizado (substitui SilentView quando fornecido)
filter_by_keywords False True para filtrar vagas sem a keyword no titulo antes do detalhamento

Portais Suportados

Portal Autenticação Como obter
LinkedIn Pública (sem login) —
Gupy Pública (REST API) —
Glassdoor Cookie de sessão (Opcional) Faça login no Glassdoor pelo navegador, copie o cookie e passe com --gd-cookie
# LinkedIn (padrão)
python buscador_vagas/buscador.py --keywords "Desenvolvedor"

# Gupy
python buscador_vagas/buscador.py --portal gupy --keywords "Python" --location "São Paulo"

# Glassdoor (requer cookie autenticado)
python buscador_vagas/buscador.py --portal glassdoor --gd-cookie "seu_cookie_aqui" --keywords "Python"

Funcionalidades

Proxy automático

Raxy descobre, testa e mantém um pool de bridges HTTP via Xray/V2Ray. Os proxies são rotacionados a cada N vagas detalhadas para evitar bloqueios.

# Pool de 25 bridges, troca de proxy a cada 5 detalhes
python buscador_vagas/buscador.py --valid-count 25 --jobs-per-proxy 5

Cache de proxies

Os proxies testados são salvos em proxy_cache.json para reúso. Remova o arquivo para forçar um novo teste.

Paginação

Colete centenas de vagas com paginação automática:

python buscador_vagas/buscador.py --keywords Desenvolvedor --max-jobs 180 --start 0

Filtros inteligentes

Regras de filtragem em JSON. O motor suporta operadores lógicos (all, any, not) e operadores de campo (contains, not_contains, equals, not_equals, regex, in, exists).

python buscador_vagas/buscador.py --filters filtros/python.json

Além dos filtros JSON opcionais, a keyword da busca também é aplicada no resultado final: para --keywords "Python", a vaga só é salva se Python aparecer no título ou na descrição detalhada. O valor padrão Vagas é tratado como placeholder e não aplica esse corte.

Modelo de trabalho

Use --work-type para pedir vagas remotas ou híbridas somente no LinkedIn. O filtro é enviado para a busca pública com f_WT=2 para remoto e f_WT=3 para híbrido. Se --work-type diferente de normal for usado na Gupy ou no Glassdoor, a busca é recusada.

python buscador_vagas/buscador.py --portal linkedin --keywords Python --work-type remote
python buscador_vagas/buscador.py --portal linkedin --keywords Python --work-type híbrido

Aliases aceitos: remote/remoto, hybrid/hibrido/híbrido e normal.

Em todos os portais, os resultados salvos recebem o campo canônico modalidade com remoto, híbrido ou presencial. Quando o portal não entrega a modalidade diretamente, o Raxy tenta inferir a partir de campos como workplaceType, isRemoteWork, critérios da vaga e textos de localização/detalhes. Na Gupy, vagas sem cidade/local explícito são tratadas como REMOTO e recebem modalidade remota quando aplicável.

Candidaturas no LinkedIn

Use --under-10-applicants para filtrar vagas com menos de 10 candidaturas no LinkedIn. Sem essa flag, a busca normal é usada.

python buscador_vagas/buscador.py --portal linkedin
python buscador_vagas/buscador.py --portal linkedin --under-10-applicants

Quando --under-10-applicants é usado, o Raxy envia f_EA=true na URL do LinkedIn. Se esse filtro for usado na Gupy ou no Glassdoor, a busca é recusada.

Vagas recentes no LinkedIn

Use --recent-period para filtrar vagas por periodo de publicacao no LinkedIn. Sem filtro, use any.

python buscador_vagas/buscador.py --portal linkedin --recent-period month
python buscador_vagas/buscador.py --portal linkedin --recent-period week
python buscador_vagas/buscador.py --portal linkedin --recent-period 24h

O Raxy envia f_TPR=r2592000 para ultimo mes, f_TPR=r604800 para ultima semana e f_TPR=r86400 para ultimas 24h. No SDK, use JobFinder(recent_period="month"), "week" ou "day".

Requisitos extraídos

Durante o detalhamento, o campo criteria.requisitos é preenchido automaticamente a partir da descrição da vaga com keywords técnicas e comportamentais conhecidas, por exemplo python, sql, power_bi, cloud, docker, scrum, comunicacao, lideranca e testes.

Esse campo pode ser usado nos filtros:

{
  "fields": ["criteria.requisitos"],
  "contains": ["python", "sql"]
}

Threads paralelas

python buscador_vagas/buscador.py --threads 8 --detail-threads 5

Filtros

Os filtros são arquivos JSON que você passa com --filters. Eles permitem incluir ou excluir vagas com base no título, descrição, localização, critérios e outros campos.

Estrutura básica

Cada filtro é um objeto JSON com operadores. O operador mais simples é o contains:

{
  "fields": ["title", "description"],
  "contains": "python"
}

Isso mantém apenas vagas cujo título ou descrição contenham "python".

Operadores de campo

Operador O que faz Exemplo
contains O campo contém o texto (case insensitive) "contains": "python"
contains (lista) O campo contém qualquer item da lista "contains": ["estagio", "estágio"]
not_contains O campo não contém o texto "not_contains": "trainee"
equals O campo é exatamente igual ao valor "equals": "Remoto"
not_equals O campo é diferente do valor "not_equals": "Presencial"
regex O campo casa com uma expressão regular `"regex": "python
in O campo é igual a um dos valores da lista "in": ["São Paulo", "SP"]
exists O campo existe e não está vazio "exists": true

Exemplos de cada operador:

{ "fields": ["title"], "not_contains": "trainee" }
{ "fields": ["company"], "equals": "Google" }
{ "fields": ["location"], "regex": "(SP|RJ)" }
{ "fields": ["criteria.Tipo"], "in": ["Remoto", "Híbrido"] }
{ "fields": ["description"], "exists": true }

Operadores lógicos

Combine regras com all, any e not:

Operador Efeito
all Todas as sub-regras precisam ser verdade (AND)
any Pelo menos uma sub-regra precisa ser verdade (OR)
not A sub-regra não pode ser verdade (NOT)

all — todas as condições devem ser atendidas:

{
  "all": [
    { "fields": ["title"], "contains": "senior" },
    { "fields": ["location"], "contains": "remoto" }
  ]
}

Só passa se o título contiver "senior" E a localização contiver "remoto".

any — qualquer condição já aprova:

{
  "any": [
    { "fields": ["title", "description"], "contains": "python" },
    { "fields": ["title", "description"], "contains": ["dados", "data"] }
  ]
}

Passa se tiver "python" OU "dados"/"data".

not — nega a condição:

{
  "not": {
    "fields": ["title", "description"],
    "contains": ["estagio", "estágio", "aprendiz"]
  }
}

Exclui vagas que contenham "estagio", "estágio" ou "aprendiz".

Você pode aninhar livremente:

{
  "all": [
    { "fields": ["title"], "contains": "python" },
    {
      "not": {
        "fields": ["title"],
        "contains": "estágio"
      }
    },
    {
      "any": [
        { "fields": ["location"], "contains": "remoto" },
        { "fields": ["location"], "contains": "hibrido" }
      ]
    }
  ]
}

Campos disponíveis para filtrar

O filtro opera sobre o dicionário completo da vaga (básico + detalhado). Os campos mais comuns:

Campo Origem Conteúdo
title básico Título da vaga
company básico Nome da empresa
location básico Localização
modalidade básico/canônico remoto, híbrido ou presencial
description detalhado Descrição completa
criteria detalhado Objeto com critérios (ex: {"Tipo": "Efetivo/CLT", "Nivel de experiencia": "N/A"})
criteria.Tipo detalhado Acesso via dot notation, ex: tipo de contratação
criteria.Nivel de experiencia detalhado Nível hierárquico quando informado pelo portal
criteria.requisitos detalhado Lista de keywords inferidas da descrição
listed_text básico Texto de quando foi publicada

Para acessar campos aninhados, use dot notation: criteria.Tipo, criteria.Nivel de experiencia.

Como montar seu próprio filtro

  1. Execute uma busca primeiro para gerar output/linkedin/detalhadas.json
  2. Veja a estrutura dos campos no JSON gerado
  3. Crie um arquivo .json com as regras desejadas
  4. Passe com --filters

Exemplo passo a passo:

# 1. Busca para gerar os JSONs de saída
python buscador_vagas/buscador.py --keywords "Python" --details-limit 5

# 2. Olhe o arquivo gerado para conhecer os campos
python -m json.tool output/linkedin/detalhadas.json

# 3. Crie seu filtro, por exemplo meu_filtro.json:
# {
#   "all": [
#     { "fields": ["title"], "contains": "senior" },
#     { "fields": ["criteria.Tipo"], "in": ["Remoto", "Híbrido"] }
#   ]
# }

# 4. Rode com o filtro
python buscador_vagas/buscador.py --keywords "Python" --filters meu_filtro.json

Filtros prontos

Arquivo Efeito
buscador_vagas/filters/python.json Apenas vagas com "python" no título ou descrição
buscador_vagas/filters/python_or_data.json Python OU dados/data/analytics
buscador_vagas/filters/senior_remote.json Senior E remoto
buscador_vagas/filters/not_internship.json Exclui estágio/aprendiz

Opções da CLI

--portal

Portal de vagas a consultar. Padrão: linkedin.

--portal linkedin     LinkedIn (padrão, sem autenticação)
--portal gupy         Gupy (API pública REST)
--portal glassdoor    Glassdoor (requer --gd-cookie)

--keywords

Termo de busca. Use aspas para múltiplas palavras. Depois do detalhamento, o Raxy mantém apenas vagas em que esse termo aparece no título ou na descrição; Vagas, o padrão, não aplica esse filtro final.

--keywords "Python"
--keywords "Desenvolvedor Java Sênior"

--location / --location-choice / --location-id / --geo-id

Controlam o local da busca. O Raxy consulta o typeahead do portal e mostra as opções disponíveis.

--location "São Paulo"                  # texto da busca
--location "São Paulo" --location-choice 1   # escolhe automaticamente o 1º resultado
--location-id 106057199                 # pula o typeahead, usa o ID direto
--geo-id 106057199                      # alias do --location-id (LinkedIn)

--provider

Fonte de proxies do repositório F0rc3Run/splitted-by-country. Padrão: united-states.

--provider brazil
--provider united-states

--work-type

Modelo de trabalho desejado, exclusivo do LinkedIn. Padrão: normal.

--work-type normal     # não aplica filtro de modalidade no LinkedIn
--work-type remote     # remoto; aceita também remoto
--work-type hybrid     # híbrido; aceita também hibrido/híbrido

--under-10-applicants

Filtro booleano de candidaturas, exclusivo do LinkedIn. Por padrão fica desligado.

--under-10-applicants  # adiciona f_EA=true

--recent-period

Periodo de publicacao, exclusivo do LinkedIn. Padrão: any.

--recent-period any       # não aplica filtro de data
--recent-period month     # ultimo mes; f_TPR=r2592000
--recent-period week      # ultima semana; f_TPR=r604800
--recent-period day       # ultimas 24h; aceita também 24h

--proxy-source

URL ou caminho local para uma lista manual de proxies. Pode repetir a flag para múltiplas fontes.

--proxy-source "https://exemplo.com/proxies.txt"
--proxy-source "./meus_proxies.txt" --proxy-source "https://outra-fonte.com/proxies.txt"

--valid-count

Número alvo de bridges HTTP a manter no pool. O Raxy testa proxies até atingir esse número. Se encontrar menos, segue com os disponíveis.

--valid-count 25    # padrão
--valid-count 50    # pool maior = mais resiliência

--jobs-per-proxy

Quantos detalhes de vaga cada proxy processa antes de rotacionar para o próximo. Útil para evitar bloqueio por excesso de requisições no mesmo IP.

--jobs-per-proxy 5    # troca de proxy a cada 5 detalhes (padrão)
--jobs-per-proxy 1    # troca a cada vaga (máximo de discrição)
--jobs-per-proxy 20   # troca só a cada 20 detalhes

--max-count

Número máximo de proxies a testar. Corta o teste cedo se você já tiver proxies suficientes.

--max-count 10    # testa no máximo 10 proxies

--max-jobs / --start

Paginação. --max-jobs define o total de vagas a coletar; --start define o offset inicial. A cada página o offset incrementa em 60.

--max-jobs 180 --start 0     # coleta 180 vagas do início
--max-jobs 300 --start 60    # começa do offset 60, coleta até 300

--timeout / --detail-timeout

Timeouts em segundos. --timeout para o teste inicial de conectividade do proxy; --detail-timeout para o request de detalhe da vaga.

--timeout 12        # 12s para testar cada proxy (padrão)
--detail-timeout 5  # 5s para cada detalhe de vaga (padrão)

--threads / --detail-threads

Paralelismo. --threads para testar proxies simultaneamente; --detail-threads para buscar detalhes de vagas em paralelo.

--threads 8           # 8 workers testam proxies por vez (padrão)
--detail-threads 5    # 5 threads buscam detalhes em paralelo (padrão)

--details-limit

Limita quantas vagas serão detalhadas. Use 0 para detalhar todas.

--details-limit 10    # detalha só as 10 primeiras vagas
--details-limit 0     # detalha todas as vagas encontradas

--jobs-output / --details-output

Caminhos dos arquivos de saída.

--jobs-output output/linkedin/vagas.json       # vagas básicas
--details-output output/linkedin/detalhadas.json  # vagas com descrição

--show-jobs

Quantas vagas exibir na tabela do terminal ao final.

--show-jobs 20    # mostra 20 vagas na tabela
--show-jobs 50    # mostra 50 vagas na tabela

--filters

Arquivo JSON com regras de filtragem. O motor suporta operadores all, any, not, contains, not_contains, equals, not_equals, regex, in, exists e dot notation para campos aninhados.

--filters filters/python.json
--filters filters/senior_remote.json

--filter-by-keywords

Ativa filtro restritivo por keyword no título e descrição. Sem essa flag, a keyword da busca é usada apenas para filtrar o resultado final (vagas sem a keyword no título ou descrição são descartadas). Com --filter-by-keywords, o filtro é aplicado durante a coleta — vagas que não contêm a keyword no título são ignoradas antes mesmo do detalhamento.

--filter-by-keywords  # ativa filtro restritivo

--gd-cookie

Cookie de sessão do Glassdoor (obrigatório para o portal Glassdoor). Faça login no Glassdoor pelo navegador, abra o DevTools (F12) > Network, copie o header Cookie de qualquer requisição.

--gd-cookie "session_id=abc123; ..."

Campos retornados

Os arquivos JSON são salvos em um schema canônico estável. Campos internos específicos de cada portal ficam em provider_data durante a execução, mas não são persistidos por padrão.

Vagas básicas: provider, job_id, title, company, location, listed_at, listed_text, url, company_url, logo_url, modalidade

listed_at é salvo como Unix timestamp em segundos quando o portal fornece uma data absoluta. Campos textuais, como listed_text e detail_posted_text, continuam preservando o texto original do portal.

Vagas detalhadas (adicional): detail_title, detail_company, detail_company_url, detail_location, detail_posted_text, detail_applicants_text, description, criteria, apply_text, detail_url, detail_logo_url, detail_status_code, detail_html_size, detail_bridge_index

criteria.requisitos contém a lista de requisitos/keywords inferidos da descrição quando o detalhamento encontra esses termos.


TUI

Raxy também oferece uma interface TUI interativa com prompt_toolkit:

# Abre a interface gráfica no terminal
python buscador_vagas/buscador.py

A TUI exige um config.yaml no diretório atual antes de abrir. Configurações técnicas, como provider de proxy, limites, timeouts, caminhos de saída e Redis, vêm desse arquivo; o termo de busca não deve ser configurado em defaults.keywords, porque ele é informado a cada busca.

A TUI guia a busca em etapas com seletores para valores fechados, como portal, modalidade do LinkedIn e periodo de vagas recentes, e campos textuais apenas onde há entrada livre. O status em tempo real é exibido via eventos Redis/pub-sub durante proxy, busca, detalhes e salvamento.

Para usar com Redis, as variáveis RAXY_REDIS_URL e RAXY_REDIS_CHANNEL são repassadas automaticamente ao container ao iniciar a busca pela TUI.


Eventos / Redis

O Raxy publica eventos em tempo real via Redis pub/sub durante todo o ciclo de busca.

Canais

Canal Conteúdo Quando
raxy:events Evento JSON: {name, message, level, payload, occurred_at} Todo ciclo de vida
vagas:disponiveis {portal, total_vagas, vagas: [...]} Ao finalizar a busca

Consumindo dados de vagas

import redis, json

r = redis.Redis()
pubsub = r.pubsub()
pubsub.subscribe("vagas:disponiveis")
for msg in pubsub.listen():
    if msg["type"] == "message":
        data = json.loads(msg["data"])
        print(f"{data['portal']}: {data['total_vagas']} vagas")

Config

redis:
  url: "redis://localhost:6379/0"
  channel: "raxy:events"
Env Var Sobrepoe
RAXY_REDIS_URL redis.url
RAXY_REDIS_CHANNEL redis.channel
RAXY_REDIS_DATA_CHANNEL redis.data_channel
RAXY_LOG_LEVEL logging.level
XRAY_PATH Caminho do binário Xray

Proxy System

O Raxy baixa listas de proxies de URLs públicas (organizadas por país), testa conectividade em paralelo, e inicia bridges Xray locais (http://127.0.0.1:54xxx).

  • Rotação: a cada N vagas detalhadas troca de bridge (round-robin)
  • Fallback: se uma bridge falha, a próxima disponível assume
  • Cache: resultados de teste salvos em proxy_cache.json

Provedores disponíveis: united-states, brazil, canada, germany, netherlands, all (40+ países).


Testes

nix-shell --run 'python -m pytest'

Estrutura: tests/domain/, tests/application/, tests/infrastructure/, tests/modules/, tests/tui/, tests/view/.


Arquitetura

Arquitetura hexagonal (Ports & Adapters):

                  +---------+  TUI  +---------+
                  |  CLI    |       |  SDK    |
                  +----+----+       +----+----+
                       |                 |
              +--------+--------+--------+
              |                  |
      JobSearchService           |
              |                  |
     +--------+--------+        |
     |        |        |        |
[Ports]  [Domínio]  [Eventos]   |
     |        |        |        |
LinkedIn  Gupy  Glassdoor       |
     |                  |       |
BotasaurusHttpClient    Redis   |
     |                  |       |
ProxyFrameworkPool -----+       |
     |                          |
[Xray bridges]            [JSON files]
Diretório Camada
job_search/domain/ Entidades de negócio
job_search/application/ Orquestração, DTOs, Ports, Eventos
job_search/infrastructure/ HTTP, Redis, JSON, Proxy, Config
job_search/interfaces/ CLI, TUI, Console
job_search/providers/ Adaptadores dos portais
sdk/ API programática
api/ API REST/SSE FastAPI
ui/ UI web estática

Entrypoints: buscador_vagas/buscador.py → launcher.py → CLI (se args) ou TUI; api.main:app → API REST/SSE; ui/index.html → UI web.

About

Buscador multicanal de vagas com rotação automática de proxies.

Resources

Stars

10 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages