12. Serviços web em Python
![]() |
Os scripts em Python podem ser executados por um servidor WEB. É esse servidor que ficará à espera das solicitações dos clientes. Do ponto de vista do cliente, chamar um serviço WEB equivale a solicitar o URL desse serviço. O cliente pode ser escrito em qualquer linguagem, inclusive em Python. Precisamos saber “conversar” com um serviço WEB, ou seja, compreender o protocolo Http de comunicação entre um servidor web e seus clientes. Esse é o objetivo dos programas a seguir.
Os scripts do serviço web serão executados pelo servidor web Apache do WampServer. É necessário colocá-los em um diretório específico: <WampServer>\bin\apache\apachex.y.z\cgi-bin, onde <WampServer> é a pasta de instalação do WampServer e x.y.z é a versão do servidor web Apache.
![]() |
Colocar os scripts Python na pasta <cgi-bin> não é suficiente. É necessário que o script indique, na primeira linha, o caminho do interpretador Python a ser utilizado. Esse caminho é inserido na forma de um comentário:
O leitor deverá adaptar esse caminho ao seu próprio ambiente.
12.1. Aplicativo cliente/servidor de data e hora
Nosso primeiro serviço web será um serviço de data e hora: o cliente recebe a data e a hora atuais.
12.1.1. O servidor
#!D:\Programas\ActivePython\Python2.7.2\python.exe
import time
# cabeçalhos
print "Content-Type: text/plain\n"
# envio da hora ao cliente
# hora local: número de milissegundos desde 01/01/1970
# "formato de exibição de data e hora
# d: dia com 2 dígitos
# m: mês com 2 dígitos
# y: ano com 2 dígitos
# H: hora 0,23
# M: minutos
# S: segundos
print time.strftime('%d/%m/%y %H:%M:%S',time.localtime())
Observações:
- linha 6: o script deve gerar por conta própria alguns dos cabeçalhos HTTP da resposta ao cliente. Eles serão adicionados aos cabeçalhos HTTP gerados pelo próprio servidor Apache. O cabeçalho HTTP da linha 6 indica ao cliente que será enviado a ele um recurso no formato text/plain, ou seja, texto não formatado. Observe-se o “\n” no final do cabeçalho, que irá gerar uma linha vazia após o cabeçalho. Isso é obrigatório: é essa linha vazia que sinaliza ao cliente HTTP o fim dos cabeçalhos HTTP da resposta. Em seguida, vem o recurso solicitado pelo cliente, neste caso, um texto não formatado;
- linha 18: o recurso enviado ao cliente é um texto que exibe a data e a hora atuais.
12.1.2. Dois testes
O script anterior pode ser executado diretamente pelo interpretador Python em uma janela de comandos, como fizemos até agora. Isso permite eliminar possíveis erros de sintaxe ou de funcionamento. Obtém-se o seguinte resultado:
Depois que o script for testado dessa forma, ele pode ser colocado na pasta <cgi-bin> do servidor Apache (ver parágrafo 12). Vamos iniciar o aplicativo WampServer. Isso inicia simultaneamente um servidor web Apache e um SGBD MySQL. Por enquanto, usaremos apenas o servidor web. Em seguida, usando um navegador, acessemos a seguinte URL: http://localhost/cgi-bin/web_02.py:
![]() |
- em [1]: o URL solicitado;
- em [2]: a resposta exibida pelo navegador;
- em [3]: o código-fonte recebido pelo navegador. É exatamente o mesmo enviado pelo script Python.
Com algumas ferramentas (neste caso, o Firebug, um complemento do navegador Firefox), é possível acessar os cabeçalhos HTTP trocados com o servidor. Acima, o navegador recebeu os seguintes cabeçalhos HTTP:
Nas linhas 7 e 8, reconhece-se o cabeçalho HTTP enviado pelo script Python. Os que vêm antes foram gerados pelo servidor web Apache.
12.1.3. Um cliente programado
Vamos agora escrever um script que atuará como cliente do serviço web anterior. Utilizamos as funcionalidades do módulo httplib, que facilita a criação de clientes HTTP.
# -*- coding=utf-8 -*-
import httplib,re
# constantes
HOST="localhost"
URL="/cgi-bin/web_02.py"
# conexão
connexion=httplib.HTTPConnection(HOST)
# rastreamento
connexion.set_debuglevel(1)
# envio da solicitação
connexion.request("GET", URL)
# processamento da resposta
reponse=connexion.getresponse()
# conteúdo
contenu=reponse.read()
# encerramento da conexão
connexion.close()
print "------\n",contenu,"-----\n"
# recuperação dos elementos da hora
elements=re.match(r"^(\d\d)/(\d\d)/(\d\d) (\d\d):(\d\d):(\d\d)\s*$",contenu).groups()
print "Jour=%s,Mois=%s,An=%s,Heures=%s,Minutes=%s,Secondes=%s" % (elements[0],elements[1],elements[2],elements[3],elements[4],elements[5])
Notas:
- linha 3: o módulo re é necessário para expressões regulares, e o módulo httplib para as funções dos clientes HTTP;
- linha 9: é criada uma conexão HTTP com a porta 80 do HOST, definida na linha 6;
- linha 11: o monitoramento permite visualizar os cabeçalhos HTTP da solicitação do cliente e da resposta do servidor;
- linha 13: o URL do serviço web é solicitado. Há duas maneiras de solicitá-la: usando um comando HTTP GET ou POST. A diferença entre os dois é explicada mais adiante. Aqui, ela será solicitada com o comando HTTP GET;
- linha 15: a resposta do servidor é lida. Aqui é obtida a resposta completa: cabeçalhos HTTP e o recurso solicitado pelo cliente. Em sua resposta, o servidor pode ter solicitado que o cliente seja redirecionado. Nesse caso, o cliente httplib realiza automaticamente o redirecionamento. A resposta obtida é, portanto, aquela resultante do redirecionamento;
- linha 17: a resposta é composta pelos cabeçalhos HTTP e pelo documento solicitado pelo cliente. Para obter apenas os cabeçalhos HTTP, utilizar-se-á [reponse].getHeaders(). Para obter o documento, utiliza-se [reponse].read();
- linha 19: uma vez obtida a resposta do servidor web, a conexão com ele é encerrada;
- sabe-se que o documento enviado pelo servidor é uma linha de texto no formato 15/06/11 14:56:36. Nas linhas 22 a 26, utiliza-se uma expressão regular para extrair os diferentes elementos dessa linha.
12.1.4. Resultados
Notas:
- linha 1: os cabeçalhos HTTP enviados pelo cliente ao servidor web;
- linhas 2 a 6: os cabeçalhos HTTP da resposta do servidor web;
- linha 8: o documento enviado pelo servidor;
- linha 11: o resultado de sua análise;
12.2. Recuperação pelo servidor dos parâmetros enviados pelo cliente
No protocolo HTTP, um cliente dispõe de dois métodos para passar parâmetros ao servidor web:
- ele solicita o URL do serviço na forma
GET url?param1=val1¶m2=val2¶m3=val3… HTTP/1.0
onde os valores vali devem ser previamente codificados para que certos caracteres reservados sejam substituídos por seus valores hexadecimais.
- ele solicita o URL do serviço na forma
e, em seguida, entre os cabeçalhos HTTP enviados ao servidor, insere o seguinte cabeçalho:
O restante dos cabeçalhos enviados pelo cliente termina com uma linha em branco. Ele pode, então, enviar seus dados na forma
onde os caracteres vali devem, assim como no método GET, ser previamente codificados. O número de caracteres enviados ao servidor deve ser N, sendo que N é o valor declarado no cabeçalho:
12.2.1. O serviço web
O serviço web a seguir recebe três parâmetros de seu cliente: nom, prenom, age. Ele os recupera em uma espécie de dicionário chamado cgi.FieldStorage, fornecido pelo módulo cgi. O valor vali de um parâmetro parami é obtido por meio de vali=cgi.FieldStorage().getlist("parami"). Obtém-se uma matriz com:
- 0 elemento se o parâmetro parami não estiver presente na solicitação do cliente;
- 1 elemento se o parâmetro parami estiver presente 1 vez na solicitação do cliente;
- n elementos se o parâmetro parami estiver presente n vezes na solicitação do cliente.
Após recuperar os parâmetros, o script os retorna ao cliente.
#!D:\Programas\ActivePython\Python2.7.2\python.exe
import cgi
# cabeçalhos
print "Content-Type: text/plain\n"
# recuperação pelo servidor das informações enviadas pelo cliente
# aqui nome=P&sobrenome=N&idade=A
formulaire=cgi.FieldStorage()
# elas são reenviadas ao cliente
print "informations recues du service web [prenom=%s,nom=%s,age=%s]" % (formulaire.getlist("prenom"),formulaire.getlist("nom"),formulaire.getlist("age"))
É possível realizar um teste com um navegador da web:
![]() |
Em [1], o URL do serviço web. Observe a presença dos três parâmetros nom, prenom e age. Em [2], a resposta do serviço web.
12.2.2. O cliente GET
# -*- coding=utf-8 -*-
import httplib,urllib
# constantes
HOST="localhost"
URL="/cgi-bin/web_03.py"
PRENOM="Jean-Paul"
NOM="de la Huche"
AGE=42
# os parâmetros devem ser codificados antes de serem enviados ao servidor
params = urllib.urlencode({'nom': NOM, 'prenom': PRENOM, 'age': AGE})
# os parâmetros são colocados no final do URL
URL+="?"+params
# conexão
connexion=httplib.HTTPConnection(HOST)
# rastreamento
connexion.set_debuglevel(1)
# envio da solicitação
connexion.request("GET",URL)
# processamento da resposta
reponse=connexion.getresponse()
# conteúdo
contenu=reponse.read()
print contenu,"\n"
# encerramento da conexão
connexion.close()
Notas:
- linhas 8-10: os valores dos três parâmetros enviados ao serviço web;
- linha 13: é necessário codificá-los. Isso é feito por meio do método urlencode do módulo urllib. Esse módulo é importado na linha 3. O método aceita como parâmetro um dicionário {param1:val1, param2:val2, ...};
- linha 15: em um comando GET (linha 21), o cliente deve inserir os parâmetros codificados no final do URL do serviço web;
- as linhas seguintes já foram abordadas.
12.2.3. Os resultados
Observações:
- linha 2: observe a codificação dos parâmetros (sobrenome, nome, idade);
- linha 8: a resposta do serviço web.
12.2.4. O cliente POST
O cliente POST é análogo ao cliente GET, exceto que os parâmetros codificados não fazem mais parte do URL de destino. Eles foram passados como terceiro argumento da solicitação POST (linha 19).
# -*- coding=utf-8 -*-
import httplib,urllib
# constantes
HOST="localhost"
URL="/cgi-bin/web_03.py"
PRENOM="Jean-Paul"
NOM="de la Huche"
AGE=42
# os parâmetros devem ser codificados antes de serem enviados ao servidor
params = urllib.urlencode({'nom': NOM, 'prenom': PRENOM, 'age': AGE})
# conexão
connexion=httplib.HTTPConnection(HOST)
# rastreamento
connexion.set_debuglevel(1)
# envio da solicitação
connexion.request("POST",URL,params)
# processamento da resposta
reponse=connexion.getresponse()
# conteúdo
contenu=reponse.read()
print contenu,"\n"
# encerramento da conexão
connexion.close()
12.2.5. Os resultados
Notas:
- observe-se, na linha 2, o método utilizado pelo cliente POST para enviar os parâmetros codificados:
- o cabeçalho HTTP Content-Length indica o número de caracteres que serão enviados ao serviço web;
- esse cabeçalho HTTP é seguido por uma linha vazia, indicando o fim dos cabeçalhos HTTP;
- em seguida, os 39 caracteres dos parâmetros codificados são enviados.
- linha 8: a resposta do serviço web.
12.3. Recuperação das variáveis de ambiente de um serviço web
12.3.1. O serviço web
O script CGI em Python é executado em um ambiente de sistema que possui atributos. Seus atributos e seus valores estão disponíveis em um dicionário os.environ.
#!D:\Programas\ActivePython\Python2.7.2\python.exe
import os
# cabeçalhos
print "Content-Type: text/plain\n"
# informações de ambiente
for (cle,valeur) in os.environ.items():
print "%s : %s" % (cle,valeur)
Notas:
- linha 3: é necessário importar o módulo os para ter acesso às variáveis “do sistema”.
Se executarmos diretamente o script acima (c.a.d, como script de console e não como CGI), obtemos na console os seguintes resultados:
Em um navegador da web (nesse caso, é o script CGI que é executado), obtêm-se os seguintes resultados:
![]() |
Observe-se que, dependendo do contexto de execução, o ambiente obtido não é o mesmo.
12.3.2. O cliente programado
# -*- coding=utf-8 -*-
import httplib
# constantes
HOST="localhost"
URL="/cgi-bin/web_04.py"
# conexão
connexion=httplib.HTTPConnection(HOST)
# envio da solicitação
connexion.request("GET", URL)
# processamento da resposta
reponse=connexion.getresponse()
# conteúdo
print reponse.read()
12.3.3. Resultados
Observe-se que o cliente programado não recebe exatamente a mesma resposta que o navegador da web. Isso ocorre porque este último enviou ao servidor web informações que foram utilizadas pelo servidor web para criar sua resposta. Neste caso, o cliente programado não enviou nenhuma informação sobre si mesmo.




