19 may. 2017

Obtener datos de eventos sismológicos de Funvisis con Python

Este artículo es gracias al código desarrollado por William Cabrera, donde en su blog menciona que creó un Canal en Telegram sobre los Sismos en Venezuela. El código fuente de sus scripts en php fueron la base para el código Python que se muestra en este artículo.

Gracias William por esta herramienta de información que es el Canal en Telegram.


Se usará mechanizeBeautifulSoup para obtener la información del sitio de funvisis por medio de WebScraping.  La información que se quiere obtener se muestra en un recuadro en la siguiente figura:





Para ver cual sección del código html se tiene que buscar, se le da boton derecho a inspeccionar elemento y la siguiente figura muestra el resultado:


Ahí se ve claramente  el tag html que es necesario buscar.

A continuación se muestra el código de la aplicación:



#!/usr/bin/env python





#Se importa mechanize y cookielib

import mechanize

import cookielib

#Se importa beautifulSoup

from BeautifulSoup import BeautifulSoup





def Sismo():

    br = mechanize.Browser()

    #Se crea una instancia para la Cookie

    cj = cookielib.LWPCookieJar()

    #Se asocia la instancia del cookie con el navegador.

    br.set_cookiejar(cj)

    #Se deshabilita el manejo de robots.txt

    br.set_handle_robots(False)

    #Se define el tiempo de refrescamiento

    br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1)

    #Se pasa el url del sitio timeanddate con la informacion

    url = "http://www.funvisis.gob.ve/"



    urlhome = url + "index.php"

    #de la salida y ocultamiento del sol en Venezuela.

    #Se define las cabeceras del navegador, en este caso se le esta diciendo

    # que el navegador es un firefox desde Linux Debian

    br.addheaders = [('SSL_VERIFYHOST', False),\

        ('FRESH_CONNECT',True),\

        ('RETURNTRANSFER',True),\

        ('SSL_VERIFYPEER', False),\

        ('Referer', 'http://www.cantv.com.ve'),\

        ('User-agent','Mozilla/5.0 (X11; U; Linux i686; es-VE; rv:1.9.0.1)Gecko/2008071615 Debian/6.0 Firefox/9')]

    #Se abre el url

    r = br.open(urlhome)

    #Se lee el htmml de la pagina

    html = br.response().read()

    #Se crea una instancia de BeautifulSoup pasando el html

    #a verificar

    soup = BeautifulSoup(html)

    sismo = {}



    #SE obtiene el primer  div que tengan class module

    for row in soup('div', {'class': 'module'})[0]:

        #Se obtiene el tag a para luego obtener el href y tener el url

        #del gif del sitio de funvisis que tiene la imagen del sitio donde

        #fue el sismo.

        trs = row.find('a')

        if trs == -1:

            continue

        sismo['urlref'] = url  + trs.get('href',None)



        trs = row.find('tr')

        if trs == -1:

            continue

        #Obtiene los datos del sismo del sitio de funvisis

        datos = trs.find('td').getText()

        sismo['fecha'] = datos.split(' ')[1][:-5]

        sismo['hora'] =  datos.split(' ')[2][-20:-14]

        sismo['magnitud'] = datos.split(' ')[3][-16:-12]

        sismo['profundidad'] = datos.split(' ')[4][-6:] + " " + datos.split(' ')[5][-11:-8]

        sismo['latitud'] = datos.split(' ')[6].split('º')[0][-9:] +datos.split(' ')[6][-10:-9]

        linea = datos.split(' ')[7].split('º')

        sismo['longitud'] = linea[0][-9:]+ linea[1][0]

        sismo['epicentro'] = datos.split(' ')[8]

        return sismo



def EventoSismoJSON():

    #Devuelve los datos del sismo en formato JSON

    import json

    return json.dumps(Sismo())



if __name__ == '__main__':

    print Sismo()

    print EventoSismoJSON()



A ejecutar el Script devuelve el diccionario con la información del evento sismológico.

python sismux_getdata.py 
{'hora': u'16:13 ', 'latitud': u'   11.73 N', 'epicentro': u'52 Km al sur de Curazao', 'profundidad': u'  40.6 km', 'fecha': u'19/05/2017', 'urlref': u'http://www.funvisis.gob.ve/images/reportes/2017/05/reporte_7415.gif', 'magnitud': u' 3.0', 'longitud': u'  -68.93 O'}
{"hora": "16:13 ", "latitud": "   11.73 N", "epicentro": "52 Km al sur de Curazao", "profundidad": "  40.6 km", "fecha": "19/05/2017", "urlref": "http://www.funvisis.gob.ve/images/reportes/2017/05/reporte_7415.gif", "magnitud": " 3.0", "longitud": "  -68.93 O"}


El código fuente del script lo pueden ver en el repositorio de gitlab.

El siguiente artículo será subir la información en una base de datos mongoDB en mongolab y consultar si el evento sismográfico ya no está registrado.


8 may. 2017

Cálculo de Pi por el método MonteCarlo usando Python.

El método MonteCarlo es un método estadístico numérico que se usa para aproximar expresiones matemáticas complejas y costosas de evaluar conexactitud. Para más información pueden revisar wikipedia.

La expresión matemática que se va a resolver es el cálculo de Pi.

En este artículo mostraré dos versiones del uso del Método MonteCarlo.

El primer ejemplo el algoritmo fue tomado de un código en Pascal y llevado a Python. A continuación el código:


#!/usr/bin/env python

#Se importa el modulo random

import random



#Se define la funcion

def Pi(limite=10000000):

    dentro = 0

    contador = 0

    #Se hace un ciclo hasta que contador sea igual al limite

    while contador < limite:

        #Se calcula  que los puntos esten dentro del radio del circulo

        #Si es asi se incrementa la variable dentro. y luego se incrementa

        #contador para pasar al siguiente ciclo.

        if ((random.random()**2 + random.random()**2) <= 1):

            dentro += 1

        contador += 1

    #Se retorna el resultado de la cantida de puntos dentro del circulo

    #entre el limite por 4.

    return 4.0*float(dentro)/limite



if __name__ == "__main__":

    n = (10000, 1000000,100000000)

    for i in n:

        print ("El valor de pi es: {0:2.8f} para n {1}".format(Pi(i),i))


Al ejecutar el código se tiene:

El valor de pi es: 3.14960000 para n 10000
El valor de pi es: 3.14308000 para n 1000000
El valor de pi es: 3.14141900 para n 100000000


Al aumentar el valor de n se logra tener un número más preciso del valor de PI, claro también se llevará más tiempo en calcular.

En el siguiente ejemplo se basa en un articulo en inglés publicado en Medium que se llama Day 9: Monte Carlo Pi y el código del mismo se encuentra en github.

El código se muestra a continuación:

#!/usr/bin/env python

#Se importa el modulo numpy

import numpy as np





def pi(n, batch=1000):

    t = 0

    for i in range(n // batch):

        p = np.random.rand(batch, 2)

        p = (p * p).sum(axis=1)

        t += (p <= 1).sum()

    return 4 * float(t) / n





if __name__ == "__main__":

    print ("El valor de pi es: {0:2.8f} para n {1}".format(pi(10**8),10**8))


Al ejecutarlo se obtiene:

El valor de pi es: 3.14146076 para n 100000000


Como ven la última versión es menos la cantidad de líneas de código y más rápida. 


7 may. 2017

Restructuración del blog.

Tengo varios días sin escribir algo en el blog, primero está la situación local, y lo otro es que ando pensando hacer una restructuración de los blogs que tengo.

Los blogs que tengo son:

  •  ernestocrespo.blogspot.com: Blog en inglés que lo tengo algo descuidado. Este blog lo pienso migrar de primero al url http://blog2.crespo.org.ve y usaré pelican para el contenido.
  • blog.crespo.org.ve: Versión en Español del blog, que tiene más de 300 posts. Como este blog es el que tiene más contenido, la migración será por etapas teniendo una versión beta con nombre blog3.crespo.org.ve, cuando esté lista la migración pasará a ser blog.crespo.org.ve
  • Medium: Este blog será para temas generales no técnicos o algunos técnicos (muy pocos). 
  • ernestocrespo13.wordpress.com: Este normalmente es un respaldo del blog en Español,  ahora manejará los posts de ambos blogs  en inglés y español como respaldo.


En un futuro dejaré de publicar en blogspot y wordpress dejando sólo los blogs  en  pelican.

Otro actividad que tengo es levantar www.crespo.org.ve, y que los dos blogs junto con el de Medium estén enlazaos allí.

El otro punto es que voy a empezar a utilizar acortadores de URL que permitan monetizar el blog, así como ya he colocado enlaces para recibir donaciones vía Billetera Bitcoin o paypal.

A continuación les dejo una imagen donde se encierra en un recuadro negro la billetera bitcoin y el formulario para donar por medio de paypal.




Billetera Bitcoin para donaciones:

197vyJ3KSCj287nLqhb7FSJpJUDayDoTMP

Donar vía Paypal:



10 abr. 2017

Entorno de Desarrollo en la nube Cloud9

Cloud9 es un Entorno Integrado de Desarrollo en línea, publicado como OpenSource desde la versión 3.0.

Acá les dejo otros enlaces de artículos sobre docker.

La aplicación la pueden acceder en  c9.io .

A continuación se muestra una imagen del sitio:


Es desarrollado enteramente en javascript, node.js como backend, los espacios de trabajo se contruyen por medio de Docker.

Soporta varios lenguajes de programación, entre los principales se tiene:

  • C/C++
  • PHP
  • Ruby
  • Perl
  • Python
  • Javascript
  • Go


Como cloud9 es OpenSource a parte de usarlo desde su sitio web, se puede montar un servidor, su código fuente se encuentra en github. El procedimiento de instalación lo encuentrán en el siguiente enlace.

En este caso se usará una imagen Docker para montarlo como servidor local. La imagen que se usará la pueden revisar en el siguiente enlace.

Para correr cloud9 como contenedor se ejecuta:

docker run -it -d -p 9080:80 -v /home/ernesto/worksplace/:/workspace/ kdelfour/cloud9-docker

En este caso se corre la aplicación desde el puerto 9080 y se usará como directorio de trabajo worksplace.

Al hacer un docker ps se tiene lo siguiente:

CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                            NAMES
f4d06af60205        kdelfour/cloud9-docker   "supervisord -c /etc/"   38 seconds ago      Up 33 seconds       3000/tcp, 0.0.0.0:9080->80/tcp   condescending_gates

Ahora se abre el navegador en el puerto 9080, a continuación se muestra la imagen:

Imagen mientras carga cloud9:




Entorno de trabajo y muestra de un Hola mundo!:

Como se puede ver, ya no es necesario usar la herramienta desde la web, ya puede usarse desde un servidor local usando una imagen Docker.

27 mar. 2017

Crear una imagen Docker a partir de debootstrap para Debian Jessie

Antes de empezar a tocar el tema sobre crear una imagen Docker a partir de debootstrap de Debian, les dejo el enlace de los artículos sobre docker del blog.

Lo primero que se tiene que hacer es instalar debootstrap:

#apt-get install debootstrap

A continuación se crea un directorio para construir la jaula debootstrap:

mkdir debian-jaula

Ahora se ejecuta debootstrap pasando la distribución a bajar, el directorio donde se crea la jaula y el repositorio a usar:

debootstrap jessie debian-jaula/ http://ftp.debian.org/debian
I: Retrieving Release 
I: Retrieving Release.gpg 
I: Checking Release signature
I: Valid Release signature (key id 75DDC3C4A499F1A18CB5F3C8CBF8D6FD518E17E1)
I: Validating Packages 
I: Resolving dependencies of required packages...
I: Resolving dependencies of base packages...
I: Found additional required dependencies: acl adduser dmsetup insserv libaudit-common libaudit1 libbz2-1.0 libcap2 libcap2-bin libcryptsetup4 libdb5.3 libdebconfclient0 libdevmapper1.02.1 libgcrypt20 libgpg-error0 libkmod2 libncursesw5 libprocps3 libsemanage-common libsemanage1 libslang2 libsystemd0 libudev1 libustr-1.0-1 procps systemd systemd-sysv udev 
I: Found additional base dependencies: libdns-export100 libffi6 libgmp10 libgnutls-deb0-28 libgnutls-openssl27 libhogweed2 libicu52 libidn11 libirs-export91 libisc-export95 libisccfg-export90 libmnl0 libnetfilter-acct1 libnettle4 libnfnetlink0 libp11-kit0 libpsl0 libtasn1-6 
I: Checking component main on http://ftp.debian.org/debian...
I: Validating acl 2.2.52-2
I: Retrieving libacl1 2.2.52-2
I: Validating libacl1 2.2.52-2
........................
..............
I: Configuring isc-dhcp-client...
I: Configuring tasksel...
I: Configuring tasksel-data...
I: Configuring libc-bin...
I: Configuring systemd...
I: Base system installed successfully.


Ahora se muestra el contenido del directorio:

ls debian-jaula/
bin/  boot/  dev/  etc/  home/  lib/  lib64/  media/  mnt/  opt/  proc/  root/  run/  sbin/  srv/  sys/  tmp/  usr/  var/

Ahora se crea la imagen por medio de tar y de docker import:

tar -C debian-jaula/ -c . | docker import - ecrespo/debian
sha256:49ad34e39c5f9ede2c1c57994895065236a5965496631e8fcab00b00778d85fa
Como se puede ver, se genera la imagen y el ID de la misma en sha256, se coloca en subrayado la parte que identifica la imagen al listas las imagenes.


Al hacer docker images se tiene lo siguiente:
REPOSITORY                                        TAG                 IMAGE ID            CREATED             SIZE
ecrespo/debian                                    latest              49ad34e39c5f        2 minutes ago       272.7 MB


Al tener la jaula lista se puede hacer personalizaciones y adaptaciones a fin de crear la imagen docker.

Este artículo se basa en a documentación del wiki de Debian sobre debootstrap y en un artículo sobre imagen base de docker

12 mar. 2017

Estructura de datos en python (Grafos)

Continuando con la serie de artículos sobre estructuras de datos en python. En este caso se tocará el tema de grafos con dos ejemplos, uno con listas y otro con matrices.

Los artículos anteriores son:

Este artículo se basa en los códigos en github Grafos con listas adyacentes y Grafos con matriz adyacente y del vídeo en youtube Grafos en Python.

De ejemplo de grafo se usará un modelo de procesos de colas, a continuación la imagen:


A continuación el código manejando el grafo como una lista:


#!/usr/bin/env python



class Vertice(object):

 def __init__(self, n):

  #Se define el nombre del vertice y la lista de vecinos

  self.nombre = n

  self.vecinos = list()

 

 def agregarVecino(self, v):

  if v not in self.vecinos:

   self.vecinos.append(v)

   self.vecinos.sort()







class Grafo(object):

 #Se crea un diccionario de vertices.

 vertices = {}

 

 def agregarVertice(self, vertice):

  #Se pregunta si vertice es una instancia de Vertice y si el nombre no esta en la lista de vertices.

  #Si se cumple se agrega el vertice al diccionario de vertices.

  if isinstance(vertice, Vertice) and vertice.nombre not in self.vertices:

   self.vertices[vertice.nombre] = vertice

   return True

  else:

   return False

 

 def agregarBorde(self, u, v):

  #Si u y v estan en vertices. se agregan como vecinos.

  if u in self.vertices and v in self.vertices:

   self.vertices[u].agregarVecino(v)

   self.vertices[v].agregarVecino(u)

   return True

  else:

   return False

   

 def printGrafo(self):

  #Se muestra el grafo.

  for key in sorted(list(self.vertices.keys())):

   print(key + str(self.vertices[key].vecinos))



if __name__ == '__main__':

 g = Grafo()

 cinco = Vertice('5')

 tres = Vertice('3')

 cuatro = Vertice('4')

 uno = Vertice('1')

 dos = Vertice('2')

 for i in range(ord('1'), ord('6')):

  g.agregarVertice(Vertice(chr(i)))



 bordes = ['53','54','31','35','41','42','45','12','13','14','21','24']

 for borde in bordes:

  g.agregarBorde(borde[:1],borde[1:])



 g.printGrafo()

Al ejecutar el script se tiene:
python grafo-listas.py
1['2', '3', '4']
2['1', '4']
3['1', '5']
4['1', '2', '5']
5['3', '4']


Como se ve, los vertices relacionados, el 1 se conecta con 2,3 y 4, el 2 con 1 y 4, el 3 con 1 y 5, el 4 con 1,2 y 5; y el 5 con 3 y 4.

El siguiente código muestra otra manera de crear el grafo, en este caso se puede manejar el peso de los bordes (aunque no se usa en el ejemplo).  A continuación el código:


#!/usr/bin/env python3



#Se importa nuevas caracteristicas de print

from __future__ import print_function





#Se crea la clace vertice que solo tiene como argumento su nombre.

class Vertice(object):

 def __init__(self, n):

  self.nombre = n





#Se crea la clase grafo con vertices e indices de bordes como diccionarios

#y bordes como una lista.

class Grafo(object):

 vertices = {}

 bordes = []

 indices_bordes = {}





 def agregarVertice(self,vertice):

  #Si vertice es una instancia de su clase y su nombre no esta en el 

  #diccionario de vertices se agrega.

  if isinstance(vertice, Vertice) and vertice.nombre not in self.vertices:

   self.vertices[vertice.nombre] = vertice

   #Se recorre los bordes y se agregan.

   for fila in self.bordes:

    fila.append(0)

   self.bordes.append([0] * (len(self.bordes)+1))

   self.indices_bordes[vertice.nombre] = len(self.indices_bordes)

   return True

  else:

   return False



 def agregarBorde(self,u,v, peso=1):

  #Se agrega el borde.

  if u in self.vertices and v in self.vertices:

   self.bordes[self.indices_bordes[u]][self.indices_bordes[v]] = peso

   self.bordes[self.indices_bordes[v]][self.indices_bordes[u]] = peso

   return True

  else:

   return False





 def printGrafo(self):

  #Se muestra el grafo

  for v, i in sorted(self.indices_bordes.items()):

   print(v + ' ', end='')

   for j in range(len(self.bordes)):

    print(self.bordes[i][j], end='')

   print(' ')    





if __name__ == '__main__':

 g = Grafo()

 cinco = Vertice('5')

 tres = Vertice('3')

 cuatro = Vertice('4')

 uno = Vertice('1')

 dos = Vertice('2')

 for i in range(ord('1'), ord('6')):

  g.agregarVertice(Vertice(chr(i)))



 bordes = ['53','54','31','35','41','42','45','12','13','14','21','24']

 for borde in bordes:

  g.agregarBorde(borde[:1],borde[1:])



 g.p

rintGrafo()





Al ejecutar el script se tiene lo siguiente:
python grafo-matrix-adyacente.py 
1 01110 
2 10010 
3 10001 
4 11001 
5 00110 

Como en el caso anterior, el vertice 1 se conecta con 2,3 y 4, el vertice 2 se conecta con 1 y 4, el vertice 3 conecta a 1 y 5, el vertice 4 conecta a 1,2 y 5; y el vertice 5 conecta con 3 y 4.



Se tienen dos formas de representar un grafo, puede usar el que prefiera, dependiendo de la complejida, si se necesita manejar pesos, la opción es el de la matriz.