├── 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 | --------------------------------------------------------------------------------