Oi pessoal, boa tarde.
Baixei os dados do CAFIR na Receita Federal e apesar de que no site indicam como arquivo csv, quando faço o download são 10 arquivos K3243.K34313DP.D21223.PARTE01 , …02 , 03… .
Como faço pra unir os arquivos e converter pra csv?
Desde já agradeço.
Dei uma olhada no dataset e parece ser um arquivo de colunas com largura fixa. Os nomes e larguras das colunas estão documentados no dicionário de dados. Dá um pouco de trabalho para ler, em comparação com csv, mas não é nada de outro mundo. Para concatenar os arquivos, também depende de que ferramenta / linguagem você está usando.
Se você estiver usando Python, o Pandas tem o método pandas.read_fwf
para isso. Para concatenar os dataframes lidos de cada arquivo, tem o pandas.concat
.
Sim, estou usando (aprendendo) o Python. Que tipo de arquivo é esse? Obrigado!
São arquivos texto tabulares, onde cada coluna tem uma largura determinada de caracteres. Então, quando vistos em um editor de texto, as colunas aparecem alinhadas.
Pesquise por “fixed width file”. Segue um texto explicando como usar no Pandas.
Muito bom, obrigado.
Com este código você conseguirá ler todas as planilhas:
import pandas as pd
URL_BASE = "https://dadosabertos.rfb.gov.br/CAFIR/K3243.K34313DP.D21223"
arquivos = [f"{URL_BASE}.PARTE{parte:02}" for parte in range(1, 11)]
dfs = [pd.read_fwf(url, encoding="iso-8859-1", widths=[8,9,13,55,2,56,40,2,40,8,1,8,1]) for url in arquivos]
for numero, df in enumerate(dfs):
print(f"processando arquivo {numero + 1}...")
# reinsere a primeira linha, que o pandas interpreta como nome das colunas
df.loc[-1] = df.columns
df.index = df.index + 1
df.sort_index(inplace=True)
df.columns = [
"NR-IMOVEL",
"AREA-TOTAL",
"NR-INCRA",
"NOME-IMOVEL",
"SIT-IMOVEL",
"ENDEREÇO",
"DISTRITO",
"UF",
"MUNICÍPIO",
"CEP",
"CD-IMUNE",
"DT-INSCRIÇÃO",
"SNCR",
]
cafir = pd.concat(dfs)
cafir.to_csv("cafir.csv", index=False)
Obs.: o download dos arquivos vai demorar bastante e vai consumir muita memória da sua máquina, pois o total tem quase 2 GB.
Onde ele salva os arquivos? Rodei o código e ele depois de processar os arquivos retorna dois erros: Traceback(most recennt call last) e No objects to concatenate
Não chegou a salvar porque deu erro antes. Como o download é muito demorado, eu tinha testado apenas com 1 arquivo. Corrigi o código lá, foi só trocar os parênteses por colchetes, para dfs
ser uma lista em vez de ser um gerador. Só que agora a linha que vai demorar é essa onde é criada a variável dfs
, pois é quando ele vai fazer todos os downloads.
Deu certo, só que o arquivo cafir.csv ficou com pouco mais de 1gb.
Estava pensando em fazer uma api com esses dados e disponibilizar pro público (tudo open source), só que estou com algumas dúvidas referente à última coluna:
No layout, tá especificado que ela corresponde ao SNCR, não sei o que essa sigla representa, mas pode assumir quatro diferentes valores:
- VINCULACAO PROVISORIA REALIZADA;
- VINCULACAO CONFIRMADA;
- DESVINCULADO;
- DESCARACTERIZACAO DE DESTINACAO RURAL;
O problema é que, no dataset, esse campo só assume dois valores: “A” e “I”. Alguém sabe o que isso significa?
Ademais, como pretendo fazer uma CI/CD para todo o processo (principalmente para os testes), fiz um script (shell) para rodar na pipeline que só precisa do curl e baixa e trata os dados automaticamente para csv, óbvio que com uma footprint bem menor que usando o python e pandas KKKKK, também não gostaria de introduzir mais uma dependência. Vou compartilhar ele aqui, e, se for usar, acho que precisa provisionar uma máquina com no mínimo 228M de mémoria (tamanho dos arquivos).
#!/usr/bin/env bash
set -eo pipefail
# Check if curl is installed
if ! [ -x "$(command -v curl)" ]; then
echo >&2 "Error: curl is not installed."
exit 1
fi
BASE_URL="https://dadosabertos.rfb.gov.br/CAFIR/K3243.K34313DP.D21223"
for i in $(seq -w 10);
do
echo >&2 "Processing file ${i}"
# Download the file
curl "${BASE_URL}.PARTE${i}" \
# Pipe into awk, separating the fixed width fields using ";" as the separator
| awk -v FIELDWIDTHS="8 9 13 55 2 56 40 2 40 8 1 8 1" -v OFS=";" '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13}' \
# Regex to remove whitespace between the separators
| sed 's/ *; */;/g' \
# Append to cafir.csv
>> cafir.csv
done
>&2 echo "The CAFIR data has been treated, ready to go!"
Exemplo dos dados processados:
$ head -10 cafir.csv
00000027;000013000;;FAZENDDA AGUA LIMPA;02;BR 401- KM 85 REGIAO DO TUCANO;;RR;BONFIM;69380000;2;0180528N;A
00000175;000000977;;FAZENDA CURRAIS NOVOS - LOTE 46,35;02;LOTE 46, GLEBA 35, PAD MAL DUTRA, LINHA C-35;ZONA RURAL;RO;ARIQUEMES;76870192;2;0210331N;A
00000299;000001087;0010311067120;SITIO PRIMAVERA;02;LT 16 GL 30 PAD MAL DUTRA;;RO;ARIQUEMES;76870001;2;0210331N;A
00000418;000000735;9500331778066;SITIO ALVORADA 14/A E 16/B GLEBA 35 PAD MAL DUTRA;02;LOTES 14/A E 16/B GLEBA 35PAD MAL DUTRA;ZONA RURAL;RO;ARIQUEMES;76870001;2;0210331N;A
00000566;000000986;;SITIO CEU AZUL;02;LOTE 74, GLEBA 11, LINHA C -100;ZONA RURAL;RO;RIO CRESPO;76863000;2;0200724S;I
00000701;000000897;;SITIO RONDONIA;02;LOTE 33 C GLEBA 35/B PAD MARECHAL DUTRA;;RO;ARIQUEMES;76870970;2;0200724N;A
00000833;000000855;;SITIO BEIRA RIO;02;LINHA T4 LOTE 54 GL 14, ST SAO MIGUEL;ZONA RURAL;RO;SAO MIGUEL DO GUAPORE;76932000;2;0200724N;A
00000965;000000350;;SITIO BOA VISTA;02;LOTE 154 - GLEBA 01 - PA NOVA CONQUISTA;;RO;VILHENA;76980002;2;0200724S;I
00001066;000000981;;SITIO BOM JESUS;02;LOTE 171, SETOR TENENTE MARQUES;;RO;VILHENA;76980002;2;0200724N;A
00001180;000000400;;SITIO SAO LUIZ;02;LT 68 GL 10 LH 86 NORTE KM 06 ST SAO MIGUEL;;RO;SAO MIGUEL DO GUAPORE;76932000;2;0200724N;A
No final, o tamanho do arquivo é de 1,02G:
$ ls -l cafir.csv
-rw-r--r-- 1 user user 1098167058 Jan 28 18:15 cafir.csv
EDIT: comentei o arquivo
Boa tarde, SNCR é o sistema nacional de cadastro rural. Todo imóvel rural tem que fazer a inscrição ou atualização do sncr pela plataforma dcr para emitir o ccir. Esses cadastros são do INCRA
Feito isso tem que ser feita a vinculaçao do sncr(ccir) ao cib(antigo nirf) no cnir(cadastro nacional de imóveis rurais).
O cib é da receita Federal.
Obrigado por esclarificar, mas até agora não entendi o que os valores “A” e “I” desse campo representam.
Também vale ressaltar que os campos que esses valores não são “A” ou “I” (os outros valores possíveis são “O”, letra o, não 0, ou “1”) estão mal formatados, exemplo:
$ grep "[^AI]$" cafir.csv | head -10
00508268;000001053;1120620209405;FAZENDA CAMPESTRE;02;ESTRADA PALMA A LUSTRãO;M;AP;RESIDENTE DUTRA 6;57600002;0;210331NA;O
01897780;000000053;5030290089152;SITIO SANTO QUATO;02;CORREGO DO DEZ - A 2 KM DE VINHáTICO;E;SM;ONTANHA 2;98900002;0;210331NA;O
02109328;000000226;5041140164115;SíTIO STUHR 0;21;KM ANTES DO COMERCIO DE VITORINO KOSANKE;E;SS;ANTA MARIA DE JETIBA 2;96450002;0;210331NA;O
02279070;000000280;5060520063278;SITIO DAS PEDRAS;02;CóRREGO SANTA CLARA;E;SI;BATIBA 2;93950002;0;210331NA;O
02438860;000000513;6290654976309;SíTIO MARINA 0;2E;STRADA BOTUCATU-FAZENDA MONTE ALEGRE KM 14;S;PB;OTUCATU 1;86000012;0;210331NA;O
02519135;000000518;6281580021787;FAZENDA SANTA LUZIA;02;ESTRADA TEJUPá A TAQUARITUBA, KM 12;S;PT;EJUPA 1;88300012;0;210802NA;O
02627671;000000081;6250860159706;SíTIO BOTACIM 0;2B;AIRRO DAS LAVRAS DE BAIXO;S;PS;OCORRO 1;39600002;0;210331NA;O
02683482;000001067;6340340222099;SITIO SANTA IZABEL 0;2R;ODOVIA BRAGANCA - AMPARO KM 10 BAIRRO RIO ABAIXO;S;PB;RAGANCA PAULISTA 1;29000022;0;210331NA;O
02821885;000000056;6250780083385;SITIO SAO JOSé 0;2B;AIRRO DAS TRES BARRAS;S;PS;ERRA NEGRA 1;39300002;0;210331NA;O
02959313;000001412;6240200047667;SíTIO POROMBO - GLEBA C 0;2R;ODOVIA WILSON FINARDI (SP 191), KM 34;S;PA;RARAS 1;36000012;0;210331NA;O
A razão disso é que esses campos tem caracteres que não são ascii, então acho que realmente só pode os valores A ou I e o resto da linha tá sendo cortada.
Depois vou tentar concertar essas linhas, mas são poucas.
Descibri esse problema, o layout está errado, o campo DT-INSCRICAO tem 7, não 8 caracteres, e o último campo não tem 1, ele tem 4 ou são na verdade dois campos KKKKK. Exemplo:
$ curl https://dadosabertos.rfb.gov.br/CAFIR/K3243.K34313DP.D21223.PARTE01 | head -10
00000027000013000 FAZENDDA AGUA LIMPA 02BR 401- KM 85 REGIAO DO TUCANO RRBONFIM 6938000020180528NAO3
00000175000000977 FAZENDA CURRAIS NOVOS - LOTE 46,35 02LOTE 46, GLEBA 35, PAD MAL DUTRA, LINHA C-35 ZONA RURAL ROARIQUEMES 7687019220210331NAO3
000002990000010870010311067120SITIO PRIMAVERA 02LT 16 GL 30 PAD MAL DUTRA ROARIQUEMES 7687000120210331NAO1
000004180000007359500331778066SITIO ALVORADA 14/A E 16/B GLEBA 35 PAD MAL DUTRA 02LOTES 14/A E 16/B GLEBA 35PAD MAL DUTRA ZONA RURAL ROARIQUEMES 7687000120210331NAO1
00000566000000986 SITIO CEU AZUL 02LOTE 74, GLEBA 11, LINHA C -100 ZONA RURAL RORIO CRESPO 7686300020200724SIM3
00000701000000897 SITIO RONDONIA 02LOTE 33 C GLEBA 35/B PAD MARECHAL DUTRA ROARIQUEMES 7687097020200724NAO3
00000833000000855 SITIO BEIRA RIO 02LINHA T4 LOTE 54 GL 14, ST SAO MIGUEL ZONA RURAL ROSAO MIGUEL DO GUAPORE 7693200020200724NAO3
00000965000000350 SITIO BOA VISTA 02LOTE 154 - GLEBA 01 - PA NOVA CONQUISTA ROVILHENA 7698000220200724SIM3
00001066000000981 SITIO BOM JESUS 02LOTE 171, SETOR TENENTE MARQUES ROVILHENA 7698000220200724NAO3
00001180000000400 SITIO SAO LUIZ 02LT 68 GL 10 LH 86 NORTE KM 06 ST SAO MIGUEL ROSAO MIGUEL DO GUAPORE 7693200020200724NAO3
Esse campo é NAO/SIM + 1 a 4. Ou na verdade são dois campos e não sei pra que serve o NAO ou SIM.
EDIT: eu não posso fazer mais nenhum comentário porque membros novos estão limitados a 3 respostas em um thread. Então minha resposta a mensagem abaixo tá aqui:
Achei o que significa isso em um pdf no site da câmara. Na página 4 tem o valor correto de todas as colunas, sendo que esse SIM/NAO representa CD-IMUNIDADE. Acredito que esse CD-IMUNIDADE corresponde à necessidade de pegar o imposto da propriedade.
Esse é o meu script atualizado, que também corrige o erro das caracteres unicode serem mais que uma caractere na conta do layout:
#!/usr/bin/env bash
set -eo pipefail
if ! [ -x "$(command -v curl)" ]; then
echo >&2 "Error: curl is not installed."
exit 1
fi
if ! [ -x "$(command -v awk)" ]; then
echo >&2 "Error: awk is not installed."
exit 1
fi
BASE_URL="https://dadosabertos.rfb.gov.br/CAFIR/K3243.K34313DP.D21223"
for i in $(seq -w 10);
do
echo >&2 "Processing file ${i}"
curl "${BASE_URL}.PARTE${i}" \
| awk -b -v FIELDWIDTHS="8 9 13 55 2 56 40 2 40 8 8 3 1" -v OFS=";" '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13}' \
| sed 's/ *; */;/g' \
>> cafir.csv
done
>&2 echo "The CAFIR data has been treated, ready to go!"
Com isso, o arquivo fica:
$ head -10 cafir.csv
00000027;000013000;;FAZENDDA AGUA LIMPA;02;BR 401- KM 85 REGIAO DO TUCANO;;RR;BONFIM;69380000;20180528;NAO;3
00000175;000000977;;FAZENDA CURRAIS NOVOS - LOTE 46,35;02;LOTE 46, GLEBA 35, PAD MAL DUTRA, LINHA C-35;ZONA RURAL;RO;ARIQUEMES;76870192;20210331;NAO;3
00000299;000001087;0010311067120;SITIO PRIMAVERA;02;LT 16 GL 30 PAD MAL DUTRA;;RO;ARIQUEMES;76870001;20210331;NAO;1
00000418;000000735;9500331778066;SITIO ALVORADA 14/A E 16/B GLEBA 35 PAD MAL DUTRA;02;LOTES 14/A E 16/B GLEBA 35PAD MAL DUTRA;ZONA RURAL;RO;ARIQUEMES;76870001;20210331;NAO;1
00000566;000000986;;SITIO CEU AZUL;02;LOTE 74, GLEBA 11, LINHA C -100;ZONA RURAL;RO;RIO CRESPO;76863000;20200724;SIM;3
00000701;000000897;;SITIO RONDONIA;02;LOTE 33 C GLEBA 35/B PAD MARECHAL DUTRA;;RO;ARIQUEMES;76870970;20200724;NAO;3
00000833;000000855;;SITIO BEIRA RIO;02;LINHA T4 LOTE 54 GL 14, ST SAO MIGUEL;ZONA RURAL;RO;SAO MIGUEL DO GUAPORE;76932000;20200724;NAO;3
00000965;000000350;;SITIO BOA VISTA;02;LOTE 154 - GLEBA 01 - PA NOVA CONQUISTA;;RO;VILHENA;76980002;20200724;SIM;3
00001066;000000981;;SITIO BOM JESUS;02;LOTE 171, SETOR TENENTE MARQUES;;RO;VILHENA;76980002;20200724;NAO;3
00001180;000000400;;SITIO SAO LUIZ;02;LT 68 GL 10 LH 86 NORTE KM 06 ST SAO MIGUEL;;RO;SAO MIGUEL DO GUAPORE;76932000;20200724;NAO;3
Tamanho de 1,04G:
-rw-r--r-- 1 user user 1117158000 Jan 28 21:02 cafir.csv
Será que o sim e não é referente ao imóvel estar com sncr e cib vinculados ao cnir?
ajustei para quem já baixou
import pandas as pd
arquivos = [f"K3243.K34313DP.D21223.PARTE{parte:02}" for parte in range(1, 11)]
dfs = [pd.read_fwf(url, encoding="iso-8859-1", widths=[8,9,13,55,2,56,40,2,40,8,1,8,1]) for url in arquivos]
for numero, df in enumerate(dfs):
print(f"processando arquivo {numero + 1}...")
# reinsere a primeira linha, que o pandas interpreta como nome das colunas
df.loc[-1] = df.columns
df.index = df.index + 1
df.sort_index(inplace=True)
df.columns = [
"NR-IMOVEL",
"AREA-TOTAL",
"NR-INCRA",
"NOME-IMOVEL",
"SIT-IMOVEL",
"ENDEREÇO",
"DISTRITO",
"UF",
"MUNICÍPIO",
"CEP",
"CD-IMUNE",
"DT-INSCRIÇÃO",
"SNCR",
]
cafir = pd.concat(dfs)
cafir.to_csv("cafir.csv", index=False)
Andre, você conseguiu compilar todos esses arquivos em uma só planilha ?
Att,