Introdução e Objetivo do Projeto Completo em Python Rodando no Amazon EC2 Grátis

O objetivo do, tutorial do projeto completo em python rodando no Amazon EC2 grátis, é mostrar como criar uma aplicação em Python 3.7 desde a instalação de todo o software necessário na máquina do desenvolvedor, passando pela criação de um projeto e depois disponibilizar esta aplicação em um servidor virtual na nuvem da Amazon EC2.

Veremos como instalar o Python, o PyCharm, configuração do ambiente e das bibliotecas necessárias.

Criaremos um app que verifica a previsão do tempo diariamente e envia para seu e-mail. Usaremos o Github para guardar e controlar o versionamento do código de forma que fique sempre guardado de forma segura.

Por fim criaremos uma máquina virtual rodando o Ubuntu 18.04 no Amazon Elastic Cloud de forma gratuita para rodar nosso app em Python.

Ferramentas Necessárias

Quais ferramentas e recursos vamos usar? Eis a lista:

  • Python 3.7.
  • Git.
  • Pycharm Community.
  • Uma conta na Amazon EC2.

Instalação do Python e Pycharm

Vá até a página oficial do Python 3.7 para baixar o instalador. Se você usa Windows, dê preferência para versão 64 bits. Se for Mac baixe o instalador 64 bits.

Se o seu computador for 32 bits use a opção azul na figura abaixo.

Depois de baixar o instalador do Python, abra e execute para finalizar o processo.
No Windows eu costumo alterar o local de instalação do Python para C:\Python , isso porque fica mais claro e fácil depois durante a utilização de debugar problemas.

Criar Conta no Github

O Github é um serviço de hospedagem de código fonte com versionamento. O que é isso? Toda vez que você fizer modificações no seu código ao fim do dia ou de alguma parte importante do projeto você realiza o “commit e pull” para o Github. O commit significa salvar as alterações localmente e o pull empurrar as alterações para os servidores do Github.

Desta forma, seu código fonte fica sempre guardado de forma segura. O Github guarda todas as versões ou alterações que você fizer no seu código. Isso é importante até para em caso de um erro você poder voltar atrás e recuperar seu trabalho.

Depois que você criar sua conta no Github você precisa instalar no seu computador o software git que se comunica e faz as transações de commit entre outras para o servidor.

Configuração do Ambiente

Instale primeiramente o python, o git e depois o Pycharm. Nesta sequencia!

Abra o PyCharm para iniciarmos um novo projeto.

Escolha a opção “Create New Project”.

Nesta nova janela, o “location” é a pasta que seu projeto vai ficar. Você pode dar o nome da pasta de acordo com o nome do seu projeto. Como vamos criar um programa que vai na internet buscar as informações de previsão do tempo e depois enviar por e-mail, resolvi dar o nome de hello-weather.
Logo abaixo é a localização da pasta de ambiente virtual (virtual environment).
O que seria isso?

Como cada projeto de Python utiliza bibliotecas que geralmente você vai apenas usar naquele projeto. Então ao invés de instalar todas bibliotecas no seu computador para acesso geral, vamos criar uma pasta dentro do nosso projeto para armazenar apenas as bibliotecas que ele usa.

Uma vantagem de usar o ambiente virtual é que quando você for transportar o seu código, vai saber exatamente quais bibliotecas que ele precisa para rodar. Todo o processo fica mais enxuto. A pasta do nosso ambiente virtual vai se chamar “venv”.

Certifique-se que o PyCharm escolher em “Base interpreter” o Python 3.7.

Clique em “Create”.

Agora temos o PyCharm aberto para começar a escrever nosso código.

Objetivo do Nosso Projeto

Vamos criar um App que tem o seguinte objetivo:

  1. Tem acesso a informações do clima de uma cidade, dados como temperatura, umidade e ventos.
  2. Cria e manda um e-mail usando uma conta no Gmail, contendo essas informações para um endereço de e-mail pré-configurado.

Vamos precisar:

  1. Criar uma conta no OpenWeatherMap para obter uma chave API que será usada pelo nosso app para pegar informações do clima.
  2. Saber a cidade que vamos pegar as informações, por exemplo, para Rio de Janeiro usamos “Rio de Janeiro, BR”. Veja sua cidade aqui.
  3. Ter uma conta no Gmail. (login e senha).

No caso de usar o Gmail você ao invés de usar sua senha normal de acesso, deve criar uma senha específica de aplicativo.

Código Usado no Projeto

Todo código deste projeto está compartilhado no Github.

Clique com o botão direito em cima da pasta hello-weather na esquerda e escolha “new Python file”. Dê o nome de “app.py”.

A primeira parte do código serve para adicionar as bibliotecas que vamos usar:

import smtplib
import email
import email.mime.application
from xml.dom import minidom
import os
import sys
import time
from email.mime.multipart import MIMEMultipart
import pyowm

Desta lista acima, apenas a pyowm não é básica do Python, por isso temos que importa-la para nosso projeto.

Vá em File -> Settings.

Clique em Project: Hello-weather depois em Project Interpreter

Clique no botão (+) que está na direita e pesquise por pyowm.

Clique em “Install Package”.

Nosso projeto tem 4 funções:

getNodetext(node):

É uma função auxiliar para pegar os parâmetros do arquivo config.xml.

def getNodeText(node):
nodelist = node.childNodes
result = [] for node in nodelist:
if node.nodeType == node.TEXT_NODE:
result.append(node.data)

return ''.join(result)

get_Config(cfg):

Esta função tem como entrada o caminho do arquivo de configurações (cfg)_, depois ela lê os parâmetros e os passa para as variáveis que vamos usar.

def get_config(cfg):
global smtp, fromaddr, toaddr, ccaddr, server, port, useSSL, username, passwd, apikey, city

doc = minidom.parse(cfg)
root = doc.getElementsByTagName("config")[0]

apikey = getNodeText(root.getElementsByTagName("apikey")[0])
city = getNodeText(root.getElementsByTagName("city")[0])

smtp = root.getElementsByTagName("smtp")[0]

fromaddr = getNodeText(smtp.getElementsByTagName("from")[0])
toaddr = getNodeText(smtp.getElementsByTagName("to")[0])
ccaddr = getNodeText(smtp.getElementsByTagName("cc")[0])

server = getNodeText(smtp.getElementsByTagName("server")[0])
port = getNodeText(smtp.getElementsByTagName("port")[0])
useSSL = getNodeText(smtp.getElementsByTagName("ssl")[0])
username = getNodeText(smtp.getElementsByTagName("user")[0])
passwd = getNodeText(smtp.getElementsByTagName("password")[0])

send_mail(date, body, subject, smtp, fromaddr, toaddr, ccaddr, server, port, useSSL, username, passwd):

A função que envia o e-mail. Os parâmetros dela são os dados da conta do Gmail, endereços de remetente, destinatário e da mensagem que vamos enviar.

def send_mail(date, body, subject, smtp, fromaddr, toaddr, ccaddr, server, port, useSSL, username, passwd):
msg = MIMEMultipart()

msg['Subject'] = date + " - " + subject
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Cc'] = ccaddr

msg.preamble = 'You will not see this in a MIME-aware mail reader.\n'

if len(server) == 0 or len(port) == 0:
return

rcpt = ccaddr.split(",") + [toaddr]

email_text = """\
From: %s
To: %s
Subject: %s

%s
""" % (fromaddr, ", ".join(rcpt), subject + " : " + date, body)

email_text = "\r\n".join([
"From: " + fromaddr,
"To: " + ", ".join(rcpt),
"Subject: " + date + " - " + subject,
"",
body
])

try:
with smtplib.SMTP(server, port) as s:
s.ehlo()

if useSSL.lower() == 'true':
s.starttls()
else:
s.ehlo()
s.login(fromaddr, passwd)
s.sendmail(fromaddr, rcpt, email_text)
s.close()
print("Email sent!")
except:
print("Unable to send the email. Error: ", sys.exc_info()[0])
raise

get_weather(apikey, location=’Rio de Janeiro, BR’):

A função que pega a previsão do tempo atual para a cidade que escolhermos. Os parâmetros de entrada são a chave API e a localização. Note que para a localização deixei um valor padrão com “Rio de Janeiro, BR”.

def get_weather(apikey, location='Rio de Janeiro, BR'):

owm = pyowm.OWM(apikey)
# observation = owm.weather_at_id(cityid)
w = owm.weather_at_place(location)
weather = w.get_weather()
wind = weather.get_wind()
temp = weather.get_temperature('celsius')
humidity = weather.get_humidity()

report = """
Report for: %s \n
Temperature: %s \n
Winds: %s \n
Humidity: %s
"""

report = report % (location, temp, wind, humidity)
return report

Veja o código completo final:

import smtplib
import email
import email.mime.application
from xml.dom import minidom
import os
import sys
import time
from email.mime.multipart import MIMEMultipart
import pyowm

cfgFile = os.path.realpath('./config.xml')

smtp = ''
fromaddr = ''
toaddr = ''
ccaddr = ''
server = ''
port = ''
useSSL = ''
username = ''
passwd = ''
city = ''
apikey = ''

def getNodeText(node):
nodelist = node.childNodes
result = [] for node in nodelist:
if node.nodeType == node.TEXT_NODE:
result.append(node.data)

return ''.join(result)

def get_config(cfg):
global smtp, fromaddr, toaddr, ccaddr, server, port, useSSL, username, passwd, apikey, city

doc = minidom.parse(cfg)
root = doc.getElementsByTagName("config")[0]

apikey = getNodeText(root.getElementsByTagName("apikey")[0])
city = getNodeText(root.getElementsByTagName("city")[0])

smtp = root.getElementsByTagName("smtp")[0]

fromaddr = getNodeText(smtp.getElementsByTagName("from")[0])
toaddr = getNodeText(smtp.getElementsByTagName("to")[0])
ccaddr = getNodeText(smtp.getElementsByTagName("cc")[0])

server = getNodeText(smtp.getElementsByTagName("server")[0])
port = getNodeText(smtp.getElementsByTagName("port")[0])
useSSL = getNodeText(smtp.getElementsByTagName("ssl")[0])
username = getNodeText(smtp.getElementsByTagName("user")[0])
passwd = getNodeText(smtp.getElementsByTagName("password")[0])

def send_mail(date, body, subject, smtp, fromaddr, toaddr, ccaddr, server, port, useSSL, username, passwd):

msg = MIMEMultipart()

msg['Subject'] = date + " - " + subject
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Cc'] = ccaddr

msg.preamble = 'You will not see this in a MIME-aware mail reader.\n'

if len(server) == 0 or len(port) == 0:
return

rcpt = ccaddr.split(",") + [toaddr]

email_text = """\
From: %s
To: %s
Subject: %s

%s
""" % (fromaddr, ", ".join(rcpt), subject + " : " + date, body)

email_text = "\r\n".join([
"From: " + fromaddr,
"To: " + ", ".join(rcpt),
"Subject: " + date + " - " + subject,
"",
body
])

try:
with smtplib.SMTP(server, port) as s:
s.ehlo()

if useSSL.lower() == 'true':
s.starttls()
else:
s.ehlo()
s.login(fromaddr, passwd)
s.sendmail(fromaddr, rcpt, email_text)
s.close()
print("Email sent!")
except:
print("Unable to send the email. Error: ", sys.exc_info()[0])
raise

def get_weather(apikey, location='Rio de Janeiro, BR'):

owm = pyowm.OWM(apikey)
# observation = owm.weather_at_id(cityid)
w = owm.weather_at_place(location)
weather = w.get_weather()
wind = weather.get_wind()
temp = weather.get_temperature('celsius')
humidity = weather.get_humidity()

report = """
Report for: %s \n
Temperature: %s \n
Winds: %s \n
Humidity: %s
"""

report = report % (location, temp, wind, humidity)
return report

if __name__ == "__main__":

currentdate = time.strftime("%Y-%m-%d %H:%M:%S")

get_config(cfgFile)

body = get_weather(apikey, city)

subject = "Weather report for: " + city

send_mail(currentdate, body, subject, smtp, fromaddr, toaddr, ccaddr, server, port, useSSL, username, passwd)

print("Email sent")

Por fim temos uma função especial que roda apenas se o arquivo app.py for o executado principal. Isso porque no Python poderíamos usar o arquivo app.py como uma biblioteca em outro projeto para usar suas funções, então essa função checa se a execução foi a partir do app.py ou se foi chamada por outro arquivo python.

if __name__ == "__main__":

currentdate = time.strftime("%Y-%m-%d %H:%M:%S")

get_config(cfgFile)

body = get_weather(apikey, city)

subject = "Weather report for: " + city

send_mail(currentdate, body, subject, smtp, fromaddr, toaddr, ccaddr, server, port, useSSL, username, passwd)

print("Email sent")

Experimente rodar esse código dentro do Pycharm.

No menu Run-> Debug, escolha o “app”. Ou aperte no ícone do “bug”.

Se você quiser debugar o código e ver a execução no passo-a-passo, coloque alguns pontos de parada no seu código (ao lado esquerdo da linha de código) antes de iniciar a execução.

Quando a execução chegar no ponto que você colocou vai parar e você pode avançar com o botão da seta para baixo ou apertando a tecla F7.

Compartilhar Código no Github

Agora que temos nosso código pronto, vamos compartilhar ele no Github.

Antes de fazer isso, temos que realizar um passo importante que é criar o arquivo requirements.txt contendo as bibliotecas necessárias para o projeto.

No PyCharm, clique com o botão direito em cima do nome do projeto no navegador de arquivos, escolha “Open in Terminal”.

Digite:


venv\scripts\activate
pip3 freeze -l > requirements.txt

Isso vai jogar o nome de todas bibliotecas usadas no projeto para o arquivo requirements.txt.

Compartilhando no Github ficará mais fácil controlar qualquer alteração no código e sincronizar com o ambiente de produção que será a máquina virtual com Ubuntu hospedada no Amazon EC2.

No menu: VCS-> Import Into Version Control -> Share Project on Github.

O PyCharm vai pedir seu login e senha e vai perguntar o nome do projeto.

Agora, toda vez que você fizer uma alteração no código que seja algo importante, faça um commit (botão verde no topo direito do PyCharm) para que fique salvo no banco de dados local a marcação de versão.

Para atualizar no Github use a função Commit and Push.

IMPORTANTE: O PyCharm por padrão deixa diversos arquivos de configuração dele marcados para compartilhar no Github. Desmarque e marque apenas os arquivos app.py e requirements.txt conforme a figura abaixo.

Por fim, clique em “Commit and Push”.

Conclusões Projeto Completo em Python Rodando no Amazon EC2

Pronto, agora você tem um código funcional em Python que pega a previsão de tempo de um site metereológico e envia para seu email.

Seu código ainda está hospedado seguramente nos servidores do Github.

No próximo artigo veremos como instalar este código no servidor virtual linux no Amazon EC2 de forma grátis.