Curso Python DGA 2011/acceso a datos/slides

= Acceso a datos =

y gestión de información
Luis Miguel Morillas &lt;lmorillas at xml3k.org&gt;

identi.ca: lmorillas

Introducción

 * Una de las tareas más frecuentes que tenemos es el tratamiento de información.
 * Muchas veces esa información está bien estructurada y almacenada en herramientas estándar (bases de datos relacionales),
 * pero otras veces los datos están en hojas de cálculo, páginas web y formatos menos estructurados.

Hojas de cálculo
Mucha información está almacenada en hojas de cálculo.

Ficheros CSV
La información de una hoja de cálculo se puede exportar/importar desde un fichero csv. Python tiene soporte para tratar ficheros csv. Un fichero csv es un fichero de texto.
 * http://docs.python.org/library/csv.html
 * http://blog.doughellmann.com/2007/08/pymotw-csv.html

Quoting
writer = csv.writer(f, quoting=csv.QUOTE_NONNUMERIC)

Dialectos
>>> csv.list_dialects ['excel-tab', 'excel']

Se pueden crear dialectos: csv.register_dialect(nombre, delimiter="|")

Hojas de cálculo Excel
Algunas librerías interesantes:
 * xlrd
 * http://pypi.python.org/pypi/xlrd
 * Lee datos y formato de ficheros .xls
 * Documentación de la API: https://secure.simplistix.co.uk/svn/xlrd/trunk/xlrd/doc/xlrd.html
 * xlwt
 * http://pypi.python.org/pypi/xlwt
 * Escribe datos y formatos a ficheros .xls
 * Doc: https://secure.simplistix.co.uk/svn/xlwt/trunk/xlwt/doc/xlwt.html
 * Ejemplos: https://secure.simplistix.co.uk/svn/xlwt/trunk/xlwt/examples/

Hojas de cálculo Excel (II)
Sin embargo es necesario usar COM para :
 * xlutils
 * http://pypi.python.org/pypi/xlutils
 * Colección de utilidades que usan xlrd y xlwt:
 * Doc y ejemplos: https://secure.simplistix.co.uk/svn/xlutils/trunk/xlutils/docs/
 * manipular gráficos
 * celdas con texto enriquecido
 * leer fórmulas
 * trabajar con macros y nombres

Bases de Datos Relacionales

 * Una base de datos relacional es una colección de tablas, cada una tien un número fijo de columnas y un número variable de filas. Las columnas tienen un nombre y contienen datos del mismo tipo.
 * Muchos sistemas de bases de datos: comerciales (Oracle, DB2, SQL Server, ...) y libres (MySQL, PostgreSQL, SQLite ...)
 * SQLite está incluida en Python

Bases de Datos Relacionales en Py
Usar bases de datos relacionales con Python es muy fácil. Python proporciona un estándar para acceder a bases de datos. La DB API 2.0 es la versión vigente (PEP 249) Módulos compatibles:
 * MySQLdb (MySQL)
 * psycopg2 (PostgreSQL)
 * cx_Oracle (Oracle)
 * mxODBC (SQL Server, DB2, Sybase, Oracle, etc.)

Estructura
La DB API usa dos conceptos para realizar los procesos:
 * Objeto Conexión
 * conexión con la base de datos
 * Transacciones
 * Objeto Cursor
 * Ejecuta las sentencias
 * Accede a los resultados

Conexión

 * El objeto conexión se encarga de conectar con la base de datos
 * Proporciona acceso (red/RPC) a la base de datos.
 * Este objeto no permite lanzar sentencias.
 * Gestiona las transacciones (grupos lógicos de sentencias)

Cursor

 * Creado a partir de una conexión
 * Sentencias de manipulación y de consulta en la bbdd.
 * Método execute, que acepta una secuencia de parámetros.
 * Almacena los datos del result set depués de lanzar la consulta.
 * Método fetch* que lee los datos del result set

Transacciones

 * DB API 2.0 soporta transacciones (si el motor las soporta) desde el objeto conexión.
 * conexión: commit / rollback

Introspección del esquema
 Método sencillo:  Método avanzado: 
 * Busca el tipo de las columnas de una tabla:

Muy importante: Paso de parámetros

 * No hay que hacer nunca sustitución de cadenas de caracteres para evitar inyección de código.

Paso de parámetros

 * paramstyle: define cómo se pasan los parámetros.
 * Todos los módulos admiten al menos uno de:
 * 'qmark': Signo de interrogación, ej. '...WHERE name=?'
 * 'numeric': Numerico, posicional, ej. '...WHERE name=:1'
 * 'named': por Nombre, ej. '...WHERE name=:name'
 * 'format': Formato ANSI C, ej. '...WHERE name=%s'
 * 'pyformat': Formato Python, ej. '...WHERE name=%(name)s'

Ampliación MySQL
Acceso a MySQL con Python

pickle
Pickle: convierte un objeto python en secuencia de bytes Funciones de pickle:
 * dumps(objeto, proto): serializa a una string
 * dump(objeto, archivo, proto): guarda en archivo
 * loads(cadena, proto): des-serializa una string
 * load(archivo, proto): carga desde archivo

Shelve
Shelve: objeto similar a un diccionario persistente
 * open(filename, flag='c', protocol=None, writeback=False) #crea un diccionario persistente
 * flag= 'r': solo lectura, 'w': lectura/escritura, 'c':creación y lectura/escritura, 'n': nuevo
 * shelve.sync: sincronizar (writeback=True)
 * shelve.close: grabar y cerrar diccionario

ORM
En un modelo tradicional de bases de datos (ver charla de pycamp.orm: MySQL <> dialecto_sql_1 <---> MySQLdb <> Python PostgreSQL <---> dialecto_sql_2 <---> psycopg2 <---> python Oracle <---> dialecto_sql_3 <---> cx_Oracle <--> Python

Esto dificulta las migraciones y la escalabilidad de las aplicaciones:
 * Cada base de datos usa un dialecto.
 * Al usar el driver de Python tenemos que usar ese dialecto. Una migración supone cambiar muchas sentencias al nuevo dialecto.

Cuando trabajamos con un ORM sólo usamos objetos Python. El ORM se encarga de traducir las sentencias al dialecto de la base de datos: BASE_DE_DATOS <-> ORM (SQLAlchemy, Elixir ...) <--> PYTHON El mismo código Python funcionará en PostgreSQL, Oracle o MySQL.

Un ejemplo
Incrementar la edad de las personas que tienen 20 años: Sin ORM

Con ORM 

ORMs en Python

 * http://wiki.python.org/moin/HigherLevelDatabaseProgramming
 * SQLAlchemy: http://www.sqlalchemy.org/
 * Elixir: http://elixir.ematia.de/
 * SQLObject: http://sqlobject.org
 * Storm: https://storm.canonical.com/
 * Autumn: http://autumn-orm.org/

Nosotros vamos a usar elixir.

Elixir
(Tutorial basado en http://elixir.ematia.de/trac/wiki/TutorialDivingIn)
 * Capa declarativa sobre SQLAlchemy
 * SQLAlchemy usa el patrón "Data Mapper" (no hay relación uno a uno de tablas y clases: las clases se pueden mapear a selects arbitrarias)
 * Elixir usa el patrón "Active Record": relación uno a uno de clases y tablas.
 * Soporta claves primarias compuestas.

Instalar
$ sudo easy_install elixir # pip install elixir

Podemos descargar el fuente de: http://elixir.ematia.de/trac/wiki/Download $ svn checkout http://elixir.ematia.de/svn/elixir/trunk/ elixir

Un modelo sencillo
La clase Entity define clases, tablas y mapper en un sólo paso.

modelo.py

Creación de la bases de datos II

 * Por defecto la tabla se llama _.
 * Si ningún campo tiene el parámetro primary_key=True, crea un atributo id.

Búsquedas generativas
(usando partes de otras búsquedas)

Herencia
Si pensamos en introducir actores y directores:

Profundización

 * Documentación de elixir: http://elixir.ematia.de/trac/wiki
 * Documentación de SQLAlchemy: http://www.sqlalchemy.org/

Web scraping: la web como fuente de información
La web se está transformando en una web de datos, pero muy poca información se sirve de forma estructurada y abierta:
 * http://www.zaragoza.es/ciudad/risp/
 * http://www.data.gov/
 * http://data.gov.uk/

Dificultades

 * Información poco o mal estructurada
 * Etiquetado no válido

Alternativas
Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two problems. – Jamie Zawinski
 * Leer la información de la web y parsearla con herramientas de análisis textual (expresiones regulares, etc.)

Alternativas (cont.)

 * Usar parsers de html/xml. Estos parsers tiene que poder leer tagsoup porque se encontrarán con código no válido:
 * BeautifulSoup, lxml, amara.

Nosotros usaremos Amara: http://wiki.xml3k.org/Amara (Tutorial)

Amara

 * Interfaz rápida con API más cercana al xml
 * API más pythonica:

Tagsoup

 * Para usar html no válido:

Instalar
Para instalar la última versión: $ sudo pip install http://files.akara.info/00-amara-latest.tar.bz2 También puedes descargar el código del repositorio: $ git clone https://github.com/zepheira/amara.git

Es necesario tener instalado un compilador de C y la cabeceras de python (en debian/ubuntu hay que instalar python-dev) Para windows hay versiones precompiladas.

Búsqueda de las entradas de una revista
Barrapunto publica sus entradas como

Búsqueda de las entradas de una revista (cont.)
Para extraer los nombres de los artículos de la primera página:

Búsqueda de las entradas de una revista (cont.)
Más ejemplos en http://wiki.xml3k.org/Amara/Recipes

Inyección de marcado
Se puede transformar un documento para añadirle o quitarle información. https://github.com/zepheira/amara/blob/master/demo/inject_markup.py
 * En este ejemplo añadimos unos links a los nombre de los autores, detectados por expresiones regulares:
 * En este proyecto hacemos un uso intensivo de inyección de marcado en páginas web: https://bitbucket.org/lmorillas/iaaa/

Inmersión en Python