Automatize o Monitoramento de Licitações de Obras em Todo o Brasil
Um sistema robusto e escalável para monitorar licitações de obras públicas através da API do Portal Nacional de Contratações Públicas (PNCP) em tempo real, com filtros inteligentes, geolocalização e integração com ferramentas de gestão de tarefas.
Antes de começar, certifique-se de ter instalado:
git clone https://github.com/rodrigochavesoa/monitor_licitacoes.git
cd monitor_licitacoes
Windows (PowerShell):
python -m venv venv
.\venv\Scripts\Activate.ps1
macOS/Linux:
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Nota: Este comando instalará todas as bibliotecas necessárias, incluindo
python-dotenvpara carregar configurações do arquivo.env.
npm install
# Copiar template de ambiente
cp .env.example .env
# Editar o arquivo .env com seus valores
.envAbra o arquivo .env e configure as variáveis principais:
# Dias a buscar no passado
DIAS_DE_BUSCA=1
# Estado alvo (sigla)
UF=BA
# Estado alvo (nome completo)
ESTADO=Bahia
# ClickUp (opcional)
CLICKUP_TOKEN=seu_token_aqui
CLICKUP_LIST_ID=seu_list_id_aqui
# Servidor backend
PORT=3001
O projeto já inclui dados de exemplo de Bahia e Sergipe. Para usar dados de outro estado:
Nenhuma configuração necessária - os dados já estão prontos em malhas_municipais/Bahia/
# Executar script para identificar cidades próximas
python identificar_cidades.py
Este script:
malhas_municipais/<ESTADO>/cidades_alvo.csv com as cidades prioritáriasOs filtros de licitação são totalmente personalizáveis através do arquivo .env, sem necessidade de editar código Python. Isso permite adaptar o sistema para diferentes segmentos de negócio.
O sistema utiliza 3 níveis de filtragem para refinar os resultados:
📋 Abra o arquivo .env e localize a seção de filtros:
# GRUPO_SERVICO: Palavras que descrevem o tipo de serviço/produto
# A licitação PRECISA conter pelo menos UMA destas palavras
GRUPO_SERVICO=pavimentação,reforma,construção,obra,infraestrutura
# GRUPO_CONTEXTO: Palavras que confirmam o contexto de contratação
# A licitação PRECISA conter pelo menos UMA destas palavras
GRUPO_CONTEXTO=engenharia,execução de,mão de obra
# GRUPO_EXCLUSAO: Palavras que descartam a licitação
# Se a licitação contiver QUALQUER uma destas palavras, será DESCARTADA
GRUPO_EXCLUSAO=consultoria,software,treinamento,veículo
🏗️ Obras de Engenharia Civil (Padrão):
GRUPO_SERVICO=pavimentação,paralelepípedo,reforma,ampliação,construção,edificação,obra
GRUPO_CONTEXTO=engenharia,serviços de engenharia,execução de,mão de obra
GRUPO_EXCLUSAO=fotográficos,consultoria,software,material de consumo
🛠️ Produtos/Equipamentos de Engenharia:
GRUPO_SERVICO=aquisição,fornecimento,compra,equipamento,material,ferramenta
GRUPO_CONTEXTO=material,produto,equipamento,fornecimento de,aquisição de
GRUPO_EXCLUSAO=serviço de,mão de obra,consultoria,obra,construção
🏥 Saúde e Hospitalar:
GRUPO_SERVICO=medicamento,equipamento médico,material hospitalar,insumo,vacina
GRUPO_CONTEXTO=hospital,clínica,saúde,posto de saúde,unidade básica
GRUPO_EXCLUSAO=obra,construção,reforma,pavimentação
💻 TI e Tecnologia:
GRUPO_SERVICO=software,hardware,sistema,aplicativo,equipamento de informática
GRUPO_CONTEXTO=tecnologia da informação,TI,sistema de,software de
GRUPO_EXCLUSAO=obra,construção,material de consumo
💡 Dica: Sempre use palavras em minúsculas e separe-as por vírgula sem espaços extras.
Nota: O sistema busca apenas as modalidades mais comuns e relevantes para obras públicas:
- Pregão Eletrônico
- Concorrência Eletrônica
- Concorrência Presencial
- Dispensa de Licitação
- Inexigibilidade
Essas modalidades são definidas na lista MODALIDADES_INTERESSE no início do arquivo monitor_licitacoesv2.py:
MODALIDADES_INTERESSE = [
6, # Pregão - Eletrônico
4, # Concorrência - Eletrônica
5, # Concorrência - Presencial
8, # Dispensa de Licitação
9 # Inexigibilidade
]
Existem outras modalidades disponíveis no PNCP, conforme o manual oficial. Se desejar incluir ou remover modalidades, basta editar essa lista conforme sua necessidade.
Busca na API PNCP
↓
┌───────────────────────────────────┐
│ Nível 1: GRUPO_SERVICO │
│ ✓ Contém "Reforma" OU │
│ ✓ Contém "Construção" │
└───────────────────────────────────┘
↓ (passa filtro)
┌───────────────────────────────────┐
│ Nível 2: GRUPO_CONTEXTO │
│ ✓ É "Municipal" OU "Estadual" │
└───────────────────────────────────┘
↓ (passa filtro)
┌───────────────────────────────────┐
│ Nível 3: GRUPO_EXCLUSAO │
│ ✗ Não contém "Consultoria" │
│ ✗ Não contém "Projeto" │
└───────────────────────────────────┘
↓
✅ RESULTADO FINAL
# Ativar ambiente virtual
.\venv\Scripts\Activate.ps1 # Windows
source venv/bin/activate # macOS/Linux
# Executar monitor
python monitor_licitacoesv2.py
python shpforcsv.py
Converte arquivos shapefile para CSV
python identificar_cidades.py
Gera arquivo cidades_alvo.csv com cidades próximas
python csvforjson.py
Converte dados em CSV para formato JSON
python conversao_conlicitacoes.py
Converte licitações exportadas do Portal Conlicitação para o formato aceito pelo sistema.
Como funciona:
.xlsx pelo próprio portal..xlsx gerado na pasta licitacoes_xlsx/ do projeto..json no formato compatível com o sistema..json gerado pode ser utilizado, por exemplo, para alimentar o painel web wp7licitacoes.html.⚠️ Importante: O Portal Conlicitação exige assinatura para acessar e exportar os boletins. O sistema não faz download automático, apenas converte arquivos já exportados.
node server.js
Inicia servidor Express na porta configurada (padrão: 3001)
Após executar o monitor, você verá:
{
"id": "123456",
"orgao": "Prefeitura de Salvador",
"objeto": "Reforma de escola",
"valor": 150000.00,
"data_publicacao": "2025-10-27",
"data_limite": "2025-11-10",
"status": "Aberta",
"cidade": "Salvador",
"distancia_km": 0.0,
"url": "https://pncp.gov.br/..."
}
app.clickup.com/list/<LIST_ID>.env e configure:
CLICKUP_TOKEN=pk_xxxxxxxxxxxxx
CLICKUP_LIST_ID=123456789
node server.js
monitor_licitacoesv2.py (detecta nova licitação)
↓
server.js (backend)
↓
API ClickUp (cria tarefa)
↓
✅ Tarefa aparece no ClickUp
monitor_licitacoes/
│
├── 📄 monitor_licitacoesv2.py ⭐ Script principal
├── 📄 server.js ⭐ Backend opcional
├── 📄 identificar_cidades.py Identificar cidades por distância
├── 📄 shpforcsv.py Converter shapefile para CSV
├── 📄 csvforjson.py Converter CSV para JSON
├── 📄 conversao_conlicitacoes.py Converter licitações
│
├── .gitignore Configurações do Git
├── .env.example Template de variáveis
├── requirements.txt Dependências Python
├── package.json Dependências Node.js
├── readme.md 📖 Este arquivo
│
├── data/ 📁 Dados gerados (JSON)
│ ├── .gitkeep
│ └── (boletins_*.json, etc)
│
├── licitacoes_xlsx/ 📁 Planilhas geradas
│ ├── .gitkeep
│ └── xlsx_processados/
│ └── .gitkeep
│
└── malhas_municipais/ 📁 Dados geográficos
├── Bahia/
│ ├── BA_Municipios_2024.shp Arquivo shapefile
│ ├── BA_Municipios_2024.dbf
│ ├── BA_Municipios_2024.shx
│ ├── municipios_Bahia.csv CSV de referência
│ └── (mais arquivos shapefile)
│
└── Sergipe/
├── SE_Municipios_2024.shp
└── municipios_Sergipe.csv
Explicação de Diretórios:
| Diretório | Propósito |
|---|---|
data/ |
Armazena JSONs com licitações capturadas |
licitacoes_xlsx/ |
Armazena exportações em XLSX |
malhas_municipais/ |
Dados geográficos (shapefiles, municipios) |
identificar_cidades.py?Este script identifica automaticamente todas as cidades dentro de um raio específico a partir de uma cidade sede. Permite buscar em múltiplos estados simultaneamente, perfeito para monitorar oportunidades de licitação em uma região geográfica.
Abra o arquivo identificar_cidades.py e configure:
ESTADO_SEDE = 'Bahia'
NOME_CIDADE_SEDE = 'Serrinha'
Um único estado:
ESTADOS_ALVO = ['Sergipe']
Múltiplos estados:
ESTADOS_ALVO = ['Sergipe', 'Bahia', 'SaoPaulo']
RAIO_MIN_KM = 5 # Distância mínima
RAIO_MAX_KM = 400 # Distância máxima
LIMITE_CIDADES = None # Sem limite (todas as cidades)
# ou
LIMITE_CIDADES = 50 # Apenas 50 cidades mais próximas
Para cada estado que você quer buscar, DEVE existir esta estrutura:
malhas_municipais/
├── Bahia/
│ └── municipios_Bahia.csv
├── Sergipe/
│ └── municipios_Sergipe.csv
└── SaoPaulo/
└── municipios_SaoPaulo.csv
Cada arquivo CSV DEVE conter estas colunas:
CD_MUN - Código IBGE do municípioNM_MUN - Nome do municípiolatitude - Latitudelongitude - LongitudeExemplo:
CD_MUN,NM_MUN,latitude,longitude
2930501,Serrinha,-11.665667104222422,-38.99379057060335
2930105,Salvador,-12.971388888888889,-38.501666666666665
# Ativar ambiente
.\venv\Scripts\Activate.ps1
# Executar
python identificar_cidades.py
O script cria:
malhas_municipais/cidades_alvo_consolidado.csv
Contém: codigo_ibge, nome_municipio, estado, distancia
malhas_municipais/Sergipe/cidades_alvo.csv
malhas_municipais/Bahia/cidades_alvo.csv
Contém: codigo_ibge, nome_municipio
P: E se colocar um estado que não tem arquivo CSV?
R: O script detecta, mostra um aviso e continua com os outros estados:
⚠️ AVISO: Arquivo não encontrado. Pulando estado SaoPaulo.
P: Posso adicionar novos estados depois?
R: Sim! Basta:
malhas_municipais/<ESTADO>/municipios_<ESTADO>.csv com as colunas corretasESTADOS_ALVOP: Posso usar a mesma cidade sede em estado diferente do alvo?
R: SIM! Esse é exatamente o propósito:
Exemplo 1: Apenas Sergipe
ESTADO_SEDE = 'Bahia'
NOME_CIDADE_SEDE = 'Serrinha'
ESTADOS_ALVO = ['Sergipe']
RAIO_MIN_KM = 5
RAIO_MAX_KM = 400
Exemplo 2: Múltiplos Estados
ESTADOS_ALVO = ['Sergipe', 'Bahia', 'Pernambuco']
Exemplo 3: Apenas 50 Cidades Mais Próximas
ESTADOS_ALVO = ['Sergipe', 'Bahia', 'Pernambuco']
RAIO_MIN_KM = 5
RAIO_MAX_KM = 500
LIMITE_CIDADES = 50
O script valida:
ModuleNotFoundError: No module named 'requests'Solução:
pip install -r requirements.txt
ModuleNotFoundError: No module named 'dotenv'Solução:
pip install python-dotenv
Possíveis causas:
.env estão corretas e em minúsculasGRUPO_SERVICO e GRUPO_CONTEXTOGRUPO_EXCLUSAO.env não existe
cp .env.example .env
# Edite o .env com seus valores
.env está na raiz do projetoGRUPO_SERVICO, GRUPO_CONTEXTO e GRUPO_EXCLUSAO estão definidasComo testar seus filtros:
# Ative o ambiente
.\venv\Scripts\Activate.ps1
# Execute o monitor e observe as mensagens
python monitor_licitacoesv2.py
FileNotFoundError: .envSolução:
pip install -r requirements.txt
FileNotFoundError: .envSolução:
cp .env.example .env
# Editar .env com seus valores
Solução:
Solução:
CLICKUP_TOKEN está corretoCLICKUP_LIST_ID é válidonode server.jsSolução:
malhas_municipais/<ESTADO>/python shpforcsv.py para converteridentificar_cidades.py gera cidades_alvo.csv| Recurso | Link |
|---|---|
| Portal PNCP | https://pncp.gov.br |
| Documentação API PNCP | https://www.gov.br/pncp/pt-br/central-de-conteudo/manuais |
| ClickUp API | https://clickup.com/api |
| Biblioteca Geopy | https://geopy.readthedocs.io |
| IBGE Dados Municipais | https://www.ibge.gov.br |
| Python Documentation | https://docs.python.org |
| Express.js Guide | https://expressjs.com |
# Ativar ambiente
.\venv\Scripts\Activate.ps1
# Executar primeira busca
python monitor_licitacoesv2.py
# Verificar resultados em data/
# Editar .env com seus tokens
code .env
# Iniciar servidor
node server.js
# Em outro terminal, rodar monitor
python monitor_licitacoesv2.py
# Converter dados para Excel
python csvforjson.py
# Arquivo estará em licitacoes_xlsx/
Este projeto está licenciado sob a MIT License - veja o arquivo LICENSE para detalhes.
Desenvolvido por rodrigochavesoa
Contribuições são bem-vindas! Para reportar bugs ou sugerir melhorias:
git checkout -b feature/MinhaFeature)git commit -m 'Adiciona MinhaFeature')git push origin feature/MinhaFeature)Se este projeto foi útil para você, deixe uma ⭐ no GitHub!
Tem dúvidas? Abra uma Discussion ou Issue
Last Updated: Outubro de 2025
Status: ✅ Ativo e em desenvolvimento
Estrutura dos Arquivos identificar_cidades.py: Script para encontrar as cidades-alvo.
monitor_licitacoesv2.py: Script principal que busca as licitações.
municipios_bahia.csv: Arquivo de dados com o nome e as coordenadas de todos os municípios da Bahia.
requirements.txt: Lista de bibliotecas Python necessárias.
cidades_alvo.txt: (Gerado) Arquivo com a lista das cidades a serem monitoradas.
licitacoes_encontradas_*.csv: (Gerado) Relatório com as licitações encontradas.