Tag Archives: Python - Page 3

Aburrido en San Valentín

Python

Mientras algunos salían a divertirse y celebrar el amor en San Valentín, algunos estabamos aburridos en casa, estudiando. Y como estaba aburrido de estudiar, hice este pequeño (y muy estúpido script) en Python que comparto con ustedes.

Lo que hace es buscar la cantidad de apariciones de una palabra/frase en el código de una página web. Pero no busca que exista exactamente esa cadena en el texto, sino que va buscando que aparezcan en orden las letras que componen esa palabra. Por ejemplo, si uno busca “abc” en la cadena “había una vez una casa”, el script va a tomar las letras que marqué en negrita para decir que “abc” existe una vez en la cadena.

¿Y dónde está el amor?

Hasta el momento, San Valentín no entró en la ecuación. Bueno, justamente la idea me surgió para ver cuántas veces una página decía “te amo” y “te odio”. Antes de que se lo pregunten: no, no estaba drogado ni pensando en amores perdidos. De hecho creo que se me ocurrió en el baño jaja.

A continuación, el script:

#!/usr/bin/env python
import sys
import urllib2

if len(sys.argv) < 3:
    print "Please provide a URL an a string to search"
    print "Example: %s ‘http://www.microsoft.com’ ‘i hate u’" % sys.argv[0]
    sys.exit(1)
url = sys.argv[1]
phrase = sys.argv[2]
c = 0
stack = list(phrase)
stack2 = []
string = urllib2.urlopen(url).read()
needle = stack.pop(0)
for char in string:
    if char == needle:
        stack2.append(needle)
        if stack:
            needle = stack.pop(0)
        else:
            stack = stack2
            stack2 = []
            needle = stack.pop(0)
            c = c + 1
print "The URL ‘%s’  says ‘%d’ times ‘%s’" % (url, c, phrase)

Alternativamente, si quieren ignorar los espacios en la cadena a buscar (por ejemplo en “te amo”), es cuestión de reemplazar la línea 12 por esto:

stack = list(phrase.replace(" ", ""))

Y ahora, el ejemplo analizando la página principal de este blog:

$ python valentine.py "http://www.tail-f.com.ar" "te amo"
The URL 'http://www.tail-f.com.ar'  says '238' times 'te amo'
$ python valentine.py "http://www.tail-f.com.ar" "te odio"
The URL 'http://www.tail-f.com.ar'  says '166' times 'te odio'

Parece que este blog está inspirado por más sentimientos de amor que de odio jajaja.

mod_wsgi + Python 2.6 en CentOS

Python

Hace algún tiempo publiqué un artículo donde explicaba cómo instalar mod_python con Python 2.6 en CentOS, por el problemita que tiene yum que no funciona con la última versión de Python. Pues bien, últimamente por lo que he venido leyendo, una alternativa mejor a mod_python es mod_wsgi, pues aparentemente funciona bastante mejor, más rápido y es la opción recomendada para usar con Apache y Django.

Por lo tanto, dejo esta guía muy sencilla de cómo instalar mod_wsgi con Python 2.6 en CentOS.

Descargar mod_wsgi, descomprimir y configurar

# cd /usr/src
# wget http://modwsgi.googlecode.com/files/mod_wsgi-3.1.tar.gz
# tar zxvf mod_wsgi-3.1.tar.gz
# cd mod_wsgi-3.1
# ./configure --with-python=/usr/bin/python2.6

Esa última línea es la clave para que utilice la instalación correcta de Python (ver el artículo anterior para saber cómo instalar Python 2.6 sin pisar la versión actual).

Luego compilamos e instalamos

# make && make install

Agregamos la línea para cargar el módulo en el httpd.conf

LoadModule wsgi_module        lib/apache/mod_wsgi.so

Y reiniciamos el Apache

service httpd restart

Luego para configurar un virtual host para que utilice mod_wsgi no es tan sencillo, pero tampoco es demasiado complicado. Básicamente hay que generar un archivo .wsgi, que no es más que un archivo Python que va a ser el que se integre con mod_wsgi y luego configurarlo en el httpd.conf. Lo que hay que tener en cuenta es que mod_wsgi no sirve contenido estático, por lo cual uno debe configurar por un lado el handling del código python y por otro los archivos estáticos. Si bien es algo distinto a lo que solemos hacer con mod_php, es algo bastante lógico y es una buena práctica pensar en servir por separado el contenido dinámico y el estático.

Como es un poco complejo, lo mejor es leer la guía correspondiente. En el sitio de mod_wsgi van a ver que hay mucha documentación. Particularmente, la guía de integración con Django es muy útil.

Python-Directadmin: API para conectarse a Directadmin desde Python

Este post viene un poco postergado. Hace algún tiempo que empecé con un pequeño proyecto y tenía pensado escribir una entrada en el blog para presentarlo, pero por distintos compromisos no he podido hacerlo hasta ahora, así que aquí va.

Para los que no lo sepan, Directadmin tiene una API para realizar distintas operaciones en el panel de control desde otra aplicación. La API no es más que una serie de URLs que reciben información por HTTP POST, ejecutan una acción y devuelven un resultado. De esa forma se pude acceder a muchas de las operaciones que uno realiza manualmente a través del panel (salvo algunas que parecen no estar muy bien implementadas/probadas).

En el foro de Directadmin existe una clase hecha en PHP a la que se le da bastante crédito, que lo que hace es abrir un socket y enviar requests HTTP a un servidor Directadmin y devolver la respuesta. Personalmente me parece que la clase es bastante mala y pobre, por las siguientes razones:

  • Está pensada para PHP 4.
  • No utiliza cURL, con lo cual hay demasiado código para hacer tareas que ya están implementadas en otras librerías.
  • Tiene un manejo de errores muy pobre
  • No es una implementación de la API de Directadmin (no implementa comandos específicos), sino que, como su nombre lo indica, se limita a crear un socket a un puerto HTTP y enviar requests (nuevamente… cURL).
  • El código no sigue ningún estándar de formato y “mejores prácticas”.

A pesar de todos estos problemas, tampoco me parecía un aporte muy interesante reescribir esa clase utilizando cURL. Además no tenía ganas de programar en PHP. Por lo tanto, lo que hice fue crear una implementación de la API en Python. Es decir, una librería que se ocupe de conectarse a un servidor Directadmin, enviar comandos, procesar sus respuestas y ofrecer una interfaz de programación cómoda para el desarrollador. De paso, el proyecto me sirvió para aprender un poco más de Python que es un lenguaje que me gusta mucho.

El resultado fue este proyecto que alojé en Google Code: http://code.google.com/p/python-directadmin/

El código es bastante sencillo (e incluso un poco tosco). Si ven el código del módulo directadmin, van a ver que hay una serie de clases. La más importante es la clase Api, que implementa los distintos métodos de la API de Directadmin (salvo algunos que no implementé aún). Esa clase hace uso de ApiConnector que es una clase muy sencilla que resume en unas pocas líneas lo que hacía la clase de PHP, utilizando urllib2. Luego hay un par de clases más para representar los tipos de usuarios, que no revisten mayor interés.

Posibles implementaciones

Cuando publiqué mi contribución en el foro de Directadmin obtuve una respuesta bastante poco amistosa de un usuario que no le veía utilidad a mi aporte. Más allá de esa persona, que afirma no conocer a nadie que programe en Python (sin comentarios…), yo creo que hay al menos tres vías de implementación de esta librería:

  • La más básica: crear scripts de consola para automatizar tareas (ver ejemplos más adelante).
  • Desarrollo web: así como el principal objetivo de la clase en PHP era que las empresas de hosting pudieran integrar sus sitios institucionales con el panel de control, esta implementación en Python permite el mismo tipo de integración para sitios desarrollados en Python (por ejemplo usando frameworks como Django, web2py, TurboGears, Pylons, etc.).
  • Aplicaciones de escritorio: no hay ni punto de comparación entre el soporte que ofrece Python para aplicaciones de escritorio con el que ofrece PHP. Hoy por hoy, un porcentaje muy alto de las aplicaciones de escritorio para Linux se escriben en Python y librerías como PyQt permiten hacer software desktop para Linux, Windows y Mac. Una aplicación de escritorio para monitorear y administrar múltiples servidores Directadmin se podría hacer sencillamente utilizando esta librería.

Ejemplos

Utilizar la API es bastante sencillo. En la página del proyecto podrán ver algunos ejemplos básicos como éste, para listar todos los usuarios del panel.

import directadmin

api = directadmin.Api("admin", "password", "hostname.com", 2222)
print api.list_all_users()

Además en el paquete incluí un archivo de ejemplo que se llama suspension.py. Este script utiliza la API para suspender/desuspender usuarios desde la consola. Se utiliza de la siguiente forma:

./suspension.py suspend

Tiene algunas otras opciones para especifiar host, puerto, usuario y password para conectarse Directadmin. Para ver las opciones disponibles pueden poner:

./suspension.py --help

Pendientes

Aún quedan varias cosas pendientes por hacer. Hay algunos métodos que no he implementado aún. Hay otros que los he probado y no funcionan, pero porque obtengo errores de parte de Directadmin y todavía nadie me ha sabido contestar por qué. También me gustaría crear un script de instalación con setuptools, pero todavía debo interiorizarme un poco más en el tema. Por último, me gustaría también hacer una implementación de más alto nivel, pues ahora la clase Api es una especie de bolsa de funciones que no me convence del todo.

Links

mod_python + Python 2.6 en CentOS

mod_python

mod_python

Hace algún tiempo escribí un pequeño artículo sobre cómo instalar mod_python en Apache 2.2. El tema es que, lógicamente, cada tanto uno quiere actualizar Python para tener las últimas correcciones de bugs y los últimos features. En mi caso quería instalar Python 2.6.1 en un CentOS. El tema es que con yum no veía ninguna actualización, pero tenía Python 2.4.x instalado y yo quería lo último. Me bajé el código, lo compilé, lo instalé y al rato me di cuenta que al hacer eso había roto el yum (que está escrito en Python). Así fue que llegué a darme cuenta de cómo instalar Python 2.6.1 por separado, y recompilar mod_python para que trabaje con esa versión, y esto es lo que quería compartir con ustedes.

Primero: Instalar Python 2.6 en una ubicación alternativa

Lo primero que vamos a hacer es descargar, compilar e instalar Python 2.6 en una ruta alternativa, es decir, sin pisar la instalación actual de Python 2.4 que viene con CentOS.

# cd /usr/src
# wget http://www.python.org/ftp/python/2.6.1/Python-2.6.1.tgz
# tar zxvf Python-2.6.1.tgz
# cd Python-2.6.1/
# ./configure --prefix=/usr
# make
# make altinstall

La clave está justamente en el último paso. En vez de hacer “make install”, hacemos “make altinstall” para que se instale sin sobreescribir la versión actual de Python. Básicamente lo que hace es instalar todas las libs en /usr/lib/python2.6 (esto lo hace de todas formas), y luego crear el binario /usr/bin/python2.6 pero sin sobreescribir /usr/bin/python.

Editado el 10/03/2010: En algunos casos puede ser necesario agregar al configure de Python la opción –enable-shared. Gracias Orcen!

Segundo: Recompilar mod_python

Ahora queda recompilar mod_python contra la nueva versión de python.

# cd /usr/src
# wget http://www.apache.org/dist/httpd/modpython/mod_python-3.3.1.tgz
# tar -zxvf mod_python-3.3.1.tgz
# cd mod_python-3.3.1
# ./configure --with-python=/usr/bin/python2.6
# make
# make install

La clave aquí está en el configure al que le pasamos el parámetro de qué binario de Python debe usar.

Tercero: Reiniciar Apache y probar

Por último queda reiniciar Apache y repetir la prueba explicada en el artículo anterior.

# service httpd restart

Script para contar requests por IP de un access_log de Apache

Python

Python

El otro día necesitaba saber si había alguna/s IP/s que estuvieran haciendo muchos requests a un dominio, así que escribí un muy sencillo script en Python para obtener la cantidad de peticiones por IP en un access_log de Apache. Se los dejo por si a alguien le sirve. Se me ocurre que con bash y las distintas herramientas de unix para manipular archivos y strings quizás habría podido hacer algo un poco más óptimo (aunque esto anda bastante rápido), pero me sentía más cómodo con Python.

Script

#!/usr/bin/python
import sys
from operator import itemgetter

file = open(sys.argv[1], "r")
ips = {}
line = None
while line != "":
    line = file.readline()
    ip = line.rsplit(" ")[0]
    if ip != "":
        if ips.has_key(ip):
            ips[ip] = ips[ip] + 1
        else:
            ips[ip] = 1

file.close()
list = sorted(ips.items(), key=itemgetter(1), reverse=True)
for item in list:
        print item[0].rjust(15, " "), ": ", item[1]

Cómo usarlo

Guardar el script en un archivo por ejemplo countip.py. Luego darle permisos de ejecución y correrlo.

# chmod +x countip.py
# ./countip.py /var/log/httpd/access_log

Según mis pruebas el script procesa un log de más de 14 mil líneas en aproximadamente 0,09 segundos.