Fazendo download dos dados¶

In [1]:
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]
In [2]:
#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% |########################################################################|
Out[2]:
('raw/test.zip', <http.client.HTTPMessage at 0x162f0445180>)
In [3]:
# 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% |########################################################################|
In [4]:
# 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]
In [5]:
#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)

Explorando os dados¶

In [6]:
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
Out[6]:
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

In [7]:
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])\
In [8]:
df_list['Motivos'].head()
Out[8]:
descricao
codigo
0 SEM MOTIVO
1 EXTINCAO POR ENCERRAMENTO LIQUIDACAO VOLUNTARIA
2 INCORPORACAO
3 FUSAO
4 CISAO TOTAL
In [9]:
df_list['Empresas0'].head()
Out[9]:
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
In [10]:
df_list['Naturezas'].head()
Out[10]:
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)
In [11]:
merge_test = df_list['Empresas0'].merge(df_list['Naturezas'],left_on='natureza',right_on='codigo',validate='many_to_one')
merge_test.head()
Out[11]:
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

In [12]:
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?"

In [13]:
merge_test.groupby('descricao').size()
Out[13]:
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

In [14]:
merge_test.groupby('descricao').size().sort_values(ascending=False).head(10).iloc[::-1].plot.barh();
Out[14]:
<Axes: ylabel='descricao'>

Verificando o número de empresas de natureza "Empresário (Individual)"

In [15]:
merge_test.groupby('descricao').size()['Empresário (Individual)']
Out[15]:
9587003

Continuação (a terminar)¶

In [ ]: