from progressbar import ProgressBar
from urllib.request import urlretrieve
from tqdm import tqdm
import os
import zipfile
# Obtendo dados públicos CNPJ do URL:
url = "https://dadosabertos.rfb.gov.br/CNPJ/"
# Fazendo download de alguns arquivos compactados
nomes_arquivos = ['Cnaes','Empresas0','Estabelecimentos0','Motivos',\
'Municipios','Naturezas','Paises','Qualificacoes','Simples','Socios0']
url_arquivos = [url+nome+'.zip' for nome in nomes_arquivos]
#https://stackoverflow.com/questions/37748105/how-to-use-progressbar-module-with-urlretrieve
pbar = None
def show_progress(block_num, block_size, total_size):
global pbar
if pbar is None:
pbar = ProgressBar(maxval=total_size)
pbar.start()
downloaded = block_num * block_size
if downloaded < total_size:
pbar.update(downloaded)
else:
pbar.finish()
pbar = None
# Pasta para armazenar dados brutos compactados
if not os.path.exists('raw'):
os.makedirs('raw')
# Testando obtenção dos dados
print('Download: '+nomes_arquivos[0])
urlretrieve(url_arquivos[0], 'raw/test.zip', show_progress)
Download: Cnaes
100% |########################################################################|
('raw/test.zip', <http.client.HTTPMessage at 0x162f0445180>)
# Obtenção parcial da base de dados, tamanho aproximado: 1.5 GB, tempo aproximado: 1 hora
for k,url in enumerate(url_arquivos):
print('Download: '+nomes_arquivos[k])
urlretrieve(url, 'raw/'+nomes_arquivos[k]+'.zip', show_progress)
Download: Cnaes
100% |########################################################################|
Download: Empresas0
100% |########################################################################|
Download: Estabelecimentos0
100% |########################################################################|
Download: Motivos
100% |########################################################################|
Download: Municipios
100% |########################################################################|
Download: Naturezas
100% |########################################################################|
Download: Paises
100% |########################################################################|
Download: Qualificacoes
100% |########################################################################|
Download: Simples
100% |########################################################################|
Download: Socios0
100% |########################################################################|
# Pasta para armazenar dados brutos
if not os.path.exists('csv'):
os.makedirs('csv')
# Extraindo (zip -> csv), tamanho aproximado: 7 GB
for nome in nomes_arquivos:
print('Arquivo: '+nome)
with zipfile.ZipFile('raw/'+nome+'.zip') as zf:
for arquivo in tqdm(zf.infolist(), desc='Extraindo'):
try:
zf.extract(arquivo, 'csv/'+nome)
except zipfile.error as e:
pass
Arquivo: Cnaes
Extraindo: 100%|██████████| 1/1 [00:00<00:00, 1000.55it/s]
Arquivo: Empresas0
Extraindo: 100%|██████████| 1/1 [00:07<00:00, 7.50s/it]
Arquivo: Estabelecimentos0
Extraindo: 100%|██████████| 1/1 [00:40<00:00, 40.42s/it]
Arquivo: Motivos
Extraindo: 100%|██████████| 1/1 [00:00<00:00, 27.96it/s]
Arquivo: Municipios
Extraindo: 100%|██████████| 1/1 [00:00<00:00, 1032.06it/s]
Arquivo: Naturezas
Extraindo: 100%|██████████| 1/1 [00:00<00:00, 80.35it/s]
Arquivo: Paises
Extraindo: 100%|██████████| 1/1 [00:00<00:00, 333.41it/s]
Arquivo: Qualificacoes
Extraindo: 100%|██████████| 1/1 [00:00<00:00, 499.44it/s]
Arquivo: Simples
Extraindo: 100%|██████████| 1/1 [00:20<00:00, 20.64s/it]
Arquivo: Socios0
Extraindo: 100%|██████████| 1/1 [00:07<00:00, 7.88s/it]
#Renomeando
for nome in nomes_arquivos:
nome_antigo = os.listdir('csv/'+nome)[0]
os.rename('csv/'+nome+'/'+nome_antigo,'csv/'+nome+'.csv')
os.removedirs('csv/'+nome)
import pandas as pd
#Seguindo o dicionário de dados:
#https://www.gov.br/receitafederal/dados/cnpj-metadados.pdf
test_csv = pd.read_csv('csv/Cnaes.csv', index_col=0, sep=';', encoding='latin1', header=None,\
names=['CÓDIGO','DESCRIÇÃO'])
test_csv
| DESCRIÇÃO | |
|---|---|
| CÓDIGO | |
| 111301 | Cultivo de arroz |
| 111302 | Cultivo de milho |
| 111303 | Cultivo de trigo |
| 111399 | Cultivo de outros cereais não especificados an... |
| 112101 | Cultivo de algodão herbáceo |
| ... | ... |
| 9609208 | Higiene e embelezamento de animais domésticos |
| 9609299 | Outras atividades de serviços pessoais não esp... |
| 9700500 | Serviços domésticos |
| 9900800 | Organismos internacionais e outras instituiçõe... |
| 8888888 | Atividade Econônica não informada |
1359 rows × 1 columns
dic_dados = {
'Empresas0' :['cnpj_basico', 'razao', 'natureza', 'qualific','capital','porte','ente'],
'Estabelecimentos0' :['cnpj_basico','cnpj_ordem','cnpj_dv','id_matriz','nome_fantasia','sit_cadast','data_cadast','motivo_cadast','nome_cidade_ext','pais','data_inicio','cnae_principal','cnae_secundaria','tipo_logradouro','logradouro','numero','complemento','bairro','cep','uf','municipio','DDD_1','tel_1','DDD_2','tel_2','DDD_fax','fax','email','sit_especial','data_sit_especial'],
'Simples' :['cnpj_basico','opcao_simples','data_opcao','data_exclusao','opcao_mei','data_opcao_mei','data_exclusao_mei'],
'Socios0' :['cnpj_basico','id_socio','nome_socio','CNPJ/CPF','qual_socio','data_entrada','pais','rep_legal','nome_rep_legal','qual_rep_legal','faixa_etaria'],
'Paises' :['codigo','descricao'],
'Municipios' :['codigo','descricao'],
'Qualificacoes' :['codigo','descricao'],
'Naturezas' :['codigo','descricao'],
'Cnaes' :['codigo','descricao'],
'Motivos' :['codigo','descricao']
}
df_list = {nome:pd.read_csv('csv/'+nome+'.csv', index_col=0, sep=';', encoding='latin1', header=None, names=dic_dados[nome])\
for nome in nomes_arquivos}
C:\Users\Victor\AppData\Local\Temp\ipykernel_364\3308030666.py:13: DtypeWarning: Columns (8,21,22,24,26,28) have mixed types. Specify dtype option on import or set low_memory=False.
df_list = {nome:pd.read_csv('csv/'+nome+'.csv', index_col=0, sep=';', encoding='latin1', header=None, names=dic_dados[nome])\
df_list['Motivos'].head()
| descricao | |
|---|---|
| codigo | |
| 0 | SEM MOTIVO |
| 1 | EXTINCAO POR ENCERRAMENTO LIQUIDACAO VOLUNTARIA |
| 2 | INCORPORACAO |
| 3 | FUSAO |
| 4 | CISAO TOTAL |
df_list['Empresas0'].head()
| razao | natureza | qualific | capital | porte | ente | |
|---|---|---|---|---|---|---|
| cnpj_basico | ||||||
| 41273594 | OZINETE DELFINO CALDAS 41608224287 | 2135 | 50 | 5000,00 | 1.0 | NaN |
| 41273595 | GILVAN PEREIRA XAVIER 01363090380 | 2135 | 50 | 3000,00 | 1.0 | NaN |
| 41273596 | RODRIGO JOSE FERREIRA LOPES 05010247941 | 2135 | 50 | 10000,00 | 1.0 | NaN |
| 41273597 | PACHARRUS QUEIROZ DA COSTA E SILVA 03618384335 | 2135 | 50 | 5000,00 | 1.0 | NaN |
| 41273598 | GLORIA VIANA DIAS DA SILVA 13118961716 | 2135 | 50 | 1100,00 | 1.0 | NaN |
df_list['Naturezas'].head()
| descricao | |
|---|---|
| codigo | |
| 0 | Natureza Jurídica não informada |
| 3271 | Órgão de Direção Local de Partido Político |
| 3280 | Comitê Financeiro de Partido Político |
| 3298 | Frente Plebiscitária ou Referendária |
| 3301 | Organização Social (OS) |
merge_test = df_list['Empresas0'].merge(df_list['Naturezas'],left_on='natureza',right_on='codigo',validate='many_to_one')
merge_test.head()
| razao | natureza | qualific | capital | porte | ente | descricao | |
|---|---|---|---|---|---|---|---|
| 0 | OZINETE DELFINO CALDAS 41608224287 | 2135 | 50 | 5000,00 | 1.0 | NaN | Empresário (Individual) |
| 1 | GILVAN PEREIRA XAVIER 01363090380 | 2135 | 50 | 3000,00 | 1.0 | NaN | Empresário (Individual) |
| 2 | RODRIGO JOSE FERREIRA LOPES 05010247941 | 2135 | 50 | 10000,00 | 1.0 | NaN | Empresário (Individual) |
| 3 | PACHARRUS QUEIROZ DA COSTA E SILVA 03618384335 | 2135 | 50 | 5000,00 | 1.0 | NaN | Empresário (Individual) |
| 4 | GLORIA VIANA DIAS DA SILVA 13118961716 | 2135 | 50 | 1100,00 | 1.0 | NaN | Empresário (Individual) |
Verificando o tamanho das maiores dataframes
df_list['Estabelecimentos0'].info()
<class 'pandas.core.frame.DataFrame'> Int64Index: 14785878 entries, 17770083 to 51788350 Data columns (total 29 columns): # Column Dtype --- ------ ----- 0 cnpj_ordem int64 1 cnpj_dv int64 2 id_matriz int64 3 nome_fantasia object 4 sit_cadast int64 5 data_cadast int64 6 motivo_cadast int64 7 nome_cidade_ext object 8 pais float64 9 data_inicio int64 10 cnae_principal int64 11 cnae_secundaria object 12 tipo_logradouro object 13 logradouro object 14 numero object 15 complemento object 16 bairro object 17 cep float64 18 uf object 19 municipio int64 20 DDD_1 object 21 tel_1 object 22 DDD_2 float64 23 tel_2 object 24 DDD_fax float64 25 fax object 26 email object 27 sit_especial object 28 data_sit_especial float64 dtypes: float64(5), int64(9), object(15) memory usage: 3.3+ GB
Podemos ver mais de 3.3+ GB e com 15 milhões de linhas! E isso obtido de uma base de dados parcial! Pandas é poderoso! Podemos reparar que Pandas conseguiu inferir os tipos de cada campo.
Vamos responder a seguinte pergunta: "Como é a distribuição das naturezas jurídicas entre as empresas?"
merge_test.groupby('descricao').size()
descricao
Associação Privada 211395
Autarquia Estadual ou do Distrito Federal 105
Autarquia Federal 144
Autarquia Municipal 406
Candidato a Cargo Político Eletivo 29657
...
Órgão Público do Poder Legislativo Estadual ou do Distrito Federal 9
Órgão Público do Poder Legislativo Municipal 1242
Órgão de Direção Local de Partido Político 2252
Órgão de Direção Nacional de Partido Político 24
Órgão de Direção Regional de Partido Político 107
Length: 79, dtype: int64
Pegando as 10 maiores, podemos representar visualmente em um gráfico de barra
merge_test.groupby('descricao').size().sort_values(ascending=False).head(10).iloc[::-1].plot.barh();
<Axes: ylabel='descricao'>
Verificando o número de empresas de natureza "Empresário (Individual)"
merge_test.groupby('descricao').size()['Empresário (Individual)']
9587003