Extrator único de fontes oficiais SINAPI — transforma os arquivos públicos da Caixa Econômica Federal (PDFs e XLSXs) em JSON estruturado consumível por qualquer sistema, em particular o sinpres-api.
| Fonte da Caixa | Periodicidade | Extrator | Output |
|---|---|---|---|
SINAPI_Referência_YYYY_MM.xlsx |
Mensal | extract_reference.py |
output/reference/*.json |
SINAPI_Manutenções_YYYY_MM.xlsx |
Mensal | extract_maintenances.py |
output/maintenances.json |
SINAPI_Fichas_Especificacao_Tecnica_Insumos.pdf |
Eventual (~anual) | extract_technical_sheets.py |
output/items.json + output/items.csv + output/images/ |
- Python 3.9+
- Dependências:
pip install -r requirements.txt
Os arquivos da Caixa podem ser baixados em https://www.caixa.gov.br/poder-publico/modernizacao-gestao/sinapi/
Coloque os arquivos baixados da Caixa em input/ mantendo os nomes oficiais:
input/
├── SINAPI_Referência_AAAA_MM.xlsx (obrigatório)
├── SINAPI_Manutenções_AAAA_MM.xlsx (opcional — pula se ausente)
└── SINAPI_Fichas_Especificacao_Tecnica_Insumos.pdf (opcional, ~anual)
Depois rode passando só o mês de referência:
python3 src/extract_all.py 2026-04Para pular o PDF de fichas técnicas (que muda raramente, ~1x por ano):
python3 src/extract_all.py 2026-04 --skip-pdfA pasta input/ está no .gitignore — você pode jogar os arquivos da Caixa lá sem se preocupar com versionamento.
# Referência (insumos, composições, analítico)
python3 src/extract_reference.py 2026-04 input/SINAPI_Referência_2026_04.xlsx
# Manutenções (substituições de código)
python3 src/extract_maintenances.py input/SINAPI_Manutenções_2026_04.xlsx
# Fichas técnicas (PDF — eventual, atualiza pouco)
python3 src/extract_technical_sheets.py
# (ou passa um caminho explícito como primeiro argumento)output/
├── reference/
│ ├── metadata.json { reference_month, generated_at, source_file }
│ ├── items_catalog.json [{ code, description, unit }]
│ ├── items_prices.json [{ code, state_code, reference_month, is_desonerated, unit_price }]
│ ├── compositions_catalog.json [{ code, description, unit }]
│ ├── compositions_prices.json [{ code, state_code, reference_month, is_desonerated, base_unit_cost }]
│ └── composition_items.json [{ composition_code, item_type, item_code, description, unit, coefficient }]
├── maintenances.json [{ old_code, new_code, type: 'INPUT' | 'COMPOSITION' }]
├── items.json [{ code, description, unit, technical_standards, general_info, image, source_updated_at }]
├── items.csv mesmo conteúdo de items.json em CSV
└── images/ imagens individuais por código SINAPI (ex: 34.jpeg)
unit_price e base_unit_cost são inteiros em centavos (R$ × 100). Isso evita imprecisão de ponto flutuante e é o formato direto pra gravar em colunas integer no banco do sinpres-api.
Coeficientes em composition_items.json são strings com ponto decimal (ex: "0.250000"). Esse formato preserva precisão e mapeia direto pra coluna numeric(12,6) no Postgres.
O Relatório de Manutenções da Caixa mistura vários tipos de evento (criação, desativação, alteração de descrição, etc.). O extrator extrai apenas substituições explícitas — entradas onde a coluna "Manutenção" carrega o padrão SUBSTITUÍDO PELO CÓDIGO N. Os demais tipos são contados e impressos no log, mas não geram entradas.
No dataset 2026-03, por exemplo, a Caixa não usa substituições explícitas — ela usa DESATIVAÇÃO + CRIAÇÃO pareada. O extrator é defensivo e gera array vazio nesse caso, sem falsos positivos.
| Output | Registros | Tamanho aproximado |
|---|---|---|
items_catalog.json |
4.855 | ~500 KB |
items_prices.json |
191.742 | ~17 MB |
compositions_catalog.json |
10.230 | ~1,3 MB |
compositions_prices.json |
444.854 | ~38 MB |
composition_items.json |
54.529 | ~7 MB |
maintenances.json |
0 a centenas | <100 KB |
Este extrator é uma peça independente. Ele lê fontes oficiais SINAPI (PDF e XLSX) e cospe JSONs estáveis em output/. O que você faz com esses JSONs depois é com você — eles são o contrato público do extractor.
Um dos consumidores conhecidos é o sinpres-api, que copia os JSONs gerados aqui para a sua própria pasta input/ e popula um banco PostgreSQL. Mas o extractor não sabe nada sobre o api e não depende dele — você pode subir os JSONs num bucket S3, mandar pra um data warehouse, abrir no DuckDB, ou qualquer outra coisa.
sinapi-extractor— você está aqui. Gera os JSONs.sinpres-api— API REST pública que consome os JSONs.sinpres-web— frontend público (docs + explorer).
Cada arquivo tem um shape estável que serve como contrato:
| Arquivo | Shape |
|---|---|
output/reference/items_catalog.json |
[{ code, description, unit }] |
output/reference/items_prices.json |
[{ code, state_code, reference_month, is_desonerated, unit_price }] |
output/reference/compositions_catalog.json |
[{ code, description, unit }] |
output/reference/compositions_prices.json |
[{ code, state_code, reference_month, is_desonerated, base_unit_cost }] |
output/reference/composition_items.json |
[{ composition_code, item_type, item_code, description, unit, coefficient }] |
output/maintenances.json |
[{ old_code, new_code, type: 'INPUT' | 'COMPOSITION' }] |
output/items.json |
[{ code, description, unit, technical_standards, general_info, image, source_updated_at }] |
MIT