Blog

Postado em em 27 de julho de 2023

Freela de Python – Projeto de R$500 Completo – XML para Excel

Você quer trabalhar como freela de Python e conseguir uma grana extra? Preparei esta aula para te ensinar um projeto simples.

Caso prefira esse conteúdo no formato de vídeo-aula, assista ao vídeo abaixo ou acesse o nosso canal do YouTube!

Para receber por e-mail o(s) arquivo(s) utilizados na aula, preencha:

Fala Impressionadores! Nessa aula eu quero te mostrar a construção de um projeto de freela de Python para você ganhar dinheiro!

Pegamos esse projeto do site freelancer.com.br para te mostrar como podemos construir um leitor de XML usando Python.

A ideia é que você tenha um projeto para ganhar dinheiro com Python, pois a descrição diz que o orçamento vai de R$100 a R$500 e você vai notar que não é nada muito complexo de fazer.

Para criar o leitor de XML no Python vamos ter que utilizar a biblioteca xmltodict, que vai pegar o arquivo XML e vai passar para um dicionário, assim vamos conseguir ler as informações dentro do Python.

Vou te mostrar todo o passo a passo para entender como obter as informações de NF com Python, como testar e como tratar essas informações caso elas não estejam no mesmo local ou não existam.

E aí, bora aprender como ler XML com Python e até ganhar um dinheiro com esse projeto?

Importante:

Vamos usar para esse projeto o VS Code, clique no link para ver uma aula completa sobre a instalação dele, caso você ainda não tenha instalado.

Outro ponto é baixar os arquivos da aula, porque vamos usar cada um deles nessa automação.

Dito isso vamos ao projeto!

Abra o VS Code e clique em New -> coloque o nome da pasta de main.py (ou outro nome com a terminação py), crie uma pasta e arraste para dentro dela as notas fiscais do material didático.

Freela de Python

Você vai observar que temos vários modelos de xml e que eles são muito parecidos entre si, o que vou te ensinar nesta aula vai fazer com que você consiga trabalhar com cada um deles.

Para começar vamos usar uma ferramenta que faz a leitura do xml e permite que o Python a entenda, essa biblioteca se chama xmltodict. No seu terminal digite:

>pip install xmltodict

Note que os modelos xml possuem uma estrutura muito parecida com um dicionário, por esse motivo conseguimos transformá-la em um dicionário Python e trabalhar com eles.

Para manusear melhor os arquivos, vamos importar também a biblioteca os.

Vamos então ler cada arquivo que colocamos na pasta de arquivo e posteriormente pegar as informações de cada arquivo usando uma estrutura de repetição, neste caso vou usar o FOR e criar uma função que vai ler o extrair informações do arquivo.

Note que a variável arquivo por enquanto é apenas o nome do arquivo, para abrir o arquivo vamos usar o with.

Import xmltodict

Import os

Def pegar_infos(nome_arquivo):

        Print(f”Pegou as informações {nome_arquivo}”)

        With open(nome_arquivo, “r”) as arquivo_xml:

lista_arquivos = os.listdir(“nfs”)

For arquivo in lista_arquivos:

        pegar_infos(arquivo)

Por hora a estrutura do with ainda não vai funcionar, isso porque estamos mandando que ele pegue o arquivo direto passando o nome dos arquivos, mas os arquivos estão dentro da pasta nfs.

Rodando assim o código não consegue localizar o arquivo porque vai procurar diretamente nos documentos ao invés de ir a pasta.

Para que ele abra a pasta nfs vamos passar o caminho da pasta no with:

Import xmltodict

Import os

Def pegar_infos(nome_arquivo):

        Print(f”Pegou as informações {nome_arquivo}”)

        With open(f’nfs/{nome_arquivo}’, “r”) as arquivo_xml:

lista_arquivos = os.listdir(“nfs”)

For arquivo in lista_arquivos:

        pegar_infos(arquivo)

Feito isso temos os nossos arquivos xml, o próximo passo é transformá-lo em um dicionário, para isso vamos usar o “parse” que executa essa ação de tornar as informações do xml em um dicionário.

Obs. O tipo de leitura que está sendo feita no with -> “r” deve ser alterado para “rb”

Import xmltodict

Import os

Def pegar_infos(nome_arquivo):

        Print(f”Pegou as informações {nome_arquivo}”)

        With open(f’nfs/{nome_arquivo}’, “rb”) as arquivo_xml:

                 Dic_arquivo = xmltodict.parse(arquivo_xml)

                 Print(dic_arquivo)

lista_arquivos = os.listdir(“nfs”)

For arquivo in lista_arquivos:

        pegar_infos(arquivo)

Com todas as alterações feitas o código acima ele está pronto para resultar em um dicionário com todas as informações dos arquivos xml.

Note que rodando o código ele irá rodar todas as notas por estar em um loop for, por este motivo vamos acrescentar um Break no final do for:

For arquivo in lista_arquivos:

        pegar_infos(arquivo)

        break

Assim criamos o código para fazer apenas uma nota e quando estiver tudo certo é só adaptar para que ele leia as demais notas.

Percorrendo as informações de um dicionário

Quando queremos percorrer as informações de um dicionário temos mais de uma maneira de fazer isso, você pode copiar e colar o dicionário e após isso ir analisando a cada parte, essa opção existe mais é iniável.

Para facilitar a nossa vida vou te dar uma dica, importe a biblioteca Json para dentro do seu código.

Feito isso, ao invés de printarmos a biblioteca normalmente, vamos colocar em um json.dumps:

import xmltodict

import os

import json

def pegar_infos(nome_arquivo):

        print(f”Pegou as informações {nome_arquivo}”)

        with open(f’nfs/{nome_arquivo}’, “rb”) as arquivo_xml:

                 dic_arquivo = xmltodict.parse(arquivo_xml)

                 print(json.dumps(dic_arquivo, indent=4))

lista_arquivos = os.listdir(“nfs”)

for arquivo in lista_arquivos:

        pegar_infos(arquivo)

O que o json.dumps faz?

Basicamente ele irá formatar o dicionário de uma maneira que vai facilitar a leitura para nós, as informações virão indentadas em seções mais organizadas. Rode o código e veja a diferença na estrutura do resultado!

Agora as informações estão organizadas e você consegue ver claramente as divisões, qual estrutura está indentada a outra.

Visto isso podemos passar no código qual informação queremos de uma forma mais específica.

import xmltodict

import os

import json

def pegar_infos(nome_arquivo):

        print(f”Pegou as informações {nome_arquivo}”)

        with open(f’nfs/{nome_arquivo}’, “rb”) as arquivo_xml:

                 dic_arquivo = xmltodict.parse(arquivo_xml)

                 print(json.dumps(dic_arquivo, indent=4))

                 infos_nf = dic_arquivo[“Nfe”][“infNfe”]

lista_arquivos = os.listdir(“nfs”)

for arquivo in lista_arquivos:

        pegar_infos(arquivo)

Agora só precisamos escolher quais informações vamos extrair do dicionário, como estamos fazendo um trabalho temos que ver qual foi o pedido do cliente.

Vamos então criar uma variável para armazenar cada informação solicitada sempre indicando na variável onde está a informação ao nível de indentação, assim pegamos os valores corretos.

Feito isso podemos comentar a linha que está printando o código e fazer um novo print das variáveis para ver se as informações estão sendo coletadas corretamente.

import xmltodict

import os

import json

def pegar_infos(nome_arquivo):

        print(f”Pegou as informações {nome_arquivo}”)

        with open(f’nfs/{nome_arquivo}’, “rb”) as arquivo_xml:

                 dic_arquivo = xmltodict.parse(arquivo_xml)

                 #print(json.dumps(dic_arquivo, indent=4))

                 infos_nf = dic_arquivo[“Nfe”][“infNfe”]

            numero_nota = infos_nf [“@ld”]

            empresa_emissora = infos_nf [“emit”] [“xNome”]

            nome_cliente = infos_nf [“dest”] [“xNome”]

            endereço = infos_nf [“dest”] [“enderDest”]

            peso = infos_nf [“transp”] [“vol”] [“pesoB”]

            print(numero_nota, empresa_emissora, nome_cliente, endereço, peso, sep=”\n”)

lista_arquivos = os.listdir(“nfs”)

for arquivo in lista_arquivos:

        pegar_infos(arquivo)

Resultado

Freela de Python

Note que todas as informações da variável vieram separadas como prevíamos.

Precisamos agora verificar se este mesmo código vai funcionar para as outras notas fiscais, lembre-se de que elas possuem pequenas diferenças em sua estrutura.

Para fazer, vamos apenas retirar o Break que colocamos na última linha do For e rodar o código novamente.

Observe que não conseguimos rodar sem nenhum erro, nosso código não está conseguindo encontrar a nota fiscal!

Por que isso está acontecendo?

Na primeira nota que avaliamos as informações da nota eram encontradas direto no dic_arquivo dentro do setor nfe, diferente da segunda nota fiscal em que essa informação não está no mesmo local.

Para resolver este problema vamos usar o except, ou seja, o código vai tentar ler todas as informações e quando não conseguir vai entrar no except.

Para conseguir controlar os tipos de erro que podem ocorrer vamos armazenar os erros, assim podemos controlas o que ocorre no código.

A ideia aqui é que o erro seja armazenado e posteriormente o código printe para nós o dicionário original de onde ocorreu o erro. Dessa forma podemos localizar e criar uma solução para aquela seção.

import xmltodict

import os

import json

def pegar_infos(nome_arquivo):

        print(f”Pegou as informações {nome_arquivo}”)

        with open(f’nfs/{nome_arquivo}’, “rb”) as arquivo_xml:

                 dic_arquivo = xmltodict.parse(arquivo_xml)

                 try:

                         infos_nf = dic_arquivo[“Nfe”][“infNfe”]

                  numero_nota = infos_nf [“@ld”]

                  empresa_emissora = infos_nf [“emit”] [“xNome”]

                  nome_cliente = infos_nf [“dest”] [“xNome”]

                  endereço = infos_nf [“dest”] [“enderDest”]

                  peso = infos_nf [“transp”] [“vol”] [“pesoB”]

                  print(numero_nota, empresa_emissora, nome_cliente, endereço, peso, sep=”\n”)

            except Exception as e:

                  print(e)

                  print(json.dumps(dic_arquivo, indent=4))

lista_arquivos = os.listdir(“nfs”)

for arquivo in lista_arquivos:

        pegar_infos(arquivo)

Feitos os ajustes rode o código, observe que vamos ter agora o erro e a seção do código onde o erro ocorreu no nosso editor de código.

Neste caso as informações de nfe não foram encontradas no código 2 e 3, porque o Nfe não está na primeira chave do dicionário como no primeiro caso que analisamos.

Então vamos ter que colocar uma condição, se ele não encontrar o Nfe então ele deve procurar a informação pelo nfeProc e dentro dele coletar as informação de nfe e infNFe que é onde observamos que a informação está no dicionário 2 e 3.

import xmltodict

import os

import json

def pegar_infos(nome_arquivo):

        print(f”Pegou as informações {nome_arquivo}”)

        with open(f’nfs/{nome_arquivo}’, “rb”) as arquivo_xml:

                 dic_arquivo = xmltodict.parse(arquivo_xml)

                 try:

                         if “NFe” in dic_arquivo:

infos_nf = dic_arquivo[“Nfe”][“infNfe”]

                  else:

                        infos_nf = dic_arquivo[“nfeProc”][“NFe”][“infNFe”]

                  numero_nota = infos_nf [“@ld”]

                  empresa_emissora = infos_nf [“emit”] [“xNome”]

                  nome_cliente = infos_nf [“dest”] [“xNome”]

                  endereço = infos_nf [“dest”] [“enderDest”]

                  peso = infos_nf [“transp”] [“vol”] [“pesoB”]

                  print(numero_nota, empresa_emissora, nome_cliente, endereço, peso, sep=”\n”)

            except Exception as e:

                  print(e)

                  print(json.dumps(dic_arquivo, indent=4))

lista_arquivos = os.listdir(“nfs”)

for arquivo in lista_arquivos:

        pegar_infos(arquivo)

Agora conseguimos encontrar o NFe e as notas 1 e 3 rodaram perfeitamente, porém o código ainda mostra um erro, dessa vez na nota fiscal 2.

O código não conseguiu encontrar o valor do volume, ou seja, a informação do peso não foi encontrada.

Então o processo vai ser o mesmo feito anteriormente, vamos analisar o código e descobrir onde está essa informação de volume nesta nota.

Neste caso depois de verificar você verá que essa informação não existe na biblioteca, então não tem como pegar.

Vamos fazer mais uma condição dizendo que se existir o peso na seção transportadora, então pegamos o peso, se o peso não existir então o peso aparecerá como “não informado”.

import xmltodict

import os

import json

def pegar_infos(nome_arquivo):

        print(f”Pegou as informações {nome_arquivo}”)

        with open(f’nfs/{nome_arquivo}’, “rb”) as arquivo_xml:

                 dic_arquivo = xmltodict.parse(arquivo_xml)

                 try:

                         if “NFe” in dic_arquivo:

infos_nf = dic_arquivo[“Nfe”][“infNfe”]

                  else:

                        infos_nf = dic_arquivo[“nfeProc”][“NFe”][“infNFe”]

                  numero_nota = infos_nf [“@ld”]

                  empresa_emissora = infos_nf [“emit”] [“xNome”]

                  nome_cliente = infos_nf [“dest”] [“xNome”]

                  endereço = infos_nf [“dest”] [“enderDest”]

                  if “vol” in infos_nf[“transp”]

                        peso = infos_nf [“transp”] [“vol”] [“pesoB”]

                  else:

                        peso = “Não informado”

                  print(numero_nota, empresa_emissora, nome_cliente, endereço, peso, sep=”\n”)

            except Exception as e:

                  print(e)

                  print(json.dumps(dic_arquivo, indent=4))

lista_arquivos = os.listdir(“nfs”)

for arquivo in lista_arquivos:

        pegar_infos(arquivo)

Feito isso vamos rodar o código novamente para ver se está tudo ok, rodando conforme esperado.

Dessa vez conseguimos coletar todas as informações sem mensagens de erro.

Obs. Se você for fazer um arquivo e nele estiver aparecendo mais erros, saiba que você terá que tratar cada um individualmente como fizemos a pouco até que seu código rode perfeitamente.

No final quando o código estiver funcionando, podemos retirar do código o try e o except e voltar o tab (indentação) dos códigos no try, além disso, remova a biblioteca json pois já não é mais necessária.

import xmltodict

import os

def pegar_infos(nome_arquivo):

        print(f”Pegou as informações {nome_arquivo}”)

        with open(f’nfs/{nome_arquivo}’, “rb”) as arquivo_xml:

                 dic_arquivo = xmltodict.parse(arquivo_xml)

                 if “NFe” in dic_arquivo:

infos_nf = dic_arquivo[“Nfe”][“infNfe”]

            else:

                  infos_nf = dic_arquivo[“nfeProc”][“NFe”][“infNFe”]

            numero_nota = infos_nf [“@ld”]

            empresa_emissora = infos_nf [“emit”] [“xNome”]

            nome_cliente = infos_nf [“dest”] [“xNome”]

            endereço = infos_nf [“dest”] [“enderDest”]

            if “vol” in infos_nf[“transp”]

                  peso = infos_nf [“transp”] [“vol”] [“pesoB”]

            else:

                  peso = “Não informado”

            print(numero_nota, empresa_emissora, nome_cliente, endereço, peso, sep=”\n”)

lista_arquivos = os.listdir(“nfs”)

for arquivo in lista_arquivos:

        pegar_infos(arquivo)

A estrutura que printa uma informação para nós já está pronta. Temos agora que armazenar essas informações para criar uma tabela, para isso vamos precisar da biblioteca Pandas, para instalar escreva no terminal:

> pip install Pandas numpy openpyxl

Feito isso importe para o código a biblioteca pandas e crie uma variável chamada Colunas para começarmos a nossa tabela, essa variável vai receber os nomes de cada coluna que queremos criar:

import xmltodict

import os

import pandas as pd

def pegar_infos(nome_arquivo):

        print(f”Pegou as informações {nome_arquivo}”)

        with open(f’nfs/{nome_arquivo}’, “rb”) as arquivo_xml:

                 dic_arquivo = xmltodict.parse(arquivo_xml)

                 if “NFe” in dic_arquivo:

infos_nf = dic_arquivo[“Nfe”][“infNfe”]

            else:

                  infos_nf = dic_arquivo[“nfeProc”][“NFe”][“infNFe”]

            numero_nota = infos_nf [“@ld”]

            empresa_emissora = infos_nf [“emit”] [“xNome”]

            nome_cliente = infos_nf [“dest”] [“xNome”]

            endereço = infos_nf [“dest”] [“enderDest”]

            if “vol” in infos_nf[“transp”]

                  peso = infos_nf [“transp”] [“vol”] [“pesoB”]

            else:

                  peso = “Não informado”

            print(numero_nota, empresa_emissora, nome_cliente, endereço, peso, sep=”\n”)

lista_arquivos = os.listdir(“nfs”)

colunas = [“numero_nota”, “empresa_emissora”, “nome_cliente”, “endereco”, “peso”]

for arquivo in lista_arquivos:

        pegar_infos(arquivo)

Vamos fazer mais algumas alterações no código como criar uma variável valores que vai pegar as informações e armazená-las em uma lista. Essa lista vai começar vazia.

Vamos passar essa variável dentro de “pergar_infos” e assim conseguimos editar os valores ao invés de printá-los.

Fique atento as mudanças no código abaixo, vou deixá-las em negrito para você perceber melhor:

import xmltodict

import os

import pandas as pd

def pegar_infos(nome_arquivo, valores):

        print(f”Pegou as informações {nome_arquivo}”)

        with open(f’nfs/{nome_arquivo}’, “rb”) as arquivo_xml:

                 dic_arquivo = xmltodict.parse(arquivo_xml)

                 if “NFe” in dic_arquivo:

infos_nf = dic_arquivo[“Nfe”][“infNfe”]

                 else:

                         infos_nf = dic_arquivo[“nfeProc”][“NFe”][“infNFe”]

                 numero_nota = infos_nf [“@ld”]

                 empresa_emissora = infos_nf [“emit”] [“xNome”]

                 nome_cliente = infos_nf [“dest”] [“xNome”]

                 endereço = infos_nf [“dest”] [“enderDest”]

                 if “vol” in infos_nf[“transp”]

                         peso = infos_nf [“transp”] [“vol”] [“pesoB”]

                 else:

                         peso = “Não informado”

                 valores.append ([numero_nota, empresa_emissora, nome_cliente, endereço, peso])

lista_arquivos = os.listdir(“nfs”)

colunas = [“numero_nota”, “empresa_emissora”, “nome_cliente”, “endereco”, “peso”]

valores = [

#ex->[linha1],

        [linha1],

        [linha1]

#dentro desta variável cada linha vai corresponder a uma nota fiscal, as informações das notas vão estar organizadas por linha da tabela.

]

for arquivo in lista_arquivos:

        pegar_infos(arquivo, valores)

Obs. As partes onde temos o # são comentários explicativos no código e não fazem parte da estrutura.

Continuando, quando o For terminar, todas as informações da tabela estarão completas, então só nos resta criar a tabela colocando nela os parâmetros para a coluna, (nome do parâmetro para associação -> “columns”) e os parâmetros para as informações (nome do parâmetro para associação ->“data”).

import xmltodict

import os

import pandas as pd

def pegar_infos(nome_arquivo, valores):

        print(f”Pegou as informações {nome_arquivo}”)

        with open(f’nfs/{nome_arquivo}’, “rb”) as arquivo_xml:

                 dic_arquivo = xmltodict.parse(arquivo_xml)

                 if “NFe” in dic_arquivo:

infos_nf = dic_arquivo[“Nfe”][“infNfe”]

                 else:

                         infos_nf = dic_arquivo[“nfeProc”][“NFe”][“infNFe”]

                 numero_nota = infos_nf [“@ld”]

                 empresa_emissora = infos_nf [“emit”] [“xNome”]

                 nome_cliente = infos_nf [“dest”] [“xNome”]

                 endereço = infos_nf [“dest”] [“enderDest”]

                 if “vol” in infos_nf[“transp”]

                         peso = infos_nf [“transp”] [“vol”] [“pesoB”]

                 else:

                         peso = “Não informado”

                 valores.append ([numero_nota, empresa_emissora, nome_cliente, endereço, peso])

lista_arquivos = os.listdir(“nfs”)

colunas = [“numero_nota”, “empresa_emissora”, “nome_cliente”, “endereco”, “peso”]

valores = []

for arquivo in lista_arquivos:

        pegar_infos(arquivo, valores)

tabela = pd.DataFrame(columns=colunas, datas=valores)

print(tabela)

Quando rodarmos o código agora, a tabela já estará sendo gerada no nosso terminal, só falta transformá-la em uma tabela de Excel.

Podemos comentar ou retirar a linha que está printando acima do with, neste exemplo vou comentar colocando um # na frente apenas para ficar mais visível onde foi excluída a linha.

Feito isso vamos transformar a tabela em uma tabela Excel passando o parâmetro de index igual a falso para que os números das linhas comuns no Python não sejam passados para a tabela Excel, pois não tem necessidade.

import xmltodict

import os

import pandas as pd

def pegar_infos(nome_arquivo, valores):

        #print(f”Pegou as informações {nome_arquivo}”) -> linha excluida

        with open(f’nfs/{nome_arquivo}’, “rb”) as arquivo_xml:

                 dic_arquivo = xmltodict.parse(arquivo_xml)

                 if “NFe” in dic_arquivo:

infos_nf = dic_arquivo[“Nfe”][“infNfe”]

                 else:

                         infos_nf = dic_arquivo[“nfeProc”][“NFe”][“infNFe”]

                 numero_nota = infos_nf [“@ld”]

                 empresa_emissora = infos_nf [“emit”] [“xNome”]

                 nome_cliente = infos_nf [“dest”] [“xNome”]

                 endereço = infos_nf [“dest”] [“enderDest”]

                 if “vol” in infos_nf[“transp”]

                         peso = infos_nf [“transp”] [“vol”] [“pesoB”]

                 else:

                         peso = “Não informado”

                 valores.append ([numero_nota, empresa_emissora, nome_cliente, endereço, peso])

lista_arquivos = os.listdir(“nfs”)

colunas = [“numero_nota”, “empresa_emissora”, “nome_cliente”, “endereco”, “peso”]

valores = []

for arquivo in lista_arquivos:

        pegar_infos(arquivo, valores)

tabela = pd.DataFrame(columns=colunas, datas=valores)

#print(tabela) -> linha excluída

tabela.to_excel(“NotasFiscais.xlsx”, index=False)

Feito isso rode o código, assim que ele terminar vai surgir um arquivo do lado esquerdo da tela chamado pelo nome que escolhemos no código -> NotasFiscais.xlsx.

Abra este arquivo clicando sobre a pasta com o botão direito do mouse e em seguida em Reveal in File Explorer, e você terá a lista em Excel com todos os dados.

freela python 1

Prontinho, este projeto pode te gerar lucro, pois foi tirado de um site onde se paga para trabalhos como este feitos com Python, este trabalho estava avaliado entre 100 e 500 reais e fizemos ele em pouco mais de quarenta minutos.

Se você nunca teve contato com Python pode achar que é um trabalho mais difícil, porém, para quem já tem algum contato com a linguagem o conhecimento usado para fazer esse trabalho foi simples usando apenas bibliotecas e criando um script.

Você ainda pode transformá-lo em um executável ou fazer mais adaptações.

Conclusão – Freela de Python

Nesta aula nosso objetivo foi criar um script para um serviço de freelance que selecione e retire informações de 500 arquivos xml.

Agora, com o código pronto basta que você coloque os arquivos xml na pasta nfs e rode o código, assim ele irá resultar em um arquivo Excel com todos os dados que foram solicitados pelo cliente que pediu o projeto.

Espero que tenham gostado dessa aula focada em projetos!

Eu fico por aqui! Um abraço,

Hashtag Treinamentos

Para acessar outras publicações de Python, clique aqui!


Quer aprender mais sobre Python com um minicurso básico gratuito?