DataTables JQuery, Bootstrap y Django

Muchas veces al querer mostrar un listado o un conjunto de objetos, necesitamos hacer uso de tablas, esto lo podemos trabajar de manera sencilla usando una simple tabla html, pero que pasa cuando queremos tener mayores prestaciones, como búsquedas, ordenamiento paginación, etc. En este caso tenemos que recurrir a elementos mas avanzados, en internet podemos encontrar muchísimas aplicaciones con tablas que nos facilitan la vida, pero en esta oportunidad vamos a trabajar con una herramienta que nos ha parecido muy interesante y que nos ha resultado muy fácil de configurar y además trabaja con JQuery, la aplicación se llama DataTables y como su página dice es un plugin para JQuery, para empezar a trabajar debemos descargarla desde el siguiente enlace.

Para poder mostrar un sitio web mas o menos presentable vamos a echar mano de Bootstrap, como ya es bien conocido en el mundo del desarrollo web Bootstrap es un framework que nos facilita el diseño de nuestras aplicaciones, contiene plantillas de diseño con tipografía, formularios, botones, cuadros, menús de navegación y otros elementos de diseño basado en HTML y CSS, así como, extensiones de JavaScript, la última versión la podemos descargar de esta ubicación.

Ahora si, vamos a empezar creando nuestro proyecto en django, nosotros utilizamos como IDE Eclipse con pydev, si quieren una guía para configurarlo dense una vuelta por aquí. Nuestro proyecto se llamará tutorial, dentro del proyecto vamos a crear la aplicación personas, de tal manera que tengamos la siguiente estructura:

Ahora vamos a crear una carpeta llamada static en la raiz del proyecto y dentro de ella vamos a crear las carpetas css, js, fonts, images y localizacion.

Nos toca configurar el archivo settings para que nuestros archivos estáticos se muestren correctamente, agregamos la siguiente linea al final del archivo.

settings.py

STATICFILES_DIRS = (
        os.path.join(BASE_DIR, 'static'),
)

Y ahora como ya tenemos descargados tanto DataTables como Bootstrap los descomprimimos, en DataTables buscamos la carpeta media, aquí encontraremos las carpetas css, images y js, vamos a trabajar de la manera mas sencilla que podamos por lo que no vamos a necesitar todo el contenido de las carpetas antes mencionadas, así que de la carpeta css seleccionamos el archivo jquery.dataTables.min.css y lo copiamos a la carpeta css de nuestro proyecto, de la carpeta js seleccionamos los archivos jquery.js y jquery.dataTables.min.js y los copiamos a la carpeta js de nuestro proyecto,el contenido de la carpeta images si lo copiamos integro dentro de nuestra carpeta images. Lo mismo hacemos con Bootstrap copiamos los archivos bootstrap.min.css y bootstrap.min.css.map a nuestra carpeta css, copiamos todo el contenido de la carpeta fonts a nuestra carpeta fonts y finalmente copiamos el archivo bootstrap.min.js a nuestra carpeta js. Adicionalmente a esto debemos copiar el contenido del siguiente enlace y crear un archivo en la carpeta localización que en este caso le hemos llamado es_ES.json, esto sirve para traducir DataTables al español.

Finalmente tendremos lo siguiente dentro de nuestra carpeta static:

Ahora vamos a crear una carpeta llamada templates que va a contener nuestras plantillas html dentro de la aplicación personas. Dentro de esta carpeta creamos un archivo llamado base.html que va a ser la plantilla madre de la que heredarán las demás, este archivo tendrá el siguiente contenido:

{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
Ejemplo Círculo de Programadores de Python Piura
<link rel="stylesheet" type="text/css" href="{% static "css/bootstrap.min.css" %}">
<link rel="stylesheet" type="text/css" href="{% static "css/jquery.dataTables.min.css" %}" />
<script src="{% static "js/jquery.js" %}"></script>
<script src="{% static "js/bootstrap.min.js" %}"></script>
<script src="{% static "js/jquery.dataTables.min.js" %}"></script>
</head>
<body>
<div id="page-wrapper">
<div class="container-fluid">
{% block cuerpo %}
{% endblock cuerpo %}
</div>
</div>
</body>
{% block js %}
{% endblock js %}
</html>

Vamos a modificar el archivo urls.py del proyecto de tal manera que al correrlo este apunte directamente a nuestra aplicación personas:

urls.py

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^', include('personas.urls',namespace='personas')),
]

Ahora crearemos nuestro modelo y unas vistas bastante simples, en el archivo models.py de la aplicación personas, creamos el modelo Persona:

models.py

from django.db import models

# Create your models here.
class Persona(models.Model):
dni= models.CharField(primary_key=True,max_length=8)
nombre = models.CharField(max_length=100)
apellido_paterno = models.CharField(max_length=100)
apellido_materno = models.CharField(max_length=100)

Creamos dos vistas con sus respectivas urls: views.py

from personas.models import Persona
from django.core.urlresolvers import reverse_lazy
from django.views.generic.edit import CreateView
from django.views.generic.list import ListView

# Create your views here.
class CrearPersona(CreateView):
model = Persona
fields =['dni','nombre','apellido_paterno','apellido_materno']
template_name = 'crear_persona.html'
success_url = reverse_lazy('personas:personas')

class Personas(ListView):
model = Persona
template_name = 'personas.html'
context_object_name = 'personas'

urls.py

from django.conf.urls import patterns, url
from personas.views import Personas, CrearPersona

urlpatterns = patterns(",
url(r'^crear_persona/$',CrearPersona.as_view(), name="crear_persona"),
url(r'^',Personas.as_view(), name="personas"),
)

Ahora debemos crear la plantilla:

personas.html

{% extends "base.html" %}
{% block cuerpo %}
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">Tablas</h1>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="panel panel-info">
<div class="panel-heading">
Personas
</div>
<div class="panel-body">
<div class='form-group'>
<div class="row">
<div class="col-lg-3">

</div>
<div class="col-lg-8">

</div>
<div class="col-lg-1">
<a id="crear_detalle" href="{% url 'tablas:crear_persona' %}"
class="btn btn-info btn-block">
<span class="glyphicon glyphicon-plus"></span>
</a>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<table id="tabla" class="table table-striped table-bordered"
cellspacing="0" width="100%">
<thead>
<tr>
<th class="text-center">DNI</th>
<th class="text-center">NOMBRE</th>
<th class="text-center">APELLIDO PATERNO</th>
<th class="text-center">APELLIDO MATERNO</th>
</tr>
</thead>
<tbody>
{% for persona in personas %}
<tr>
<td>{{ persona.dni }}</td>
<td>{{ persona.nombre }}</td>
<td>{{ persona.apellido_paterno }}</td>
<td>{{ persona.apellido_materno }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock cuerpo %}
{% block js %}
<script>
$(document).ready(function()
{
var table = $('#tabla').DataTable( {
"language": {
url: "/static/localizacion/es_ES.json"
}
} );

$('#tabla tbody').on( 'click', 'tr', function()
{
if ($(this).hasClass('selected') )
{
$(this).removeClass('selected');

}
else
{
table.$('tr.selected').removeClass('selected');
$(this).addClass('selected');
}
});

});
</script>
{% endblock js %}

Como hemos visto lineas arriba es en esta plantilla donde se hace uso de DataTables, primero se crea la tabla teniendo en cuenta que se la ha puesto el id “tabla" y además se hace la traducción al español invocando al archivo es_ES.json:

var table = $('#tabla').DataTable( {
"language": {
url: "/static/localizacion/es_ES.json"
}
} );

Lo siguiente es un efecto que se le da al seleccionar una de las filas de la tabla.

Y finalmente creamos el archivo:

crear_persona.html

{% extends "base.html" %}
{% block cuerpo %}

<div class="row">
<div class="col-lg-12">
<h1 class="page-header">Tablas</h1>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">
Crear Persona
</div>
<div class="panel-body">
<form role="form" action="#" method="post">
{% csrf_token %}
<div class="form-group">
{{ form.as_p }}
</div>
<div class='form-group'>
<input type="submit" class="btn btn-primary" name="submit"
value="Crear Persona">
<button type="reset" class="btn btn-primary"
onclick="location.href='{% url 'personas:personas' %}'">
Cancelar
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<div id="popup"></div>
{% endblock cuerpo %}

{% block js %}

{% endblock js %}

Hacemos las migraciones correspondientes de nuestros modelos y finalmente corremos el servidor de prueba, si todo ha salido bien tendremos una aplicación como la siguiente:

Deployando Proyectos Django en Heroku

Heroku es una plataforma que brinda servicios en la nube y soporta varios lenguajes de programación, funciona muy bien con Python y Django y en esta ocasión haremos un pequeño tutorial basado en el tutorial oficial, que se puede encontrar en la página del proyecto. Para empezar a trabajar debemos tener una cuenta en Heroku, hay planes de varios tipos, nosotros escogeremos el plan Free. Antes de empezar nos vamos a cerciorar de tener instaladas algunas cosas básicas, que ya hemos visto antes pero que siempre es bueno recordar:

  • Pip.
  • Virtualenv
  • Git.
  • Y en nuestro caso la base de datos PostgreSQL.

El primer paso es instalar Heroku Toolbelt, esta aplicación provee acceso a la interfaz de linea de comandos(CLI) de Heroku, que es usada para administrar y escalar nuestras aplicaciones y sus añadidos, para tenerlo instalado debemos poner el siguiente comando en nuestra terminal:

wget -O- https://toolbelt.heroku.com/install-ubuntu.sh | sh

El script nos pedira permisos de superusuario para continuar, se los damos y esperamos que la instalación se efectue.

Una vez que hemos terminado de instalar debemos loguearnos utilizando el usuario y password que hemos registrado en la página de Heroku de la siguiente manera:

heroku login

Si es la primera vez que lanzamos la aplicación se demorará un poquito instalando y configurando todo lo necesario, despues nos pedirá usuario y password, si ingresamos las credenciales correctamente nos saldrá un mensaje como este:

Logged in as miguel.amaya99@gmail.com

Una vez que hemos hecho esto el manual oficial de Heroku nos indica que debemos clonar una aplicación de prueba para deployar, nosotros ya tenemos una aplicación desarrollada por lo que debemos hacer algunos cambios a esta para poder subirla sin ningún problema.

Primero debemos agregar dos archivos en la raiz del proyecto:

El archivo procfile que debe tener el siguiente contenido:

web: gunicorn volpox.wsgi -log-file -

En la parte donde dice “volpox.wsgi” se debe reemplazar por el nombre de su proyecto.

El archivo requirements.txt debe tener todos las aplicaciones que nuestro proyecto necesita para funcionar correctamente, esto se puede averiguar facilmente ejecutando el comando pip freeze y guardando su contenido en el archivo, en nuestro caso el contenido del archivo es el siguiente:

dj-database-url==0.4.0
Django==1.9.2
gunicorn==19.4.5
psycopg2==2.6.1
whitenoise==2.0.6

Debemos tener en cuenta que este es el contenido básico para garantizar el correcto funcionamiento de nuestra aplicación en Heroku, hemos adicionado el paquete psycopg2 para poder trabajar con postgresql, si su proyecto usa algún paquete de software adicional, póngalo en este archivo.

Ahora debemos modificar el archivo settings.py agregando las siguientes lineas:

#Al inicio

import dj_database_url

PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))

En la parte donde está:

ALLOWED_HOSTS = []

Lo cambiamos por:

ALLOWED_HOSTS = ['*']

En la parte final agregamos esto:

db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)

# Honor the 'X-Forwarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/

STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles')

STATIC_URL = '/static/'

# Extra places for collectstatic to find static files.
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
STATICFILES_STORAGE =
'whitenoise.django.GzipManifestStaticFilesStorage'

Ahora debemos cambiar el contenido del archivo wsgi.py

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "volpox.settings")

from django.core.wsgi import get_wsgi_application
from whitenoise.django import DjangoWhiteNoise

application = get_wsgi_application()
application = DjangoWhiteNoise(application)

También debemos crear un archivo .gitignore, que es usado por git para no trabajar con las extensiones de archivos mencionados aquí en nuestro caso serán las siguientes:

venv
*.pyc
staticfiles
.env
db.sqlite3

Ahora debemos crear un repositorio git con el siguiente comando:

git init

Añadimos los archivos:

git add *

Y hacemos nuestro primer commit:

git commit -m "Deployando proyecto"

Creamos nuestro proyecto en Heroku:

heroku create volpox

Ahora si procedamos a subir nuestro proyecto a Heroku:

git push heroku master

Si tuviesemos algún error, revisar los archivos de la carpeta static, generalmente la mayoría de errores se presentan por rutas no encontradas o cosas así.

Si todo ha salido correctamente vamos a proceder a asegurarnos de que al menos una instancia de la aplicación se está ejecutando:

heroku ps:scale web=1

Ahora abrimos el proyecto con el navegador por defecto:

heroku open

Listo, ya tenemos nuestra aplicación funcionando correctamente, ahora falta configurar la base de datos, para ello vamos a utilizar el siguiente comando:

heroku addons

Con esto añadimos una base de datos PostgreSQL en el plan Free de nuestra cuenta. Los siguiente comandos:

heroku config
heroku pg

Nos permiten ver la configuración de nuestra base de datos.

Procedemos a crear nuestras tablas en la base de datos creada, usando el comando migrate de la siguiente manera:

heroku run python manage.py migrate

Si es necesario procedemos a crear nuestro superusuario:

heroku run python manage.py createsuperuser

Listo ya tenemos nuestra aplicación desplegada. Hasta la próxima.

Servir Aplicaciones Django con Apache y mod_wsgi en Centos 7

Para instalar un servidor de producción Django en Centos 7 usaremos Apache y mod_wsgi, mod_wsgi es un módulo de Apache, que permite servir aplicaciones hechas en Python, que tengan soporte para la interfaz WSGI. Los requisitos para esto son tener un servidor Centos 7 correctamente instalado y configurado y los permisos de root para poder hacer las instalaciones correspondientes. Para comenzar el proceso, vamos a descargar e instalar todos los elementos que necesitamos de los repositorios de la distribución. Esto incluirá el servidor web Apache, el módulo mod_wsgi utilizado para interactuar con nuestra aplicación Django, y pip. Para obtener pip, tendremos que habilitar el repositorio EPEL(paquetes para Linux Empresarial):

yum install epel-release

Con EPEL habilitado nosotros podemos instalar los componentes tipeando:

yum install python-pip httpd mod_wsgi

Ahora que ya tenemos instalados los paquetes necesarios, debemos crear un entorno virtual para ellos instalaremos virtualenv usando pip:

pip install virtualenv

Ahora procedemos a crear nuestro entorno virtual:

virtualenv vproduccion

Y lo activamos:

source vproduccion/bin/activate

Cuando activamos el entorno virtual nuestro prompt debe cambiar y aparecer entre paréntesis el nombre del entorno virtual activado. Una vez que esto ha sucedido debemos instalar Django:

pip install django

Cuando ya tengamos listo esto, subimos o creamos nuestro proyecto Django utilizando los comandos clásicos que ya hemos utilizado antes, ahora nos toca configurar Apache. Una vez que comprobamos que el proyecto Django está funcionando, podemos configurar Apache como un front-end. Las conexiones de cliente que recibe serán traducidos al formato WSGI que la aplicación Django espera utilizando el módulo mod_wsgi. Esto debería haber sido activado automáticamente después de la instalación anterior. Para configurar lo anterior, tendremos que crear un nuevo archivo de configuración en el directorio /etc/httpd/conf.d. Vamos a llamar a este archivo django.conf:

nano /etc/httpd/conf.d/django.conf

Y dentro de él escribiremos lo siguiente:

#En mi caso la ruta es /home/jamaya y mi proyecto se llama siad
#Configuración para mostrar correctamente losa archivos estáticos
Alias /static /home/jamaya/siad/static
<Directory /home/jamaya/siad/static>
        Require all granted
</Directory>
#Configuración para acceder correctamente al wsgi.py
<Directory /home/jamaya/siad/siad/>
        <Files wsgi.py>
                Require all granted
        </Files>
</Directory>

WSGIDaemonProcess siad python-path=/home/jamaya/siad:/home/jamaya/vproduccion/lib/python2.7/site-packages
WSGIProcessGroup siad
WSGIScriptAlias /siad /home/jamaya/siad/siad/wsgi.py

A continuación, tenemos que arreglar los permisos para que el servicio de Apache puede acceder a nuestros archivos. Por defecto CentOS bloquea el directorio personal de cada usuario de manera muy restrictiva. Para evitar esto, añadiremos el usuario apache al grupo de nuestro propio usuario. Esto nos permitirá abrir los permisos sólo lo suficiente para que pueda llegar a los archivos correspondientes. Añadimos el usuario apache a nuestro grupo, reemplazamos la palabra jamaya con nuestro usuario:

usermod -a -G jamaya apache

Damos permisos al grupo en la carpeta personal, esto permitirá al proceso apache acceder a los archivos.

chmod 710 /home/jamaya

Ya podemos iniciar el servicio de apache:

systemctl start httpd

Vamos a probar si la carga del proyecto funciona, vamos a otra computadora de la red y colocamos la direccion ip de nuestro servidor y la aplicación:

http://172.20.30.129/siad

Si hubiese algún problema lo mas rápido y sencillo es deshabilitar SELINUX, esto lo hacemos editando el archivo:

/etc/selinux/config

Y cambiando la siguiente linea:

SELINUX=disabled

Si todo funciona correctamente habilitamos el servicio apache para que se inicie automaticamente:

systemctl enable httpd

Recuerden tener siempre su archivo requerimientos.txt o requirements.txt para instalar todas las dependendencias que hacen que nuestro proyecto funcione con éxito. Este archivo se obtiene en nuestro entorno de desarrollo escribiendo el siguiente comando:

pip freeze > requirements.txt

Y para instalarlas en nuestro entorno de producción usamos el mismo comando con algunas variantes:

pip install -r requirements.txt

En el caso nuestro teniamos un par de dependencias un poco complicadas de instalar en Centos: Pillow y psycopg2, por lo que tuvimos algunos errores, para solucionarlos debemos instalar algunas librerias, en centos en el caso de psycopg2 tenemos:

yum install gcc
yum install postgresql-devel python-devel

Y en el caso de Pillow:

yum install libjpeg-devel zlib-devel

Y listo eso es todo, ya tenemos nuestro servidor de producción.

Saludos.

Romper Captchas con Pytesseract y Selenium

En muchas de las páginas que consultamos tenemos una imagen que contiene un pequeño texto que generalmente es de 4 o de 6 letras, esta imagen es conocida como captcha y sirve para evitar la consulta masiva de datos y el uso de boots para hacer consultas, el problema radica en que podemos convertir esta imagen en texto y buscar la forma de ingresar estos datos de manera automática sin intervención humana. Para hacer la conversión de la imagen en texto tenemos la librería pytesseract que hace uso del programa tesseract-ocr y para el ingreso automático de datos y el acceso a la página objetivo contamos con la ayuda de nuestro viejo conocido selenium, cabe destacar que este procedimiento funciona siempre y cuando la imagen del captcha no sea tan complejo y contenga solamente texto. Hemos creado un script de manera general sin tener una página objetivo en específico, pero para aplicarlo se debe conocer bien la página a testear tal como hemos explicado en posts anteriores, analizando sus elementos y la ubicación del captcha. Antes de empezar debemos tener instalado el programa tesseract-ocr ya que no podremos hacer nada sin este, lo podemos descargar de la siguiente ubicación.

Posteriormente procedemos a instalar las librerias pytesseract y pillow(para el manejo y tratamiento de imágenes)

pip install pillow
pip install pytesseract

Y finalmente hacemos nuestro script el cual está debidamente documentado para que lo puedan adaptar y modificar a su gusto.

# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

try:
    import Image
except ImportError:
    from PIL import Image
import pytesseract

def ir_pagina_web(cadena,direccion_web):
    driver = webdriver.Firefox()
    #Vamos a la dirección web de la página objetivo
    driver.get(direccion_web)
    try:
        #Esperamos que se cargue correctamente la caja de texto de búsqueda
        WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.ID, "txtBusqueda")))
    except:
        print "El elemento no está presente"
    #Obtenemos la caja de texto de búsqueda
    placa = driver.find_element_by_id("txtBusqueda")
    #Enviamos la cadena a buscar en la caja de texto
    placa.send_keys(cadena)
    #Hacemos una captura de pantalla de la página objetivo
    driver.save_screenshot("screenshot.jpg")
    #Abrimos la captura hecha
    img=Image.open('screenshot.jpg')
    #Recortamos la captura de acuerdo a la ubicación del captcha.
    #El primer argumento es la posición "x" inicial, el segundo la posición "y" inicial.
    #El tercer argumento es la posición "x" final y el cuarto la posición "y" final.
    img_recortada = img.crop((380,300,550,340))
    #Guardamos el área seleccionada con el nombre de "recorte.jpg"
    img_recortada.save("recorte.jpg")
    try:
        #Convertimos la imagen a cadena de texto usando la libreria pytesseract
        captcha = pytesseract.image_to_string(img_recortada)
        #Obtenemos la caja de texto donde se ingresa el contenido del captcha
        codigo = driver.find_element_by_id("txtCaptcha")
        #Enviamos el captcha obtenido
        codigo.send_keys(captcha)
    except:
        print "Error al convertir imagen en texto"
    #Obtenemos el botón buscar
    boton=driver.find_element_by_id("btn_buscar")
    #Hacemos click en el botón
    boton.click()
    driver.close()

def main():
    ir_pagina_web("cadena","direccion_web")

main()

Por cierto hemos realizado esta prueba en Windows, nos queda la tarea pendiente de hacerlo en GNU/Linux.

Web Scraping con Selenium

En entradas anteriores comentabamos sobre el uso de Selenium para hacer test, en esta oportunidad lo utilizaremos para extraer datos de una web en particular, ahora manos a la obra.
Para hacer la extracción de datos primero necesitamos conocer bien la página web objetivo, en este caso es una página de consulta de datos de teléfonos de personas y empresas llamada “Páginas Blancas” su URL es la siguiente:
http://www.paginasblancas.pe/

Y también debemos conocer el modo de funcionamiento de la página en cuestión, en este caso se debe ingresar la cadena a buscar en una caja de texto y presionar un botón que dice “Buscar” para enviar la consulta, si hay datos coincidentes con el texto ingresado, la página nos mostrará una lista de resultados que contienen la razón social o nombre, la dirección y el teléfono:

Búsqueda

busqueda

Resultados

resultados

Nos ayudaremos con las herramientas que tiene Firefox para poder identificar los elementos HTML de la página objetivo:
Herramientas

Empezamos identificando la caja de texto donde se envían los datos a consultar:

caja

Y el botón que ejecuta la consulta:

boton

Ahora que ya tenemos identificados estos elementos procedemos a escribir nuestro script en python:

[sourcecode language="python"]

# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import os

def ir_paginas_blancas_web(cadena):
    driver = webdriver.Firefox()
    #Página a la que queremos acceder
    driver.get("http://www.paginasblancas.pe")
    lista_datos = []
    try:
        #Verificamos si el elemento con ID="nName" ya está cargado, este elemento es la caja de texto donde se hacen las busquedas
        WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.ID, "nName")))
        #Obtenemos la caja de texto de busquedas
        input_nombre = driver.find_element_by_id("nName")
        #Enviamos la cadena que estamos buscando
        input_nombre.send_keys(cadena)
        #Obtenemos el botón que ejecuta la búsqueda
        boton = driver.find_element_by_id("btnSrchName")
        #Damos click al botón
        boton.click()
    except:
        #Mostramos este mensaje en caso de que se presente algún problema
        print "El elemento no está presente"
    try:
        #Si se encuentran resultados la página los muestra en elementos de nombre "m-results-business"
        #Para ello esperamos que estos elementos se carguen para proceder a consultarlos
        WebDriverWait(driver, 5).until(EC.presence_of_all_elements_located((By.CLASS_NAME, "m-results-business")))
    except:
        print ‘Elementos no encontrados’
    #Obtenemos en una lista los elementos encontrados
    resultados = driver.find_elements_by_class_name("m-results-business")
    for resultado in resultados:
        #En cada uno de los elementos encontrados buscamos un elemento interno que tiene por nombre info
        datos = resultado.find_element_by_class_name("info")
        #Dentro del elemento interno encontrado buscamos aquellos elementos que son enlaces(etiqueta <a>)
        nombre = datos.find_element_by_tag_name(‘a’)
        #Comprobamos si la cadena que buscamos coincide con la razón social o el nombre mostrado por la página
        if nombre.text.upper().find(cadena)<>-1 or cadena.find(nombre.text.upper())<>-1:
            #Obtenemos la parte de la dirección
            span = datos.find_elements_by_tag_name(‘span’)
            direccion = span[2].text
            partes_ubigeo = span[3].text.split(‘-’)
            distrito = partes_ubigeo[0].strip()
            try:
                departamento = partes_ubigeo[1].strip()
            except:
                departamento = ‘-’
        #Obtenemos los Datos telefonicos para ello debemos simular el click en el botón que dice "Ver Teléfono"
        boton_telefono = resultado.find_element_by_class_name("m-button–results-business–icon")
        boton_telefono.click()
        #Obtenemos los teléfonos que se muestran como enlaces
        enlaces = resultado.find_elements_by_tag_name(‘a’)
        telefono = enlaces[1].text.replace(‘ ‘, ”)
        #Finalmente metemos en una lista de listas los datos obtenidos
        lista_datos.append([direccion,distrito,departamento,telefono])

    driver.close()
    return lista_datos

def main():
    print ir_paginas_blancas_web(‘UNIVERSIDAD DE LIMA’)

main()

[/sourcecode]

 

Django y Microsoft SQL Server

Si por algún oscuro motivo necesitas conectar Django con Microsoft SQL Server, la solución la tiene el proyecto django-pyodbc-azure la información completa sobre el proyecto la encontrarán en su web oficial:
https://github.com/michiya/django-pyodbc-azure
La última versión del proyecto soporta Django 1.9.1 y Microsoft SQL Server 2005,2008/2008R2,2012,2014.
Para empezar a trabajar debemos instalar de la siguiente forma:
pip install django-pyodbc-azure

Y luego configurar el archivo settings de nuestro proyecto, en la parte relacionada a la conexión a las bases de datos:

[sourcecode language="python"]
DATABASES = {
‘default’: {
‘ENGINE’: ‘sql_server.pyodbc’,
‘NAME’: ‘NOMBRE_BD’,
‘USER’: ‘usuario’,
‘PASSWORD’: ‘password’,
‘HOST’: ‘IP_SERVIDOR_SQL_SERVER’,
‘PORT’: ”,
‘OPTIONS’: {
‘driver’: ‘SQL Server Native Client 10.0′,
}
},
}
[/sourcecode]

Y listo eso es todo, si desean conocer un poco mas este excelente proyecto remitanse a su página web.
Saludos.

Obtener Módulos de un Proyecto y Vistas de una Aplicación en Django

Debido a un requerimiento en un proyecto necesitabamos tener una página donde administrar todas las aplicaciones que hemos creado en nuestro proyecto Django y poder revisar que vistas(views) tiene cada uno de estas aplicaciones, para ello creamos una aplicación llamada permisos y una vista llamada AplicacionesProyecto de la siguiente manera:

[sourcecode language="python"]
class AplicacionesProyecto(View):

def get(self, request, *args, **kwargs):
aplicaciones = [ app for app in miproyecto.settings.INSTALLED_APPS if not "django" in app ]
context={‘aplicaciones’:aplicaciones}
return render(request, ‘reporte_aplicaciones.html’,context)
[/sourcecode]

Nuestro template se llama reporte_aplicaciones.html y tiene la siguiente estructura:

[sourcecode language="html"]
{% extends "base_permisos.html" %}
{% block titulo_opcion %}
Reporte de Aplicaciones
{% endblock titulo_opcion %}
{% block cuerpo_opcion %}
<table class="table table-striped">
<tbhead>
<tr>
<th>Nombre</th>
<th>Vistas</th>
</tr>
</tbhead>
<tbody>
{% for app in aplicaciones %}
<tr>
<td>{{ app }}</td>
<td>
<a class="btn btn-small" href="{% url ‘permisos:reporte_vistas’ app %}">
<span class="glyphicon glyphicon-folder-open"></span>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock cuerpo_opcion %}
[/sourcecode]

La idea es obtener un listado de tal manera que al dar click en el enlace de cada uno de los módulos podamos ver las vistas(Views) que tiene cada una de las aplicaciones:

[sourcecode language="python"]
class ReporteVistas(View):

def get(self, request, *args, **kwargs):
aplicacion = self.kwargs['aplicacion']
lista_clases = []
for nombre_modulo,instancia_modulo in inspect.getmembers(sys.modules[aplicacion]):
if nombre_modulo==’views’:
codigo_fuente = inspect.getsource(instancia_modulo)
codigo_fuente = codigo_fuente.replace(" ", "")
for miembro in dir(instancia_modulo):
obj = getattr(instancia_modulo, miembro)
if inspect.isclass(obj):
cadena_clase = ‘class’ + miembro
if codigo_fuente.find(cadena_clase)>=0:
lista_clases.append(miembro)
context={‘vistas’:lista_clases}
return render(request, ‘reporte_vistas_aplicacion.html’,context)
[/sourcecode]

Nuestro template es reporte_vistas_aplicacion.html y tiene el siguiente contenido:

[sourcecode language="html"]
{% extends "base_permisos.html" %}
{% block titulo_opcion %}
Reporte de Vistas
{% endblock titulo_opcion %}
{% block cuerpo_opcion %}
{% for vista in vistas %}
{{ vista }}
{% endfor %}
{% endblock cuerpo_opcion %}
[/sourcecode]

Los urls respectivos son de la siguiente manera, archivo urls.py:

[sourcecode language="python"]
url(r’^aplicaciones_proyecto’, login_required(AplicacionesProyecto.as_view()), name="aplicaciones_proyecto"),
url(r’^reporte_vistas/(?P<aplicacion>.+)/$’, login_required(ReporteVistas.as_view()), name="reporte_vistas"),
[/sourcecode]

Así de esta manera tenemos un procedimiento un tanto rudimentario pero útil con el que obtenemos, las aplicaciones de nuestro proyecto y las vistas de cada una de ellas.
Hasta la próxima.

Selenium con Python

Buenas noches estimados amigos en esta oportunidad vamos a trabajar con Selenium, esta excelente herramienta que nos permite testear nuestras aplicaciones web actuando como si lo hiciera un usuario final que interactúa con nuestra aplicación, la primera vez que la probé me sorprendí gratamente porque no sabía de la existencia de una herramienta tan interesante, bueno manos a la obra, para instalar selenium con Python debemos usar nuestra querida herramienta pip de la siguiente manera:

[sourcecode language="bash"]
sudo pip install selenium
[/sourcecode]
Si tuviésemos configurado un entorno virtual simplemente trabajaríamos así:

[sourcecode language="python"]
pip install selenium
[/sourcecode]

Con esto ya tendremos instalada esta excelente aplicación, si por algún motivo tuviesen algún error o ya tuviesen instalado selenium y quieren actualizarlo deben poner lo siguiente en su terminal:

[sourcecode language="python"]
pip install selenium –upgrade
[/sourcecode]
Para probar su funcionamiento debemos tipear este ejemplo bastante simple:

[sourcecode language="python"]
#Importamos el módulo webdriver que nos permite interactuar con nuestro navegador
from selenium import webdriver
#Importamos la clase Keys que provee las teclas RETURN, F1, ALT, etc de nuestro teclado
from selenium.webdriver.common.keys import Keys
#Creamos una instancia de Firefox webdriver para poder usar el navegador firefox en esta prueba
driver = webdriver.Firefox()
#El método get permite navegar hacia un enlace determinado en este caso la página de Python.org
#WebDriver esperará hasta que la página esté cargada
driver.get("http://www.python.org")
#En esta línea confirmaremos si el título tiene la palabra Python
assert "Python" in driver.title
#WebDriver ofrece varias maneras de encontrar los elementos de una página web
#En este ejemplo queremos encontrar el elemento que tenga como atributo name la letra "q"(es la barra de busqueda de la página)
elem = driver.find_element_by_name("q")
#Como ya localizamos el elemento y sabemos que es una caja de texto, vamos a escribir en ella la palabra "selenium"
elem.send_keys("selenium")
#Y finalmente enviaremos la busqueda pulsando la tecla RETURN
elem.send_keys(Keys.RETURN)
#Cerramos el navegador
driver.close()
[/sourcecode]

Verán que cuando ejecuten el script demorará un poquito pero nos mostrará una ventana de Firefox, posteriormente cargará la página de Python.org y en la caja de busqueda escribirá la palabra “selenium” para finalmente cerrar el navegador que había abierto culminando la ejecución del script.

Esperemos que este pequeño post sea de gran utilidad para ustedes queridos lectores y si tuviesen algún problema al ejecutar el script por favor nos avisan.

Saludos.