PROGRAMANDO PARA A WEB EM PYTHON

 

 

Web em Python

Python é uma linguagem muito versátil, podendo ser usada para vários fins. Um dos nichos em que Python mais tem sido usada ultimamente é no desenvolvimento web. E quando se trata de web, temos várias ferramentas disponíveis para usar com Python. Este post irá apresentar a forma mais simples de todas: o CGI (Common Gateway Interface).

CGI

O funcionamento do CGI é bem simples: ao receber uma requisição, o servidor web roda um programa executável para gerar o conteúdo a ser retornado para o cliente (é esse programinha executável que vamos implementar). Assim, um programinha bem simples que poderia funcionar juntamente com um servidor CGI é:

1
2
3
4
5
6
#!/usr/bin/python
# cabecalho que informa o browser para renderizar como HTML
print "Content-Type: text/html\n\n"
# o conteudo em si
print "<strong>Hello, world!</strong>"

Se você quiser brincar um pouquinho com CGI, siga os seguintes passos:

  1. Crie uma pasta chamada src e dentro dela outra pasta chamada cgi-bin;
  2. Salve o arquivo acima como hello.py dentro da pasta cgi-bin recém criada;
  3. Dê permissão de execução ao arquivo hello.pychmod +x hello.py;
  4. Pelo shell de comandos do seu sistema operacional, vá até a pasta src e execute o servidorzinho CGI que Python traz consigo: python -m CGIHTTPServer 8000
  5. Abra um navegador e acesse a URL: http://localhost:8000/cgi-bin/hello.py
  6. Como resultado, você deverá ver a mensagem “Hello, world!” em negrito no seu navegador.

Mas, para que faça sentido, é preciso que nosso aplicativo seja capaz de obter eventuais informações que o usuário passar a ele. Usando o módulo cgi, podemos manipular parâmetros fornecidos pelo usuário, dentre outras possibilidades. Veja o exemplo abaixo:

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python
import cgi
# obtem referencia as variaveis passadas pelo cliente
fields = cgi.FieldStorage()
# cabecalho que informa o browser para renderizar como HTML
print "Content-Type: text/html\n\n"
nome = fields.getvalue('nome')
print "<strong>Hello, %s!</strong>" % (nome)

Salve o arquivo acima no mesmo diretório cgi-bin com o nome de hellouser.py, dê permissão de execução para o mesmo (chmod +x hellouser.py) e então acesse no seu browser: http://localhost:8000/hellouser.py?nome=Seu Nome Aqui.

Como você deve saber, /hellouser.py?nome=Seu Nome Aqui significa que estamos passando para o “programa” /hellouser.py a variável nome com o valor Seu Nome Aqui, tudo pela URL, através do método HTTP GET.

Preparando a implementação do serviço

Antes de sairmos implementando detalhes do serviço web que nos comprometemos a implementar, vamos criar uma funçãozinha que será parte essencial do nosso projeto. Essa função irá receber 3 valores: dia, mês e ano, e irá retornar o dia da semana em forma de string. Por exemplo:

dia_da_semana(27, 3, 2013) --retorna--> "Quarta-feira"
dia_da_semana(24, 3, 2013) --retorna--> "Domingo"

Para implementá-la, vamos usar o método weekday() dos objetos date, disponível no módulo datetime. A documentação dessa função diz o seguinte (tradução própria):

Retorna o dia da semana como um inteiro, onde Segunda-feira é 0 e Domingo é 6.

Assim, tudo o que teremos que fazer é construir uma instância de date com os dados fornecidos como parâmetro para nossa função, e invocar o método weekday() nesse objeto. Exemplo:

1
2
3
4
>>> from datetime import date
>>> d = date(2013, 3, 27)
>>> print d.weekday()
2

2 significa que a data em questão, 27/03/2013 cai numa Quarta-feira, visto que Segunda-feira é 0 e que Domingo é 1. Perceba que para construir um objeto do tipo date, nós passamos as informações sobre dia, mês e ano em ordem inversa à que estamos acostumados no Brasil. A assinatura do método construtor de objetos date é:

date(ano, mês, dia)

Perfeito, agora só falta definirmos uma forma de obtermos os nomes dos dias em língua portuguesa. Vamos usar uma abordagem bem simples, mas que resolve nosso problema. Vamos usar uma lista contendo as strings representando os dias da semana. (claro que se fôssemos dar suporte a usuários de vários países, a história seria diferente)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from datetime import date
dias = [
    'Segunda-feira',
    'Terça-feira',
    'Quarta-feira',
    'Quinta-feira',
    'Sexta-feira',
    'Sábado',
    'Domingo'
]
def dia_da_semana(dia, mes, ano):
    try:
        return dias[date(ano, mes, dia).weekday()]
    except ValueError:
        return 'Erro: data mal-formatada.'

Simples, huh? Utilizamos o inteiro retornado pelo método weekday() como índice para nossa lista com os nomes dos dias da semana. Além disso, envolvemos nosso código com try-except pois o usuário pode muito bem fornecer uma data inválida, como 31/02/2013 ou 100/123/2013. O construtor date() levanta a exceção ValueError quando recebe parâmetros que não representam uma data válida.

Feito isso, agora podemos implementar nosso serviço. (leia atentamente o código acima, caso não tenha entendido algo)

Implementando o serviço web

Já vimos como implementar um aplicativozinho web beeeeeeeem simples usando CGI, também já vimos como obter o dia da semana em que determinada data cai, e num post anterior vimos como codificar e decodificar dados em formato JSON. Agora, basta juntarmos as peças para implementar o serviço.

Só para relembrar, estamos implementando um serviço web que retorna o dia da semana relativo à determinada data fornecida pelo usuário. O usuário irá fornecer a data no formato dd/mm/aaaa. Por exemplo, o usuário pode solicitar a data fazendo uma requisição ao serviço da seguinte forma: http://um.host.qualquer.com/diasemana.py?data=27/3/2013.

Segue o código do nosso serviço:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/bin/python
# -*- encoding:utf-8 -*-
import cgi
import json
from datetime import date
dias = [
    'Segunda-feira',
    'Terça-feira',
    'Quarta-feira',
    'Quinta-feira',
    'Sexta-feira',
    'Sábado',
    'Domingo'
]
def quebra_data(data):
    if (data.count('/') == 2 and
            all((x.isdigit() for x in data.split('/')))):
        return [int(x) for x in data.split('/')]
    else:
        raise ValueError
def dia_da_semana(data):
    try:
        dia, mes, ano = quebra_data(data)
        return dias[date(ano, mes, dia).weekday()]
    except ValueError:
        return 'Erro: data mal-formatada.'
print "Content-Type: text/json\n\n"
fields = cgi.FieldStorage()
data = fields.getvalue('data')
dia_str = dia_da_semana(data) if data is not None else 'Erro'
print json.dumps({'data': data, 'diasemana': dia_str})

Como a data fornecida pelo usuário é recebida no programa através do cgi.FieldStorage() sob a forma de string, é preciso que separemos essa data em dia, mês e ano. Para isso, criamos a função quebra_data() que antes de mais nada verifica se a data fornecida pelo usuário está no formato adequado (dia/mês/ano), e caso não esteja, a função levanta uma exceção ValueError para ser capturada pela função dia_da_semana(). Se a data estiver no formato correto, é retornada uma lista com três valores inteiros: dia, mês e ano. O método split(), usado em nossa função quebra_datasepara a string em questão em todas as ocorrências do caractere separador fornecido como entrada ('/') e retorna uma lista contendo as substrings.

Ao final de nosso programinha, geramos um dicionário com as informações a serem codificadas em JSON e então imprimimos a informação JSONificada.

Momento “Lição de Vida”

Como você pode perceber lendo o código acima, boa parte da lógica do programa envolve a verificação dos dados fornecidos pelo usuário. Em se tratando de serviços ou aplicativos web, nunca podemos ser relapsos com os dados fornecidos pelo usuário, afinal o sistema está exposto pela web, podendo ser acessado de qualquer lugar do mundo, por pessoas com os mais variados níveis de conhecimento e com as mais variadas intenções. Às vezes, a falta de validação de um simples dado fornecido pelo usuário pode ser o suficiente para que o usuário destrua o nosso serviço ou, o que muitas vezes é pior, obtenha acesso à informações que deveriam ser sigilosas.

Portanto, nunca deixe de verificar todo e qualquer dado que um usuário forneça para o seu sistema. Às vezes ficamos com preguiça, com pena de poluir o código com “todas aquelas validações”, ou até achando que “os nossos usuários nunca tentariam sacanear o sistema”, mas não caia na bobagem de seguir esses pensamentos. Existem várias histórias de sistemas que foram destruídos e de pessoas que perderam seus empregos por deixar de filtrar os dados fornecidos pelo usuário.

Python + CGI está na crista da onda, então?

Não. Programação web com CGI nada mais é do que escrevermos programas que serão executados pelo servidor web quando houver uma requisição para eles. Essa simplicidade toda tem o seu custo: a cada requisição recebida pelo servidor web, ele inicia um novo processo que irá executar o código do recurso solicitado. Assim, recursos que de outra forma poderiam ser compartilhados entre instâncias são perdidos ao fim de cada processo. Conexões com o banco de dados, por exemplo, são reestabelecidas a CADA requisição feita para o serviço quando usamos CGI. Ou seja, sistemas web baseados em CGI dificilmente irão escalar quando necessário for.

Além disso, programar somente com CGI não é muito prático, pois temos que nos preocupar com diversos elementos que podem ser abstraídos e passados para uma outra camada. E outra coisa, código Python imprimindo HTML é muito anos 90! 😉

Para facilitar a nossa vida e resolver alguns dos problemas acima descritos, existem os frameworks para desenvolvimento web, que serão assunto para um próximo post.

Então CGI é inútil?

Não, longe disso. Com CGI, podemos executar programas remotamente e, de lambuja, ver o resultado da execução desse programa em nosso navegador. Se ele gerar HTML na saída, melhor ainda! 🙂

MAS, é claro que não vamos deixar exposto na web um programa que apaga todos os arquivos do disco rígido do servidor em que está rodando. 😛 Só que nada impede que disponibilizemos um scriptzinho inocente via CGI para que outra pessoa possa o acessá-lo remotamente, sem a necessidade de possuir acesso SSH àquela máquina. O legal é que tudo que é preciso para o acesso é um web browser, e, como você sabe, hoje em dia até as TVs possuem web browsers, sem falar nos telefones celulares.

www.revanger.com www.erguvanhaber.com www.erzurumozelders.com www.tekirdagtabldot.com www.gebzesaadet.com www.balikesiryenihaber.com www.ucanbalonmugla.com www.aymaras.com www.buyukorduhaber.com www.ambushm.com www.trabzonpostasi.com www.yalovaradyotv.com www.internetedirne.com www.duzcepark.com www.butuncanakkale.com www.ssgolfhotel.com www.ispartaradyonet.com www.tokathaberi.com www.tokathabersitesi.com www.escortlarrize.net www.sivashbr.net www.sivashaberci.com www.manisaotolastik.com www.yeniyasamgorukle.com www.alanyamado.com www.manavgatx.com