martes 1 de abril de 2008

Webservice Rústicos: aprobechando servicios POST en internet

En este articulo muestro como aprobechar la funcionalidad de un form de html en una pagina en internet. Este articulo muestra como obtener traducciones de texto desde la pagina de google (http://translate.google.com), pero explicando paso a paso el desarrollo del ejemplo. Como lenguaje uso python por lo facil que hacer y probar cosas con este.

En primer lugar le damos un vistazo a la interfaz, por ejemplo entramos a la pagina, elegimos las opciones de traduccion, ponemos un texto, y le damos al boton "Traduzca", nos queda lo siguiente:



Bueno aca lo importante es el codigo html, así que lo que hacemos es visualizar dicho codigo, y vemos que llega bastante feo, todo de corrido sin ningun formato..., pero despues de un buen rato de dar vueltas, buscamos en el codigo la parte que nos interesa (la del formulario de traduccion de texto).

Tomamos el codigo y lo llevamos a nuestro buen amigo editor de texto, lo formateamos un poco, borramos todo lo que nos sobre, y tenemos algo así:



De la declaracion del form identificamos las dos cosas mas importantes:

1. Url a enviar los datos:
'http://translate.google.com/translate_t?langpair='+this.langpair.value;", que es seteada en base a la seleccion del langpair por ejemplo es|en, (despues cuando veas los parametros se va a notar mas esto) y entonces puede llegar a quedar algo así:
'http://translate.google.com/translate_t?langpair=es|en'

2. Si los parametros viajan por el metodo POST o GET:
Para nuestro caso es claro que dice POST (dice claramente method=post)

Sin dar mas vueltas ojeamos los parametros:
un input oculto (hidden) de nombre 'hl' y que para nuestro caso su valor sera 'es' segun dice el codigo.
un input oculto de nombre 'ie' que dice el encoding, el cual rellenamos con el valor 'UTF-8' segun dice en el codigo
un textarea de nombre 'text' en el cual pondremos nuestro texto a traducir.
un ultimo parametro de nombre 'langpair' y que debe seleccionarse de la larga lista, por ejemplo si traducimos desde español a la lengua de bill decimos 'es|en' en este campo.

En resumen:
hl=es
ie=UTF-8
text=el perro es blanco
langpair=es|en

entonces en python el codigo de invocacion al sercio queda algo así:

19 def getTranslation (fromLang, toLang, text):
20 import urllib
21 import urllib2
22 langpair=fromLang+"|"+toLang
23 url = "http://translate.google.com/translate_t?langpair="+langpair
24 values = {'hl':"es",'ie':"UTF-8",'text':text,"langpair":langpair}
25 # Falla si se deja el agent por default en urllib2
26 headers = { 'User-Agent' : 'Mozilla'}
27 data = urllib.urlencode(values)
28 req = urllib2.Request(url, data,headers)
29 response = urllib2.urlopen(req)
30 lines = response.readlines ()
31 return extractTranslation (lines)
32

al hacer urlencode (values) no hace mas que formar una cadena con los parametros formateados como para enviar los datos con GET:

> print data
langpair=es%7Cen&text=El+Perro+es+blanco&ie=UTF-8&hl=es

así que este es el punto clave en que se define la forma de enviar los datos, nosotros utilizaremos POST, así que proseguimos.

Proseguimos formando el POST request con los datos codificados mas los headers adicionales,

req = urllib2.Request(url, data,headers),

y luego hacer:

response = urllib2.urlopen(req)

lo que hacemos en enviar todos los datos por el metodo POST.

Para finalizar leemos tooooda la respuesta desde el par que responde, esta no es mas que todo el codigo de la pagina que google nos muestra al darle click al boton traducir, pero en fin, el texto traducido esta ahí en su interior.
Lo que hacemos para encontrar el texto de una forma mas o menos sencilla y elegante, es utilizar expresiones regulares para analizar el texto. Pero antes de hacer cualquier cosa, le pasamos la vista por encima a la parte del codigo que tiene la traduccion, y lo encontramos por ejemplo buscando alguna palabra que sabemos que esta ahí:
entonces:
Entonces podemos notar que el tag que encierra el texto traducido es unico en el codigo:

<div id=result_box dir="ltr"> Nuestro texto traducido</div>

Entonces ahora si podemos hacer uso de expresiones regulares para generar nuestra funcion extractTraduction ():

5 def extractTranslation (lines):
6 import re
7 expr = ".*<div id=result_box dir=\"ltr\">(?P<Translation>([^<]+(<br>)*)*)</div>.*"
8 pattern = re.compile (expr)
9 for l in lines:
10 m = pattern.match (l)
11 if m:
12 res = m.group ("Translation")
13 res = res.replace ("&lt;","<")
14 res = res.replace ("&gt;",">")
15 res = re.sub ("([ ]*<br>[ ]*)","\n",res)
16 return res
17 return None
18
Bueno la cosa esta asi, nuestra expresion busca por una cantidad indefinida de caracteres que no incluya el < (que marca el fin al aparecer en ) o que lo incluya pero en una expresion que marca nueva linea. Una vez encontrado el texto, lo que se hace es reemplazar algunas cosas de html antes de retornalas, por ejemplo si nuestro texto a traducir incluía un <>, entonces la traduccion es retornada con los codigos de estos: < e >, entonces ahora tenemos que restaurarlos, también, cada caracter de nueva linea (\n) es simbolizado como
en html, entonces tenemos que reemplazarlos tambien.

En fin, este codigo es bastante sencillo, así que lo dejo terminado:
Texto plano:

#!/usr/bin/python
#autor: jonatan anauati
#email: barakawins@gmail.com
#licencia: LGPL
def extractTranslation (lines):
import re
expr = ".*<div id=result_box dir=\"ltr\">(?P<Translation>([^<]+(<br>)*)*)</div>.*"
pattern = re.compile (expr)
for l in lines:
m = pattern.match (l)
if m:
res = m.group ("Translation")
res = res.replace ("&lt;","<")
res = res.replace ("&gt;",">")
res = re.sub ("([ ]*<br>[ ]*)","\n",res)
return res
return None

def getTranslation (fromLang, toLang, text):
import urllib
import urllib2
langpair=fromLang+"|"+toLang
url = "http://translate.google.com/translate_t?langpair="+langpair
values = {'hl':"es",'ie':"UTF-8",'text':text,"langpair":langpair}
# Falla si se deja el agent por default en urllib2
headers = { 'User-Agent' : 'Mozilla'}
data = urllib.urlencode(values)
req = urllib2.Request(url, data,headers)
response = urllib2.urlopen(req)
lines = response.readlines ()
return extractTranslation (lines)


if __name__ == "__main__":
# un ejemplo
lines = getTranslation ("es","en","El perro es blanco\nAzul\n\nverde")
if lines:
print "RESULTADO"
print lines


1 ---INICIO---
2 ---google_post.b64---
3 ---para desempaquetarlo---
4 ---openssl base64 -d -in google_post.b64 -out google_post.py---
5 IyEvdXNyL2Jpbi9weXRob24KI2F1dG9yOiBqb25hdGFuIGFuYXVhdGkKI2VtYWls
6 OiBiYXJha2F3aW5zQGdtYWlsLmNvbQojbGljZW5jaWE6IExHUEwKZGVmIGV4dHJh
7 Y3RUcmFuc2xhdGlvbiAobGluZXMpOgogICAgaW1wb3J0IHJlCiAgICBleHByID0g
8 Ii4qPGRpdiBpZD1yZXN1bHRfYm94IGRpcj1cImx0clwiPig/UDxUcmFuc2xhdGlv
9 bj4oW148XSsoPGJyPikqKSopPC9kaXY+LioiCiAgICBwYXR0ZXJuICAgPSByZS5j
10 b21waWxlIChleHByKQogICAgZm9yIGwgaW4gbGluZXM6CiAgICAgICAgbSA9IHBh
11 dHRlcm4ubWF0Y2ggKGwpCiAgICAgICAgaWYgbToKICAgICAgICAgICAgcmVzID0g
12 bS5ncm91cCAoIlRyYW5zbGF0aW9uIikKICAgICAgICAgICAgcmVzID0gcmVzLnJl
13 cGxhY2UgKCImbHQ7IiwiPCIpCiAgICAgICAgICAgIHJlcyA9IHJlcy5yZXBsYWNl
14 ICgiJmd0OyIsIj4iKQogICAgICAgICAgICByZXMgPSByZS5zdWIgKCIoWyBdKjxi
15 cj5bIF0qKSIsIlxuIixyZXMpCiAgICAgICAgICAgIHJldHVybiByZXMKICAgIHJl
16 dHVybiBOb25lCgpkZWYgZ2V0VHJhbnNsYXRpb24gKGZyb21MYW5nLCB0b0xhbmcs
17 IHRleHQpOgogICAgaW1wb3J0IHVybGxpYgogICAgaW1wb3J0IHVybGxpYjIgIAog
18 ICAgbGFuZ3BhaXI9ZnJvbUxhbmcrInwiK3RvTGFuZwogICAgdXJsID0gImh0dHA6
19 Ly90cmFuc2xhdGUuZ29vZ2xlLmNvbS90cmFuc2xhdGVfdD9sYW5ncGFpcj0iK2xh
20 bmdwYWlyCiAgICB2YWx1ZXMgPSB7J2hsJzoiZXMiLCdpZSc6IlVURi04IiwndGV4
21 dCc6dGV4dCwibGFuZ3BhaXIiOmxhbmdwYWlyfQogICAgIyBGYWxsYSBzaSBzZSBk
22 ZWphIGVsIGFnZW50IHBvciBkZWZhdWx0IGVuIHVybGxpYjIKICAgIGhlYWRlcnMg
23 PSB7ICdVc2VyLUFnZW50JyA6ICdNb3ppbGxhJ30KICAgIGRhdGEgPSB1cmxsaWIu
24 dXJsZW5jb2RlKHZhbHVlcykKICAgIHJlcSA9IHVybGxpYjIuUmVxdWVzdCh1cmws
25 IGRhdGEsaGVhZGVycykKICAgIHJlc3BvbnNlID0gdXJsbGliMi51cmxvcGVuKHJl
26 cSkKICAgIGxpbmVzID0gcmVzcG9uc2UucmVhZGxpbmVzICgpCiAgICByZXR1cm4g
27 ZXh0cmFjdFRyYW5zbGF0aW9uIChsaW5lcykKCgppZiBfX25hbWVfXyA9PSAiX19t
28 YWluX18iOgogICAgIyB1biBlamVtcGxvCiAgICBsaW5lcyA9IGdldFRyYW5zbGF0
29 aW9uICgiZXMiLCJlbiIsIkVsIHBlcnJvIGVzIGJsYW5jb1xuQXp1bFxuXG52ZXJk
30 ZSIpCiAgICBpZiBsaW5lczoKICAgICAgICBwcmludCAiUkVTVUxUQURPIgogICAg
31 ICAgIHByaW50IGxpbmVzCg==

--- FIN ---

Etiquetas: , , , , , , ,

0 comentarios:

Publicar un comentario en la entrada

Suscribirse a Enviar comentarios [Atom]

<< Página principal