├── LICENSE
├── README.md
├── dados-publicos-zip
└── copie os arquivos zip da receita nesta pasta.txt
├── dados-publicos
└── aqui os arquivos serão descompactados.txt
├── dados_cnpj_baixa.py
├── dados_cnpj_mysql.py
├── dados_cnpj_postgres.py
└── requirements.txt
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 rictom
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cnpj-mysql
2 | Script em python para carregar os arquivos de cnpj dos dados públicos da Receita Federal em MYSQL e POSTGRESQL. O código é compatível com o layout das tabelas disponibilizadas pela Receita Federal a partir de 2021.
3 |
4 | ## Dados públicos de cnpj no site da Receita:
5 | Os arquivos csv zipados com os dados de CNPJs estão disponíveis em https://dados.gov.br/dados/conjuntos-dados/cadastro-nacional-da-pessoa-juridica---cnpj ou https://arquivos.receitafederal.gov.br/cnpj/dados_abertos_cnpj/ (a partir de 28/10/2024.)
6 |
7 |
8 | ## Pré-requisitos:
9 | Python 3.8;
10 | Bibliotecas pandas, dask, sqlalchemy. Para mysql instalar a biblioteca pymysql. Para postgres usar psycopg2.
11 | Para instalar a biblioteca, use o comando
12 | pip install pymysql
13 | Para postgres, instale psycopg2 (recomenda-se psycopg2-binary para instalação mais simples)
14 | pip install psycopg2-binary (testado no Ubuntu).
15 |
16 | ## Utilizando o script:
17 | Para obter relação dos arquivos disponíveis no site da Receita Federal ou baixar os arquivos, faça o seguinte comando no Anaconda prompt:
18 | python dados_cnpj_baixa.py
19 | Isto irá baixar os arquivos zipados do site da Receita na pasta "dados-publicos-zip".
20 |
21 | ATENÇÃO: Em 14/8/2024 a página de dados abertos foi modificada, o script dados_cnpj_baixa.py foi atualizado para pegar a pasta do mês mais recente.
22 |
23 | Se o download estiverm muito lento, sugiro utilizar um gerenciador de downloads.
24 |
25 | Crie uma pasta com o nome "dados-publicos". Esta pasta deve estar vazia.
26 |
27 | No servidor MYSQL ou POSTGRES, crie um database, por exemplo, cnpj.
28 | Especifique os parâmetros no começo do script:
29 | dbname = 'cnpj'
30 | username = 'root'
31 | password = ''
32 | host = '127.0.0.1'
33 |
34 | Para iniciar esse script, em um console digite
35 | python dados_cnpj_mysql.py
36 | ou
37 | python dados_cnpj_postgres.py
38 |
39 | A execução durou cerca de 5hs em um notebook i7 de 8a geração com Windows 10 no script para mysql.
40 | No caso do postgres, fiz teste só com uma amostra em Linux (Ubuntu 20.4).
41 | Se a execução deste script demorar muito, uma opção é usar o projeto em https://github.com/rictom/cnpj-sqlite para gerar o arquivo em sqlite e usar uma ferramenta como o pgloader ou o DBeaver para converter depois em postgres.
42 | Este colega usou o pgloader com um bom desempenho: https://github.com/rictom/cnpj-mysql/issues/5
43 |
44 | ## Outras referências:
45 |
46 | Para trabalhar com os dados de cnpj no formato SQLITE, use o meu projeto (https://github.com/rictom/cnpj-sqlite).
47 | A criação do arquivo sqlite é muita mais rápida que o carregamento da base em Mysql ou Postgres.
48 | O projeto (https://github.com/rictom/rede-cnpj) utiliza os dados públicos de CNPJ para visualização de relacionamentos entre empresas e sócios.
49 |
50 | ## Histórico de versões
51 | versão 0.2 (janeiro/2022)
52 | - aceita sqlalchemy>=2.0;
53 |
54 | versão 0.2 (julho/2022)
55 | - alterações menores no sql, para funcionar também em postgres;
56 | - versão para postgres.
57 |
58 | versão 0.1 (novembro/2021)
59 | - primeira versão
60 |
--------------------------------------------------------------------------------
/dados-publicos-zip/copie os arquivos zip da receita nesta pasta.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rictom/cnpj-mysql/c2a1d27d74019757177a4a4385fc807722fadb9b/dados-publicos-zip/copie os arquivos zip da receita nesta pasta.txt
--------------------------------------------------------------------------------
/dados-publicos/aqui os arquivos serão descompactados.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rictom/cnpj-mysql/c2a1d27d74019757177a4a4385fc807722fadb9b/dados-publicos/aqui os arquivos serão descompactados.txt
--------------------------------------------------------------------------------
/dados_cnpj_baixa.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 |
4 | lista relação de arquivos na página de dados públicos da receita federal
5 | e faz o download
6 | https://www.gov.br/receitafederal/pt-br/assuntos/orientacao-tributaria/cadastros/consultas/dados-publicos-cnpj
7 | https://dadosabertos.rfb.gov.br/CNPJ/
8 | http://200.152.38.155/CNPJ/
9 | """
10 | from bs4 import BeautifulSoup
11 | import requests, wget, os, sys, time, glob, parfive
12 |
13 | #url = 'http://200.152.38.155/CNPJ/dados_abertos_cnpj/2024-08/' #padrão a partir de agosto/2024
14 | #url_dados_abertos = 'https://dadosabertos.rfb.gov.br/CNPJ/dados_abertos_cnpj/'
15 | #url_dados_abertos = 'http://200.152.38.155/CNPJ/dados_abertos_cnpj/'
16 | url_dados_abertos = 'https://arquivos.receitafederal.gov.br/cnpj/dados_abertos_cnpj/'
17 |
18 | pasta_zip = r"dados-publicos-zip" #local dos arquivos zipados da Receita
19 | pasta_cnpj = 'dados-publicos'
20 |
21 | def requisitos():
22 | #se pastas não existirem, cria automaticamente
23 | if not os.path.isdir(pasta_cnpj):
24 | os.mkdir(pasta_cnpj)
25 | if not os.path.isdir(pasta_zip):
26 | os.mkdir(pasta_zip)
27 |
28 | arquivos_existentes = list(glob.glob(pasta_cnpj +'/*.*')) + list(glob.glob(pasta_zip + '/*.*'))
29 | if len(arquivos_existentes):
30 | #eg.msgbox("Este programa baixa arquivos csv.zip de dados abertos da Receita Federal e converte para uso na RedeCNPJ aplicativo.\nIMPORTANTE: Para prosseguir, as pastas 'dados-publicos' e 'dados-publicos-zip', devem estar vazias, senão poderá haver inconsistências (juntar dados de meses distintos).\n",'Criar Bases RedeCNPJ')
31 | #if eg.ynbox('Deseja apagar os arquivos das pastas ' + pasta_cnpj + ' e ' + pasta_zip + '?\nNÃO SERÁ POSSÍVEL REVERTER!!!!\n' + '\n'.join(arquivos_existentes) + '\nATENÇÃO: SE FOR EXECUTAR APENAS ALGUMA PARTE DO PROGRAMA, NÃO SELECIONE ESTA OPÇÃO, APAGUE MANUALMENTE.','Criar Bases RedeCNPJ', ['SIM-APAGAR', 'NÃO']):
32 | r = input('Deseja apagar os arquivos das pastas ' + pasta_cnpj + ' e ' + pasta_zip + '?\n' + '\n'.join(arquivos_existentes) + '\nATENÇÃO: SE FOR EXECUTAR APENAS ALGUMA PARTE DO PROGRAMA, NÃO SELECIONE ESTA OPÇÃO, APAGUE MANUALMENTE. \nNÃO SERÁ POSSÍVEL REVERTER!!!!\nDeseja prosseguir e apagar os arquivos (y/n)??')
33 | if r and r.upper()=='Y':
34 | for arq in arquivos_existentes:
35 | print('Apagando arquivo ' + arq)
36 | os.remove(arq)
37 | else:
38 | print('Parando... Apague os arquivos ' + pasta_cnpj + ' e ' + pasta_zip +' e tente novamente')
39 | input('Pressione Enter')
40 | sys.exit(1)
41 | # else:
42 | # eg.msgbox("Este programa baixa arquivos csv.zip de dados abertos da Receita Federal e converte para uso na RedeCNPJ aplicativo.",'Criar Bases RedeCNPJ')
43 |
44 | # if len(glob.glob(os.path.join(pasta_zip,'*.zip'))):
45 | # print(f'Há arquivos zip na pasta {pasta_zip}. Apague ou mova esses arquivos zip e tente novamente')
46 | # input('Pressione Enter')
47 | # sys.exit(1)
48 | requisitos()
49 |
50 | print(time.asctime(), f'Início de {sys.argv[0]}:')
51 |
52 | soup_pagina_dados_abertos = BeautifulSoup(requests.get(url_dados_abertos).text, features="lxml")
53 | try:
54 | ultima_referencia = sorted([link.get('href') for link in soup_pagina_dados_abertos.find_all('a') if link.get('href').startswith('20')])[-1]
55 | except:
56 | print('Não encontrou pastas em ' + url_dados_abertos)
57 | r = input('Pressione Enter.')
58 | sys.exit(1)
59 |
60 |
61 | url = url_dados_abertos + ultima_referencia
62 | # page = requests.get(url)
63 | # data = page.text
64 | soup = BeautifulSoup(requests.get(url).text, features="lxml")
65 | lista = []
66 | print('Relação de Arquivos em ' + url)
67 | for link in soup.find_all('a'):
68 | if str(link.get('href')).endswith('.zip'):
69 | cam = link.get('href')
70 | if not cam.startswith('http'):
71 | print(url+cam)
72 | lista.append(url+cam)
73 | else:
74 | print(cam)
75 | lista.append(cam)
76 |
77 | if __name__ == '__main__':
78 | resp = input(f'Deseja baixar os arquivos acima para a pasta {pasta_zip} (y/n)?')
79 | if resp.lower()!='y' and resp.lower()!='s':
80 | sys.exit()
81 |
82 |
83 |
84 | print(time.asctime(), 'Início do Download dos arquivos...')
85 |
86 | if True: #baixa usando parfive, download em paralelo
87 | #downloader = parfive.Downloader()
88 | headers = {'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Windows; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36", "Accept": "*/*"}
89 | downloader = parfive.Downloader(max_conn=5, max_splits=1, config=parfive.SessionConfig(headers=headers))
90 | for url in lista:
91 | downloader.enqueue_file(url, path=pasta_zip, filename=os.path.split(url)[1])
92 | downloader.download()
93 | else: #baixar sequencial, rotina antiga
94 | def bar_progress(current, total, width=80):
95 | if total>=2**20:
96 | tbytes='Megabytes'
97 | unidade = 2**20
98 | else:
99 | tbytes='kbytes'
100 | unidade = 2**10
101 | progress_message = f"Baixando: %d%% [%d / %d] {tbytes}" % (current / total * 100, current//unidade, total//unidade)
102 | # Don't use print() as it will print in new line every time.
103 | sys.stdout.write("\r" + progress_message)
104 | sys.stdout.flush()
105 |
106 | for k, url in enumerate(lista):
107 | print('\n' + time.asctime() + f' - item {k}: ' + url)
108 | wget.download(url, out=os.path.join(pasta_zip, os.path.split(url)[1]), bar=bar_progress)
109 |
110 |
111 | print('\n\n'+ time.asctime(), f' Finalizou {sys.argv[0]}!!!')
112 | print(f"Baixou {len(glob.glob(os.path.join(pasta_zip,'*.zip')))} arquivos.")
113 | if __name__ == '__main__':
114 | input('Pressione Enter')
115 |
116 | #lista dos arquivos (até julho/2024)
117 | '''
118 | http://200.152.38.155/CNPJ/Cnaes.zip
119 | http://200.152.38.155/CNPJ/Empresas0.zip
120 | http://200.152.38.155/CNPJ/Empresas1.zip
121 | http://200.152.38.155/CNPJ/Empresas2.zip
122 | http://200.152.38.155/CNPJ/Empresas3.zip
123 | http://200.152.38.155/CNPJ/Empresas4.zip
124 | http://200.152.38.155/CNPJ/Empresas5.zip
125 | http://200.152.38.155/CNPJ/Empresas6.zip
126 | http://200.152.38.155/CNPJ/Empresas7.zip
127 | http://200.152.38.155/CNPJ/Empresas8.zip
128 | http://200.152.38.155/CNPJ/Empresas9.zip
129 | http://200.152.38.155/CNPJ/Estabelecimentos0.zip
130 | http://200.152.38.155/CNPJ/Estabelecimentos1.zip
131 | http://200.152.38.155/CNPJ/Estabelecimentos2.zip
132 | http://200.152.38.155/CNPJ/Estabelecimentos3.zip
133 | http://200.152.38.155/CNPJ/Estabelecimentos4.zip
134 | http://200.152.38.155/CNPJ/Estabelecimentos5.zip
135 | http://200.152.38.155/CNPJ/Estabelecimentos6.zip
136 | http://200.152.38.155/CNPJ/Estabelecimentos7.zip
137 | http://200.152.38.155/CNPJ/Estabelecimentos8.zip
138 | http://200.152.38.155/CNPJ/Estabelecimentos9.zip
139 | http://200.152.38.155/CNPJ/Motivos.zip
140 | http://200.152.38.155/CNPJ/Municipios.zip
141 | http://200.152.38.155/CNPJ/Naturezas.zip
142 | http://200.152.38.155/CNPJ/Paises.zip
143 | http://200.152.38.155/CNPJ/Qualificacoes.zip
144 | http://200.152.38.155/CNPJ/Simples.zip
145 | http://200.152.38.155/CNPJ/Socios0.zip
146 | http://200.152.38.155/CNPJ/Socios1.zip
147 | http://200.152.38.155/CNPJ/Socios2.zip
148 | http://200.152.38.155/CNPJ/Socios3.zip
149 | http://200.152.38.155/CNPJ/Socios4.zip
150 | http://200.152.38.155/CNPJ/Socios5.zip
151 | http://200.152.38.155/CNPJ/Socios6.zip
152 | http://200.152.38.155/CNPJ/Socios7.zip
153 | http://200.152.38.155/CNPJ/Socios8.zip
154 | http://200.152.38.155/CNPJ/Socios9.zip
155 | '''
156 |
--------------------------------------------------------------------------------
/dados_cnpj_mysql.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Sat Nov 13 18:54:00 2021
4 |
5 | @author: rictom
6 | https://github.com/rictom/cnpj-mysql
7 |
8 | #Para mysql, requer biblioteca pymysql ou mysqlclient (msqldb), desempenho semelhantes.
9 | pip install pymysql
10 | pip install mysqlclient (mysqldb). O desempenho com essa biblioteca foi similar a pymysql
11 |
12 | Para postgres, instale psycopg2 (recomenda-se psycopg2-binary para instalação mais simples)
13 | pip install psycopg2-binary (testado no Ubuntu)
14 |
15 | para evitar erro OperationalError: (pymysql.err.OperationalError) (1206, 'The total number of locks exceeds the lock table size')
16 | alterar mysql.ini
17 | [mysqld]
18 | innodb_buffer_pool_size=1G # depends on your data and machine
19 | """
20 | #%%
21 |
22 | import pandas as pd, sqlalchemy, glob, time, dask.dataframe as dd
23 | from sqlalchemy import text
24 | import os, sys
25 |
26 | #%% DEFINA os parâmetros do servidor.
27 | tipo_banco= 'mysql'
28 | dbname = 'cnpj'
29 | username = 'root'
30 | password = ''
31 | host = '127.0.0.1'
32 |
33 | # tipo_banco = 'postgres'
34 | # dbname = 'cnpj'
35 | # username = 'postgres'
36 | # password = 'senha'
37 | # host = '127.0.0.1'
38 |
39 | pasta_compactados = r"dados-publicos-zip"
40 | pasta_saida = r"dados-publicos" #esta pasta deve estar vazia.
41 | dataReferencia = 'dd/mm/2024' #input('Data de referência da base dd/mm/aaaa: ')
42 |
43 | resp = input(f'Isto irá CRIAR TABELAS ou REESCREVER TABELAS no database {dbname.upper()} no servidor {tipo_banco} {host} e MODIFICAR a pasta {pasta_saida}. Deseja prosseguir? (S/N)?')
44 | if not resp or resp.upper()!='S':
45 | sys.exit()
46 |
47 | if tipo_banco=='mysql':
48 | #engine = sqlalchemy.create_engine(f'mysql+pymysql://{username}:{password}@{host}/{dbname}')
49 | engine_ = sqlalchemy.create_engine(f'mysql+pymysql://{username}:{password}@{host}/{dbname}')
50 | engine = engine_.connect()
51 | engine_url = f'mysql+pymysql://{username}:{password}@{host}/{dbname}'
52 | elif tipo_banco=='postgres':
53 | engine_ = sqlalchemy.create_engine(f'postgresql://{username}:{password}@{host}/{dbname}')
54 | engine = engine_.connect()
55 | engine_url = f'postgresql://{username}:{password}@{host}/{dbname}'
56 | else:
57 | print('tipo de banco de dados não informado')
58 | sys.exit()
59 |
60 | #%%
61 |
62 | #cam = os.path.join(pasta_saida, 'cnpj.db')
63 | #if os.path.exists(cam):
64 | # print('o arquivo ' + cam + ' já existe. Apague primeiro e rode este script novamente.')
65 | # 1/0
66 |
67 | #%%
68 | arquivos_a_zipar = list(glob.glob(os.path.join(pasta_compactados,r'*.zip')))
69 | import zipfile
70 |
71 | for arq in arquivos_a_zipar:
72 | print('descompactando ' + arq)
73 | with zipfile.ZipFile(arq, 'r') as zip_ref:
74 | zip_ref.extractall(pasta_saida)
75 |
76 | dataReferenciaAux = list(glob.glob(os.path.join(pasta_saida, '*.EMPRECSV')))[0].split('.')[2] #formato DAMMDD, vai ser usado no final para inserir na tabela _ref
77 | if len(dataReferenciaAux)==len('D30610') and dataReferenciaAux.startswith('D'):
78 | dataReferencia = dataReferenciaAux[4:6] + '/' + dataReferenciaAux[2:4] + '/202' + dataReferenciaAux[1]
79 |
80 | #%%
81 | #tipos = ['.EMPRECSV', '.ESTABELE', '.SOCIOCSV']
82 |
83 | #arquivos_emprescsv = list(glob.glob(os.path.join(pasta_saida, '*' + tipos[0])))
84 |
85 |
86 | sqlTabelas = '''
87 | DROP TABLE if exists cnae;
88 | CREATE TABLE cnae (
89 | codigo VARCHAR(7)
90 | ,descricao VARCHAR(200)
91 | );
92 | DROP TABLE if exists empresas;
93 | CREATE TABLE empresas (
94 | cnpj_basico VARCHAR(8)
95 | ,razao_social VARCHAR(200)
96 | ,natureza_juridica VARCHAR(4)
97 | ,qualificacao_responsavel VARCHAR(2)
98 | ,capital_social_str VARCHAR(20)
99 | ,porte_empresa VARCHAR(2)
100 | ,ente_federativo_responsavel VARCHAR(50)
101 | );
102 | DROP TABLE if exists estabelecimento;
103 | CREATE TABLE estabelecimento (
104 | cnpj_basico VARCHAR(8)
105 | ,cnpj_ordem VARCHAR(4)
106 | ,cnpj_dv VARCHAR(2)
107 | ,matriz_filial VARCHAR(1)
108 | ,nome_fantasia VARCHAR(200)
109 | ,situacao_cadastral VARCHAR(2)
110 | ,data_situacao_cadastral VARCHAR(8)
111 | ,motivo_situacao_cadastral VARCHAR(2)
112 | ,nome_cidade_exterior VARCHAR(200)
113 | ,pais VARCHAR(3)
114 | ,data_inicio_atividades VARCHAR(8)
115 | ,cnae_fiscal VARCHAR(7)
116 | ,cnae_fiscal_secundaria VARCHAR(1000)
117 | ,tipo_logradouro VARCHAR(20)
118 | ,logradouro VARCHAR(200)
119 | ,numero VARCHAR(10)
120 | ,complemento VARCHAR(200)
121 | ,bairro VARCHAR(200)
122 | ,cep VARCHAR(8)
123 | ,uf VARCHAR(2)
124 | ,municipio VARCHAR(4)
125 | ,ddd1 VARCHAR(4)
126 | ,telefone1 VARCHAR(8)
127 | ,ddd2 VARCHAR(4)
128 | ,telefone2 VARCHAR(8)
129 | ,ddd_fax VARCHAR(4)
130 | ,fax VARCHAR(8)
131 | ,correio_eletronico VARCHAR(200)
132 | ,situacao_especial VARCHAR(200)
133 | ,data_situacao_especial VARCHAR(8)
134 | );
135 | DROP TABLE if exists motivo;
136 | CREATE TABLE motivo (
137 | codigo VARCHAR(2)
138 | ,descricao VARCHAR(200)
139 | );
140 | DROP TABLE if exists municipio;
141 | CREATE TABLE municipio (
142 | codigo VARCHAR(4)
143 | ,descricao VARCHAR(200)
144 | );
145 | DROP TABLE if exists natureza_juridica;
146 | CREATE TABLE natureza_juridica (
147 | codigo VARCHAR(4)
148 | ,descricao VARCHAR(200)
149 | );
150 | DROP TABLE if exists pais;
151 | CREATE TABLE pais (
152 | codigo VARCHAR(3)
153 | ,descricao VARCHAR(200)
154 | );
155 | DROP TABLE if exists qualificacao_socio;
156 | CREATE TABLE qualificacao_socio (
157 | codigo VARCHAR(2)
158 | ,descricao VARCHAR(200)
159 | );
160 | DROP TABLE if exists simples;
161 | CREATE TABLE simples (
162 | cnpj_basico VARCHAR(8)
163 | ,opcao_simples VARCHAR(1)
164 | ,data_opcao_simples VARCHAR(8)
165 | ,data_exclusao_simples VARCHAR(8)
166 | ,opcao_mei VARCHAR(1)
167 | ,data_opcao_mei VARCHAR(8)
168 | ,data_exclusao_mei VARCHAR(8)
169 | );
170 | DROP TABLE if exists socios_original;
171 | CREATE TABLE socios_original (
172 | cnpj_basico VARCHAR(8)
173 | ,identificador_de_socio VARCHAR(1)
174 | ,nome_socio VARCHAR(200)
175 | ,cnpj_cpf_socio VARCHAR(14)
176 | ,qualificacao_socio VARCHAR(2)
177 | ,data_entrada_sociedade VARCHAR(8)
178 | ,pais VARCHAR(3)
179 | ,representante_legal VARCHAR(11)
180 | ,nome_representante VARCHAR(200)
181 | ,qualificacao_representante_legal VARCHAR(2)
182 | ,faixa_etaria VARCHAR(1)
183 | );
184 | '''
185 |
186 | # def sqlCriaTabela(nomeTabela, colunas):
187 | # sql = 'CREATE TABLE ' + nomeTabela + ' ('
188 | # for k, coluna in enumerate(colunas):
189 | # sql += '\n' + coluna + ' TEXT'
190 | # if k+1 postgres, change column para rename column c1 TO c2; ALTER TABLE t1 RENAME -> ALTER TABLE t1 RENAME TO; te.matriz_filial="1" -> '1';
329 | sqls = '''
330 |
331 | ALTER TABLE empresas ADD COLUMN capital_social DECIMAL(18,2);
332 | UPDATE empresas
333 | set capital_social = cast(REPLACE(capital_social_str,',', '.') AS DECIMAL(18,2));
334 |
335 | ALTER TABLE empresas DROP COLUMN capital_social_str;
336 |
337 | ALTER TABLE estabelecimento ADD COLUMN cnpj VARCHAR(14);
338 | Update estabelecimento
339 | set cnpj = CONCAT(cnpj_basico, cnpj_ordem,cnpj_dv);
340 |
341 | CREATE INDEX idx_estabelecimento_cnpj ON estabelecimento (cnpj);
342 | CREATE INDEX idx_empresas_cnpj_basico ON empresas (cnpj_basico);
343 | CREATE INDEX idx_empresas_razao_social ON empresas (razao_social);
344 | CREATE INDEX idx_estabelecimento_cnpj_basico ON estabelecimento (cnpj_basico);
345 |
346 | CREATE INDEX idx_socios_original_cnpj_basico
347 | ON socios_original(cnpj_basico);
348 |
349 | DROP TABLE IF EXISTS socios;
350 |
351 | CREATE TABLE socios AS
352 | SELECT te.cnpj as cnpj, ts.*
353 | from socios_original ts
354 | left join estabelecimento te on te.cnpj_basico = ts.cnpj_basico
355 | where te.matriz_filial='1';
356 |
357 | DROP TABLE IF EXISTS socios_original;
358 |
359 | CREATE INDEX idx_socios_cnpj ON socios(cnpj);
360 | CREATE INDEX idx_socios_cnpj_basico ON socios(cnpj_basico);
361 | CREATE INDEX idx_socios_cnpj_cpf_socio ON socios(cnpj_cpf_socio);
362 | CREATE INDEX idx_socios_nome_socio ON socios(nome_socio);
363 |
364 | CREATE INDEX idx_simples_cnpj_basico ON simples(cnpj_basico);
365 |
366 | DROP TABLE IF EXISTS _referencia;
367 | CREATE TABLE _referencia (
368 | referencia VARCHAR(100),
369 | valor VARCHAR(100)
370 | );
371 | '''
372 |
373 | print('Inicio sqls:', time.asctime())
374 | for k, sql in enumerate(sqls.split(';')):
375 | if not sql.strip():
376 | continue
377 | print('-'*20 + f'\nexecutando parte {k}:\n', sql)
378 | engine.execute(text(sql))
379 | print('fim parcial...', time.asctime())
380 | print('fim sqls...', time.asctime())
381 |
382 | #%% inserir na tabela referencia_
383 |
384 | qtde_cnpjs = engine.execute(text('select count(*) as contagem from estabelecimento;')).fetchone()[0]
385 |
386 | engine.execute(text(f"insert into _referencia (referencia, valor) values ('CNPJ', '{dataReferencia}')"))
387 | engine.execute(text(f"insert into _referencia (referencia, valor) values ('cnpj_qtde', '{qtde_cnpjs}')"))
388 |
389 | print('-'*20)
390 | print(f'As tabelas foram criadas no servidor {tipo_banco}.')
391 | print('Qtde de empresas (matrizes):', engine.execute(text('SELECT COUNT(*) FROM empresas')).fetchone()[0])
392 | print('Qtde de estabelecimentos (matrizes e fiiais):', engine.execute(text('SELECT COUNT(*) FROM estabelecimento')).fetchone()[0])
393 | print('Qtde de sócios:', engine.execute(text('SELECT COUNT(*) FROM socios')).fetchone()[0])
394 |
395 | engine.commit()
396 | engine.close()
397 |
398 | print('FIM!!!', time.asctime())
399 |
400 |
--------------------------------------------------------------------------------
/dados_cnpj_postgres.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Sat Nov 13 18:54:00 2021
4 |
5 | @author: rictom
6 | https://github.com/rictom/cnpj-mysql
7 |
8 | #Para mysql, requer biblioteca pymysql ou mysqlclient (msqldb), desempenho semelhantes.
9 | pip install pymysql
10 | pip install mysqlclient (mysqldb). O desempenho com essa biblioteca foi similar a pymysql
11 |
12 | Para postgres, instale psycopg2 (recomenda-se psycopg2-binary para instalação mais simples)
13 | pip install psycopg2-binary (testado no Ubuntu)
14 |
15 | para evitar erro OperationalError: (pymysql.err.OperationalError) (1206, 'The total number of locks exceeds the lock table size')
16 | alterar mysql.ini
17 | [mysqld]
18 | innodb_buffer_pool_size=1G # depends on your data and machine
19 | """
20 | #%%
21 |
22 | import pandas as pd, sqlalchemy, glob, time, dask.dataframe as dd
23 | from sqlalchemy import text
24 | import os, sys
25 |
26 | #%% DEFINA os parâmetros do servidor.
27 | # tipo_banco= 'mysql'
28 | # dbname = 'cnpj'
29 | # username = 'root'
30 | # password = ''
31 | # host = '127.0.0.1'
32 |
33 | tipo_banco = 'postgres'
34 | dbname = 'cnpj'
35 | username = 'postgres'
36 | password = 'senha'
37 | host = '127.0.0.1'
38 |
39 | pasta_compactados = r"dados-publicos-zip"
40 | pasta_saida = r"dados-publicos" #esta pasta deve estar vazia.
41 | dataReferencia = 'dd/mm/2024' #input('Data de referência da base dd/mm/aaaa: ')
42 |
43 | resp = input(f'Isto irá CRIAR TABELAS ou REESCREVER TABELAS no database {dbname.upper()} no servidor {tipo_banco} {host} e MODIFICAR a pasta {pasta_saida}. Deseja prosseguir? (S/N)?')
44 | if not resp or resp.upper()!='S':
45 | sys.exit()
46 |
47 | if tipo_banco=='mysql':
48 | #engine = sqlalchemy.create_engine(f'mysql+pymysql://{username}:{password}@{host}/{dbname}')
49 | engine_ = sqlalchemy.create_engine(f'mysql+pymysql://{username}:{password}@{host}/{dbname}')
50 | engine = engine_.connect()
51 | engine_url = f'mysql+pymysql://{username}:{password}@{host}/{dbname}'
52 | elif tipo_banco=='postgres':
53 | engine_ = sqlalchemy.create_engine(f'postgresql://{username}:{password}@{host}/{dbname}')
54 | engine = engine_.connect()
55 | engine_url = f'postgresql://{username}:{password}@{host}/{dbname}'
56 | else:
57 | print('tipo de banco de dados não informado')
58 | sys.exit()
59 |
60 | #%%
61 |
62 | #cam = os.path.join(pasta_saida, 'cnpj.db')
63 | #if os.path.exists(cam):
64 | # print('o arquivo ' + cam + ' já existe. Apague primeiro e rode este script novamente.')
65 | # 1/0
66 |
67 | #%%
68 | arquivos_a_zipar = list(glob.glob(os.path.join(pasta_compactados,r'*.zip')))
69 | import zipfile
70 |
71 | for arq in arquivos_a_zipar:
72 | print('descompactando ' + arq)
73 | with zipfile.ZipFile(arq, 'r') as zip_ref:
74 | zip_ref.extractall(pasta_saida)
75 |
76 | dataReferenciaAux = list(glob.glob(os.path.join(pasta_saida, '*.EMPRECSV')))[0].split('.')[2] #formato DAMMDD, vai ser usado no final para inserir na tabela _ref
77 | if len(dataReferenciaAux)==len('D30610') and dataReferenciaAux.startswith('D'):
78 | dataReferencia = dataReferenciaAux[4:6] + '/' + dataReferenciaAux[2:4] + '/202' + dataReferenciaAux[1]
79 |
80 | #%%
81 | #tipos = ['.EMPRECSV', '.ESTABELE', '.SOCIOCSV']
82 |
83 | #arquivos_emprescsv = list(glob.glob(os.path.join(pasta_saida, '*' + tipos[0])))
84 |
85 |
86 | sqlTabelas = '''
87 | DROP TABLE if exists cnae;
88 | CREATE TABLE cnae (
89 | codigo VARCHAR(7)
90 | ,descricao VARCHAR(200)
91 | );
92 | DROP TABLE if exists empresas;
93 | CREATE TABLE empresas (
94 | cnpj_basico VARCHAR(8)
95 | ,razao_social VARCHAR(200)
96 | ,natureza_juridica VARCHAR(4)
97 | ,qualificacao_responsavel VARCHAR(2)
98 | ,capital_social_str VARCHAR(20)
99 | ,porte_empresa VARCHAR(2)
100 | ,ente_federativo_responsavel VARCHAR(50)
101 | );
102 | DROP TABLE if exists estabelecimento;
103 | CREATE TABLE estabelecimento (
104 | cnpj_basico VARCHAR(8)
105 | ,cnpj_ordem VARCHAR(4)
106 | ,cnpj_dv VARCHAR(2)
107 | ,matriz_filial VARCHAR(1)
108 | ,nome_fantasia VARCHAR(200)
109 | ,situacao_cadastral VARCHAR(2)
110 | ,data_situacao_cadastral VARCHAR(8)
111 | ,motivo_situacao_cadastral VARCHAR(2)
112 | ,nome_cidade_exterior VARCHAR(200)
113 | ,pais VARCHAR(3)
114 | ,data_inicio_atividades VARCHAR(8)
115 | ,cnae_fiscal VARCHAR(7)
116 | ,cnae_fiscal_secundaria VARCHAR(1000)
117 | ,tipo_logradouro VARCHAR(20)
118 | ,logradouro VARCHAR(200)
119 | ,numero VARCHAR(10)
120 | ,complemento VARCHAR(200)
121 | ,bairro VARCHAR(200)
122 | ,cep VARCHAR(8)
123 | ,uf VARCHAR(2)
124 | ,municipio VARCHAR(4)
125 | ,ddd1 VARCHAR(4)
126 | ,telefone1 VARCHAR(8)
127 | ,ddd2 VARCHAR(4)
128 | ,telefone2 VARCHAR(8)
129 | ,ddd_fax VARCHAR(4)
130 | ,fax VARCHAR(8)
131 | ,correio_eletronico VARCHAR(200)
132 | ,situacao_especial VARCHAR(200)
133 | ,data_situacao_especial VARCHAR(8)
134 | );
135 | DROP TABLE if exists motivo;
136 | CREATE TABLE motivo (
137 | codigo VARCHAR(2)
138 | ,descricao VARCHAR(200)
139 | );
140 | DROP TABLE if exists municipio;
141 | CREATE TABLE municipio (
142 | codigo VARCHAR(4)
143 | ,descricao VARCHAR(200)
144 | );
145 | DROP TABLE if exists natureza_juridica;
146 | CREATE TABLE natureza_juridica (
147 | codigo VARCHAR(4)
148 | ,descricao VARCHAR(200)
149 | );
150 | DROP TABLE if exists pais;
151 | CREATE TABLE pais (
152 | codigo VARCHAR(3)
153 | ,descricao VARCHAR(200)
154 | );
155 | DROP TABLE if exists qualificacao_socio;
156 | CREATE TABLE qualificacao_socio (
157 | codigo VARCHAR(2)
158 | ,descricao VARCHAR(200)
159 | );
160 | DROP TABLE if exists simples;
161 | CREATE TABLE simples (
162 | cnpj_basico VARCHAR(8)
163 | ,opcao_simples VARCHAR(1)
164 | ,data_opcao_simples VARCHAR(8)
165 | ,data_exclusao_simples VARCHAR(8)
166 | ,opcao_mei VARCHAR(1)
167 | ,data_opcao_mei VARCHAR(8)
168 | ,data_exclusao_mei VARCHAR(8)
169 | );
170 | DROP TABLE if exists socios_original;
171 | CREATE TABLE socios_original (
172 | cnpj_basico VARCHAR(8)
173 | ,identificador_de_socio VARCHAR(1)
174 | ,nome_socio VARCHAR(200)
175 | ,cnpj_cpf_socio VARCHAR(14)
176 | ,qualificacao_socio VARCHAR(2)
177 | ,data_entrada_sociedade VARCHAR(8)
178 | ,pais VARCHAR(3)
179 | ,representante_legal VARCHAR(11)
180 | ,nome_representante VARCHAR(200)
181 | ,qualificacao_representante_legal VARCHAR(2)
182 | ,faixa_etaria VARCHAR(1)
183 | );
184 | '''
185 |
186 | # def sqlCriaTabela(nomeTabela, colunas):
187 | # sql = 'CREATE TABLE ' + nomeTabela + ' ('
188 | # for k, coluna in enumerate(colunas):
189 | # sql += '\n' + coluna + ' TEXT'
190 | # if k+1 postgres, change column para rename column c1 TO c2; ALTER TABLE t1 RENAME -> ALTER TABLE t1 RENAME TO; te.matriz_filial="1" -> '1';
329 | sqls = '''
330 |
331 | ALTER TABLE empresas ADD COLUMN capital_social DECIMAL(18,2);
332 | UPDATE empresas
333 | set capital_social = cast(REPLACE(capital_social_str,',', '.') AS DECIMAL(18,2));
334 |
335 | ALTER TABLE empresas DROP COLUMN capital_social_str;
336 |
337 | ALTER TABLE estabelecimento ADD COLUMN cnpj VARCHAR(14);
338 | Update estabelecimento
339 | set cnpj = CONCAT(cnpj_basico, cnpj_ordem,cnpj_dv);
340 |
341 | CREATE INDEX idx_estabelecimento_cnpj ON estabelecimento (cnpj);
342 | CREATE INDEX idx_empresas_cnpj_basico ON empresas (cnpj_basico);
343 | CREATE INDEX idx_empresas_razao_social ON empresas (razao_social);
344 | CREATE INDEX idx_estabelecimento_cnpj_basico ON estabelecimento (cnpj_basico);
345 |
346 | CREATE INDEX idx_socios_original_cnpj_basico
347 | ON socios_original(cnpj_basico);
348 |
349 | DROP TABLE IF EXISTS socios;
350 |
351 | CREATE TABLE socios AS
352 | SELECT te.cnpj as cnpj, ts.*
353 | from socios_original ts
354 | left join estabelecimento te on te.cnpj_basico = ts.cnpj_basico
355 | where te.matriz_filial='1';
356 |
357 | DROP TABLE IF EXISTS socios_original;
358 |
359 | CREATE INDEX idx_socios_cnpj ON socios(cnpj);
360 | CREATE INDEX idx_socios_cnpj_basico ON socios(cnpj_basico);
361 | CREATE INDEX idx_socios_cnpj_cpf_socio ON socios(cnpj_cpf_socio);
362 | CREATE INDEX idx_socios_nome_socio ON socios(nome_socio);
363 |
364 | CREATE INDEX idx_simples_cnpj_basico ON simples(cnpj_basico);
365 |
366 | DROP TABLE IF EXISTS _referencia;
367 | CREATE TABLE _referencia (
368 | referencia VARCHAR(100),
369 | valor VARCHAR(100)
370 | );
371 | '''
372 |
373 | print('Inicio sqls:', time.asctime())
374 | for k, sql in enumerate(sqls.split(';')):
375 | if not sql.strip():
376 | continue
377 | print('-'*20 + f'\nexecutando parte {k}:\n', sql)
378 | engine.execute(text(sql))
379 | print('fim parcial...', time.asctime())
380 | print('fim sqls...', time.asctime())
381 |
382 | #%% inserir na tabela referencia_
383 |
384 | qtde_cnpjs = engine.execute(text('select count(*) as contagem from estabelecimento;')).fetchone()[0]
385 |
386 | engine.execute(text(f"insert into _referencia (referencia, valor) values ('CNPJ', '{dataReferencia}')"))
387 | engine.execute(text(f"insert into _referencia (referencia, valor) values ('cnpj_qtde', '{qtde_cnpjs}')"))
388 |
389 | print('-'*20)
390 | print(f'As tabelas foram criadas no servidor {tipo_banco}.')
391 | print('Qtde de empresas (matrizes):', engine.execute(text('SELECT COUNT(*) FROM empresas')).fetchone()[0])
392 | print('Qtde de estabelecimentos (matrizes e fiiais):', engine.execute(text('SELECT COUNT(*) FROM estabelecimento')).fetchone()[0])
393 | print('Qtde de sócios:', engine.execute(text('SELECT COUNT(*) FROM socios')).fetchone()[0])
394 |
395 | engine.commit()
396 | engine.close()
397 |
398 | print('FIM!!!', time.asctime())
399 |
400 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | beautifulsoup4
2 | dask
3 | dask-expr
4 | pandas
5 | requests
6 | bs4
7 | SQLAlchemy
8 | wget
9 | parfive
10 | pymysql
11 | lxml
12 | pyarrow
13 |
14 |
--------------------------------------------------------------------------------