sábado, 27 de agosto de 2016

Listas vs Tupas en Python

Listas vs Tuplas en Python
Listas vs Tuplas en Python
Una pregunta que nos surge cuando somos principiantes es: ¿Cual es la diferencia entre una lista y una tupla?
La respuesta es que hay 2 diferencias, existe la diferencia técnica y la diferencia cultural.

Este artículo no es de mi autoría, es una traducción al español, cito el enlace al final de la entrada.

En primer lugar, algo que es igual, tanto para las listas como para las tuplas, es que ambas son contenedoras de una secuencia de objetos:

>>> my_list = [1, 2, 3]
>>> type(my_list)
<class 'list'>
>>> my_tuple = (1, 2, 3)
>>> type(my_tuple)
<class 'tuple'>


Ambos pueden tener elementos de cualquier tipo, incluso dentro de una sola secuencia. Ambos mantienen el orden de los elementos.

Ahora pasemos a ver las diferencias. La diferencia técnica entre las listas y tuplas es que las listas son mutables (pueden ser cambiadas) y las tuplas son inmutables (no se pueden cambiar). Esta es la única distinción que hace el lenguaje Python sobre ellas:

>>> my_list[1] = "two"
>>> my_list
[1, 'two', 3]
>>> my_tuple[1] = "two"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment


Esa es la única diferencia técnica entre las listas y tuplas, aunque se manifiesta de varias maneras. Por ejemplo, las listas tienen un método .append() para añadir más elementos a la lista, mientras que las tuplas no lo hacen:

>>> my_list.append("four")
>>> my_list
[1, 'two', 3, 'four']
>>> my_tuple.append("four")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'append'


Las tuplas no tienen necesidad del método .append() porque no se pueden modificar.

La diferencia cultural trata de como se utilizan realmente las listas y las tuplas: las listas se utilizan cuando se tiene una secuencia homogénea de longitud desconocida, las tuplas se utilizan cuando se conoce el número de elementos de antemano debido a que la posición del elemento es semánticamente significativa.

Por ejemplo, supongamos tenemos una función que dentro de un directorio nos devuelve todos los archivos .py (*.py). Esto se debería devolver en una lista, porque no sabemos cuantos archivos podemos encontrar.

>>> find_files("*.py")
["control.py", "config.py", "cmdline.py", "backward.py"]


Por otra parte, supongamos que necesitamos almacenar 5 valores para representar la ubicación de las estaciones de observación meteorológicas: id, city, state, latitude y longitude. Una tupla es lo más adecuado para esto en lugar de una lista:

>>> denver = (44, "Denver", "CO", 40, 105)
>>> denver[1]
'Denver'


A continuación, el primer elemento es el id, el segundo es la ciudad y así sucesivamente.

Python tiene una facilidad llamada namedtuple que puede hacer el significado más explicito:

>>> from collections import namedtuple
>>> Station = namedtuple("Station", "id, city, state, lat, long")
>>> denver = Station(44, "Denver", "CO", 40, 105)
>>> denver
Station(id=44, city='Denver', state='CO', lat=40, long=105)
>>> denver.city
'Denver'
>>> denver[1]
'Denver'


La diferencia técnica y la diferencia cultural tienen una alianza incomoda, ya que están aveces en desacuerdo. ¿Porque deberían ser homogéneas las secuencias mutables, pero las secuencias heterogéneas no serlo? Por ejemplo, no puedo modificar mi estación meteorológica porque un namedtuple es una tupla, que es inmutable:

>>> denver.lat = 39.7392
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute


Y aveces las consideraciones técnicas tienen prioridad sobre las consideraciones culturales. No se puede utilizar una lista como clave de diccionario, porque solamente los valores inmutables pueden ser mezclados, osea, solo los valores inmutables pueden ser claves. Para utilizar una lista como clave, se puede convertir a tupla:

>>> d = {}
>>> nums = [1, 2, 3]
>>> d[nums] = "hello"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> d[tuple(nums)] = "hello"
>>> d
{(1, 2, 3): 'hello'}


Otro conflicto entre lo técnico y lo cultural: hay momentos en que el mismo Python utiliza una tupla cuando una lista tiene más sentido. Cuando se define una función con *args, nos lo pasa como una tupla, a pesar de que la posición de los valores no es significativa. Se puede decir que es una tupla porque no se puede cambiar lo que fue pasado, pero esto es solo una valoración de la diferencia técnica sobre la cultural.

Lo se, lo se, en *args, la posición podría ser significativa debido a que son parámetros posicionales. Sin embargo, en una función que ha de aceptar *args y pasarlos a otra función, que es solo una sentencia de argumentos, ninguno diferente de otro, el numero de ellos puede variar entre invocaciones.

Python utiliza tuplas aquí porque son un poco más espacio-eficientes que las listas. Esto muestra el lado pragmático de Python: en lugar de discutir por la semántica lista/tupla de *args, solo se tiene que utilizar la estructura de datos que funcione mejor para el caso.

En la mayoría de los casos, debemos elegir entre utilizar una lista o una tupla en base a la diferencia cultural. Debemos pensar en nuestros datos. Si podríamos llegar a tener diferentes longitudes, entonces es probable que utilicemos una lista. Si cuando escribimos el código sabemos de antemano la cantidad de elementos, entonces es probable que utilicemos una tupla.

Por otro lado, la programación funcional hace hincapié en las estructuras de datos inmutables como una manera de evitar los efectos secundarios que puedan hacer difícil interpretar el código. Si somos fans de la programación funcional, es probable que prefieramos tuplas por su inmutabilidad.

Entonces: ¿Tuplas o listas? No es siempre una respuesta sencilla.

Fuente: http://nedbatchelder.com/blog/201608/lists_vs_tuples.html

sábado, 20 de agosto de 2016

Completar formularios con mechanize y BeautifulSoup

Python, mechanize y BeautifulSoup
Python, mechanize y BeautifulSoup
Hace unos días que estoy jugando con las librerías mechanize y BeautifulSoup, y la verdad que me han dejado con muchas ganas de seguir aprendiendo. En la entrada anterior les mostré un ejemplo sencillo de como acceder a los datos de una pagina web con Python y BeautifulSoup, hoy veremos como llenar un sencillo formulario con la librería mechanize, capturar la respuesta con BeautifulSoup y extraer los datos de interés de dicha respuesta.

Les dejo la entrada anterior: Web Scraping con Python y BeautifulSoup

Les dejo el código en GitHub: https://github.com/DiegoCaraballo/SignificadoDeNombres.git

Mechanize
La librería mechanize se utiliza para navegar a travez de formularios web. Sin rodeos y para que nos entendamos, automatiza la tarea de entrar en un sitio web, llenar un formulario (de Contacto por ejemplo) y enviarlo (Ejemplo: presionar el botón "Guardar", "Enviar", "Buscar", etc)
Si quieren saber un poco más, les dejo el enlace: https://pypi.python.org/pypi/mechanize/

Su instalación: pip install mechanize

Luego de estar haciendo algunas pruebas, se me vino una imagen a la cabeza

¿Y si no es un humano?
¿Y si no es un humano?

Script SignificadosDeNombres.py
Luego de ver que podía compartirles, tratando de que el código no fuera muy invasivo, se me ocurrió hacer un script que entre en un sitio que contiene el significado de muchos nombres (hay nombres que no aparecen :(), pida por un nombre y luego nos retorne su significado. El script es muy básico, pero pretende ser de ayuda para futuros códigos.

Buscar Nombre
Buscar Nombre
El formulario a llenar con mechanize
El formulario a llenar con mechanize


Las pruebas las hice en un sistema linux (Ubuntu) y probé nombres como (Diego, Roberto, Mariela, Mirta, etc).

En los comentarios del código explico sus lineas
Código:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Diego Caraballo
# www.pythondiario.com

# Importamos librerias necesarias
from bs4 import BeautifulSoup
import mechanize
import os

# Instanciamos el objeto br
br = mechanize.Browser()

# Opciones para el navegador
# Ingnora robots.txt
br.set_handle_robots(False)
br.set_handle_equiv(False)
# Simula ser una persona
br.addheaders = [('User-agent', 'Mozilla/5.0')] 

# Opcion para terminar el bucle
opcion = "N"

# Bucle para seguir mostrando nombres
while (opcion != "S"):
 nombre = raw_input("Ingrese un nombre: ")
 
 # Pagina web
 url = 'http://www.misabueso.com/nombres/nombre.php'

 br.open(url)   

 br.select_form(nr= 0)

 br.form[ 'nombre' ] = nombre
 print ""

 # Guardo el contenido del resultado de apretar el boton buscar en formato (html)
 data = br.submit()
 
 # Instancio el objeto soup
 soup = BeautifulSoup(data, "html.parser")

 # Busco dentro del div, donde tengo el texto del nombre
 div = soup.find_all("div", {"class" : "in_a_box"})
 
 # Cantidad de lineas
 cant = len(div)
 
 # Recorro hasta la penultima linea del div y luego muestro
 for i in div[:(cant-1)]:
  print i.text + "\n"
  
 print ""
 
 opcion = raw_input("Presiones 'S' para Salir...")
 # Convierto la letra a Mayusculas
 opcion = opcion.upper()
 # Limpia pantalla, usar 'cls' para Windows
 os.system("clear")


Cualquier duda, comentario o sugerencia, siempre es bienvenida. Seguiré aprendiendo sobre el tema de la automatización y extracción de datos con Python y por lo tanto iré compartiendo lo aprendido. Saludos

sábado, 13 de agosto de 2016

Screenshot y envio de correo con Python

Screenshot y envio de correo con Python
Screenshot y envío de correo con Python
La idea de esta entrada es mostrarles como hacer capturas de pantalla (screenshot) y luego enviarlas adjuntas por correo

Ya hace un tiempo publique como enviar un correo electrónico con Python, si no sabes como, puedes visitar la entrada y familiarizarte con el tema. Hoy aparte, aprenderemos a enviar imágenes adjuntas.

También les dejo en enlace de GitHub por si quieren clonarlo y hacerle sus propias modificaciones: https://github.com/DiegoCaraballo/ScreenShot-y-Envio-de-Correo-con-Python.git

Librerías que deberías tener instaladas para que funciones el script:
  • Autopy
  • Las demás librerias (os, time, smtplib) ya vienen con python

Las pruebas las realice en un sistema Linux (Ubuntu) y el servidor de correo Gmail. Algo que me paso y es muy importante para que funcione el scritp, fue que al ejecutar el scritp por primera vez me llego un correo de un inicio de sesión sospechoso, le tuve que dar "permitir acceso", de lo contrario no llegaban los correos con las capturas de pantalla.

En los comentarios del código se explica cada paso:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Sitio: http://www.pythondiario.com
# Autor: Diego Caraballo

# Captura de pantalla y envio de correo

import smtplib 
# importamos librerias  para construir el mensaje
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText 
#importamos librerias para adjuntar
from email.MIMEBase import MIMEBase 
from email import encoders 
import os
import autopy
import time


def capture():
 # capturamos la pantalla
 screen = autopy.bitmap.capture_screen() 
 screen.save("/home/diego/captura.png")
 
 
def mail():

 # definimos los correo de remitente y receptor
 ##se envia un mail a
 addr_to   = 'pythondiario@gmail.com'
 ##el mail sale desde el correo
 addr_from = 'pythondiario@gmail.com'

 # Define SMTP email server details
 smtp_server = 'smtp.gmail.com:587'
 smtp_user   = 'pythondiario@gmail.com'
 smtp_pass   = '***********'
  
 # Construimos el mail
 msg = MIMEMultipart() 
 msg['To'] = addr_to
 msg['From'] = addr_from
 msg['Subject'] = 'Prueba'
 #cuerpo del mensaje en HTML y si fuera solo text puede colocar en el 2da parametro 'plain'
 msg.attach(MIMEText('Envio de captura de pantalla','html'))

 #adjuntamos la captura de pantalla
 ##cargamos el archivo a adjuntar
 fp = open('/home/diego/captura.png','rb')
 adjunto = MIMEBase('multipart', 'encrypted')
 #lo insertamos en una variable
 adjunto.set_payload(fp.read()) 
 fp.close()  
 #lo encriptamos en base64 para enviarlo
 encoders.encode_base64(adjunto) 
 #agregamos una cabecera y le damos un nombre al archivo que adjuntamos puede ser el mismo u otro
 adjunto.add_header('Content-Disposition', 'attachment', filename='pruta.png')
 #adjuntamos al mensaje
 msg.attach(adjunto) 

 # inicializamos el stmp para hacer el envio
 server = smtplib.SMTP(smtp_server)
 server.starttls()
 #logeamos con los datos ya seteados en la parte superior
 server.login(smtp_user,smtp_pass)
 #el envio
 server.sendmail(addr_from, addr_to, msg.as_string())
 #apagamos conexion stmp
 server.quit()
 
 #esto lo puse de prueba para saber que llegaba hasta aca y salia el correo
 print "Se envió el correo"


def main():
 
 while True:
  # hacemos la captura
  capture()
  # Enviamos el correo
  mail()
  # Tiempo en segundos entre re-envios
  time.sleep(60)

main()

Si todo salio bien, ya deberían estar recibiendo correos con las capturas de pantalla del equipo donde se ejecutó el scritp.

En la próxima entrega me gustaría poder subir un Keylogger hecho en python donde además de capturar las teclas ingresadas por el usuario, se envien capturas de pantalla.

Toda sugerencia o comentario siempre es bienvenido.

Saludos, Diego.

miércoles, 10 de agosto de 2016

Mini-Curso de wxPython 4. Agregando controles

En las entradas anteriores hemos visto algunos ejemplos de aplicaciones muy sencillas que contienen algunos controles, pero aún no hemos hecho hincapié en la forma de agregar los controles y todas las consideraciones que esto conlleva.

Antes de comenzar hay algunas cuestiones que debemos aclarar un poco. En toda librería gráfica existe el concepto de componente y contenedor, o de padre e hijo, el componente u objeto hijo será cualquier control gráfico contenido dentro de un contenedor (sí, suena raro, pero así es). Normalmente dentro del grupo de contenedores se incluyen todos aquellos elementos como los paneles y frames, que sirven para organizar el contenido de una interfaz gráfica.

En wxPython existen dos formas de agregar y distribuir los objetos gráficos dentro de nuestra interfaz, a saber:

  • Posicionamiento absoluto
  • Utilizando sizers

El posicionamiento absoluto implica colocar los controles gráficos de manera absoluta mediante el argumento pos, en el cual se indica mediante una tupla de dos elementos la posición en X e Y medida en pixeles. Esta es una forma un tanto sencilla de posicionar componentes, pero que en aplicaciones que van más allá de unos cuantos controles resulta difícil de implementar.

El uso de sizers es, digamos, la forma correcta de ir agregando controles a nuestra aplicación, quizá al principio pueda resultar un poco más complicada de entender, pero, las ventajas son muy notorias desde muy temprano. Sin entrar en muchos detalles técnicos, los sizers son mecanismos de diseño que sirven para posicionar y redimensionar los objetos dentro de una interfaz gráfica.

Bueno, una vez puestos en la mesa los puntos anteriores, vamos a ver cómo agregamos controles a una interfaz gráfica. Normalmente, para instanciar un control de wxPython, el primer argumento será siempre el objeto padre, por ejemplo, veamos que nos dice la ayuda de wxPython sobre la sintaxis para crear un Botón:

>>> help(wx.Button.__init__)
Help on method __init__ in module wx._controls:

__init__(self, *args, **kwargs) unbound wx._controls.Button method
    __init__(self, Window parent, int id=-1, String label=EmptyString, 
        Point pos=DefaultPosition, Size size=DefaultSize, 
        long style=0, Validator validator=DefaultValidator, 
        String name=ButtonNameStr) -> Button

Como se observa, el primer argumento indicado es el parámetro self, el cual no se pasa de manera explícita en los argumentos de entrada, seguido por un objeto padre, que es el primer argumento real que se pasa al momento de instanciar un objeto gráfico. Luego se debe colocar un identificador, que debe ser un entero cualesquiera, pero que normalmente se recomienda utilizar el -1 o la constante wx.ID_ANY para dejar que wxPython se encargue de asignar el número correspondiente. Luego, el resto de argumentos incluyen algunas cuestiones más propias de cada control. Note que también podemos pasar tanto la posición como el tamaño del objeto, mediante los argumentos pos y size, respectivamente. Una linea típica para el caso de un botón sería:

boton = wx.Button(panel, wx.ID_ANY, u"Botón 1", pos=(0,0), size=(80,20))

De hecho en la entrada anterior vimos un ejemplo con dos botones posicionados de manera manual:

import wx

class MiFrame(wx.Frame):
    def __init__(self,*args,**kwargs):
        wx.Frame.__init__(self,*args,**kwargs)

        # Agregando botones
        self.button1 = wx.Button(self, -1, u"Botón A", size=(100,20), pos=(10,10))
        self.button2 = wx.Button(self, -1, u"Botón B", size=(100,20), pos=(10,50))
        
        # Mostrando la interfaz
        self.Show()

            
if __name__=='__main__':
    app = wx.App() 
    fr = MiFrame(None, -1, "wxPython App", size=(300,200))
    app.MainLoop()

En este caso, el objeto padre es el Frame mismo, y por ello se pasa el parámetro self como primer argumento. El -1 refiere al argumento id, y el string pasado en cada caso corresponde al argumento label. Note que se agregan los argumentos size y pos en forma de una tupla, que especifican el tamaño y posición de los botones, respectivamente. La posición (o coordenadas de posición) en wxPython se determina a partir de la esquina superior izquierda como origen y medida en pixeles.

Veamos un ejemplo más, con algunos otros controles y posicionando de manera manual/absoluta:

import wx

class MiFrame(wx.Frame):
    def __init__(self,*args,**kwargs):
        wx.Frame.__init__(self,*args,**kwargs)

        # Etiquetas ...
        self.labelA = wx.StaticText(self, wx.ID_ANY, "A", pos=(10,10), size=(80,25))
        self.labelB = wx.StaticText(self, wx.ID_ANY, "B", pos=(10,40), size=(80,25))
        self.labelR = wx.StaticText(self, wx.ID_ANY, "Resultado", pos=(10,70), size=(80,25))
        
        # Inputs
        self.A = wx.TextCtrl(self, wx.ID_ANY, pos=(100,10), size=(180,25))
        self.B = wx.TextCtrl(self, wx.ID_ANY, pos=(100,40), size=(180,25))
        self.R = wx.TextCtrl(self, wx.ID_ANY, pos=(100,70), size=(180,25))

        # Botones
        self.suma = wx.Button(self, wx.ID_ANY, "+", pos=(55,120), size=(40,30))
        self.resta = wx.Button(self, wx.ID_ANY, "-", pos=(105,120), size=(40,30))
        self.multiplicacion = wx.Button(self, wx.ID_ANY, "*", pos=(155,120), size=(40,30))
        self.division = wx.Button(self, wx.ID_ANY, "/", pos=(205,120), size=(40,30))

        self.Centre(True)
        self.Show()
            
if __name__=='__main__':
    app = wx.App() 
    fr = MiFrame(None, -1, "wxPython App", size=(300,200))
    app.MainLoop()




Ahora, implementemos este mismo ejemplo utilizando sizers:

import wx

class MiFrame(wx.Frame):
    def __init__(self,*args,**kwargs):
        wx.Frame.__init__(self,*args,**kwargs)
        # Sizers
        self.mainsz = wx.BoxSizer(wx.VERTICAL)
        self.inputsz = wx.FlexGridSizer(rows=3, cols=2, hgap=5, vgap=5)
        self.buttonsz = wx.BoxSizer(wx.HORIZONTAL)

        # Etiquetas ...
        self.labelA = wx.StaticText(self, wx.ID_ANY, "A")
        self.labelB = wx.StaticText(self, wx.ID_ANY, "B")
        self.labelR = wx.StaticText(self, wx.ID_ANY, "Resultado")
        
        # Inputs
        self.A = wx.TextCtrl(self, wx.ID_ANY)
        self.B = wx.TextCtrl(self, wx.ID_ANY)
        self.R = wx.TextCtrl(self, wx.ID_ANY)

        # Botones
        self.suma = wx.Button(self, wx.ID_ANY, "+")
        self.resta = wx.Button(self, wx.ID_ANY, "-")
        self.multiplicacion = wx.Button(self, wx.ID_ANY, "*")
        self.division = wx.Button(self, wx.ID_ANY, "/")

        # Agregando a sizers
        for obj in [self.labelA, self.A, self.labelB, self.B, self.labelR, self.R]:
            self.inputsz.Add(obj, 1, wx.EXPAND|wx.ALL, 2)
        self.inputsz.AddGrowableCol(1)

        for obj in [self.suma, self.resta, self.multiplicacion, self.division]:
            self.buttonsz.Add(obj, 1, wx.EXPAND|wx.ALL, 2)
            obj.SetInitialSize((20,-1))

        # Configurando sizers
        self.mainsz.Add(self.inputsz, 2, wx.EXPAND|wx.ALL, 5)
        self.mainsz.Add(self.buttonsz, 1, wx.EXPAND|wx.ALL, 5)
        self.SetSizer(self.mainsz)

        self.Centre(True)
        self.Show()
            
if __name__=='__main__':
    app = wx.App() 
    fr = MiFrame(None, -1, "wxPython App", size=(300,200))
    app.MainLoop()



Vaya, que con sizers hay que escribir más código, ¿no?. Bueno, posiblemente sí, pero ahora, intenta redimensionar la ventana de cada aplicación. Como se dijo, utilizar sizers tiene la enorme ventaja de que puedes redimensionar el Frame y el tamaño y posición de los objetos se ajusta a lo requerido. Además, imagina que tienes unas decenas de controles, ¿crees que es sencillo calcular y programar cada una de las posiciones y tamaños?, complicado ciertamente.

En la siguiente entrada de este curso estaremos viendo un poco más sobre los sizers y cómo utilizarlos para organizar controles dentro de una interfaz gráfica wxPython.

Y bueno, recordarles que las preguntas, comentarios o cualquier otro, serán siempre bienvenidos.

Web Scraping con Python y BeautifulSoup

Web Scraping con Python y BeautifulSoup
Web Scraping con Python y BeautifulSoup
Hace tiempo tenía ganas de escribir sobre web scraping utilizando Python, para el que no conozca, sería lo mismo que decir "Extraer datos de paginas web utilizando Python".

Los motivos de escribir sobre el tema son muchos, pero enumero algunos:
1 - Hay muchos pedidos de trabajos en lo que respecta a la extracción de datos  web
2 - En el momento el tiempo que tengo para escribir en el blog no es mucho y me gustaría que este tema vaya quedando registrado en el "Diario".
3 - Luego de incursionar un poco en este mundo del Scraping se darán cuenta de lo mucho que se puede hacer con algunas lineas de código y un poco de imaginación.

Comparto el repositorio de GitHub: https://github.com/DiegoCaraballo/Web-Scraping-con-Python-y-BeautifulSoup.git

Un tema a tener en cuenta a la hora de meternos a extraer datos mediante scripts en una página web es leer los Términos y Condiciones de la página raspada, ya que hay muchas paginas que "no lo permiten".
También comentarles que sería apropiado tener algún conocimiento de HTML para que no resulte tedioso.

Demás esta decir que debemos tener instalado python. Las pruebas que comparto más abajo las hice en un sistema Linux, pero en otras oportunidades lo he hecho en Windows y funcionan correctamente.
1 - Como instalar Python en Linux
2 - Como instalar Python en Windows

Las herramientas
Las tareas básicas para extraer los datos de un sitio son dos:
  1. Cargar una página web
  2. Analizar el HTML de la página para localizar los datos que nos interesan
Python nos ofrece dos excelentes herramientas para las tareas antes mencionadas. Vamos a utilizar requests para cargar una pagina web y BeautifulSoup para hacer el análisis.

Para instalar estas librerías podemos utilizar pip:
  • $ pip install requests
  • $ pip install beautifulsoup4
BeautifulSoup nos proporciona algunos métodos simples y Pythonicos para navegar y buscar extraer lo que necesitamos.

Técnica de Scraping Básica
Lo primero que debemos hacer a la hora de querer extraer datos de una/s pagina web es inspeccionar manualmente la pagina para determinar como podemos localizar los datos.
Para comenzar, vamos a extraer algunos datos del blog, como por ejemplo su título y todas sus páginas internas. También puedes probar con la URL que quieras.

En los comentarios del código les explico cada línea:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Sitio: http://www.pythondiario.com
# Autor: Diego Caraballo

# Haciendo pruebas con BeautifulSoup y requests

# Importamos las librerias
from bs4 import BeautifulSoup
import requests

# Capturamos la url ingresada en la variable "url"
url = raw_input("Ingrese la URL: ")

# Capturamos el hml de la pagina web y creamos un objeto Response
r  = requests.get("http://" +url)
data = r.text
print ""

# Creamos el objeto soup y le pasamos lo capturado con request
soup = BeautifulSoup(data, 'lxml')

# Capturamos el titulo de la página y luego lo mostramos
# Lo que hace BeautifulSoup es capturar lo que esta dentro de la etiqueta title de la url
titulo = soup.title.text
print "El titulo de la pagina es: " + titulo
print ""

# Buscamos todas etiquetas HTML (a) y luego imprimirmos todo lo que viene despues de "href"
for link in soup.find_all('a'):
    print(link.get('href'))

Como dije anteriormente, esto nos devolverá los el título de la página y los enlaces de la misma.

Script que devuelve Titulo y enlaces de una pagina cualquiera
Script que devuelve Titulo y enlaces de una pagina cualquiera

Ahora veremos otro ejemplo de como utilizar BeautifulSoup.

Lo que haremos ahora será extraer la temperatura en Beijing (China), no me preguntes porque elegí china jeje, espero que los administradores de la página no se enojen ;)

Lo que hace el script es ingresar en la página, obtener los datos necesarios (temperatura y sensación térmica) y mostrarlos infinitamente cada X segundos (en mi caso puse 15seg para que se aprecie). Cada vez que la pagina actualice la temperatura, nuestro script también actualizara los datos sin tener que estar entrando en la pagina (lindo no?). ¿Se imaginan haciendo una página que se provea de información desde otros sitios haciendo scraping? Si, se puede!!!, de hecho, hay millones ;)

En los comentarios del código explico lo que hace. Para obtener los datos deseados debemos hacer lo siguiente:

Las pruebas las hice con el navegador Mozilla, pero también las he hecho en Chrome

  1. Ingresar por el navegador a la url deseada, en nuestro caso: http://www.timeanddate.com/weather/china/beijing
  2. Dentro de la página, buscamos el dato a extraer. Mostraré el ejemplo de la temperatura, pero para la sensación térmica es igual.
Temperatura en Beijing
Temperatura en Beijing
    3. Ahora hacemos clic con el botón secundario en el 27 y elegimos "Inspeccionar elemento", veremos algo como lo siguiente:

Etiquetas que contienen la temperatura
Etiquetas que contienen la temperatura

    4. Lo que necesitamos nosotros para obtener la temperatura, es sacar lo que está dentro de la etiqueta "div" (class - h2), la temperatura. Esto lo capturamos con BeautifulSoup y lo devolvemos como texto.

    5. En un principio quizá nos resulte complicado, pero la practica ayuda mucho. También comentarles que cada página es un mundo a parte, debemos inspeccionarla y buscarle la vuelta para extraer los datos.

Les dejo el código:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Sitio: http://www.pythondiario.com
# Autor: Diego Caraballo

# Haciendo pruebas con BeautifulSoup y requests

# Importamos las librerias
from bs4 import BeautifulSoup
import requests
import time
import os

# Creamos el Bucle infinito
while True:

 # Capturamos la url 
 url = "http://www.timeanddate.com/weather/china/beijing"

 # Capturamos el hml de la pagina web y creamos un objeto Response
 r  = requests.get(url)
 data = r.text

 # Creamos el objeto soup y le pasamos lo capturado con request
 soup = BeautifulSoup(data, 'lxml')

 # Buscamos el div para sacar los grados
 temp = soup.find_all('div', class_="h2")

 # Buscamos el div para sacar la sensacion termica
 sTerm = soup.find_all('div', class_="clear")
        
        # Con [0] saco el primer elemento y con [1] el segundo
 print "La temperatura en Beijing: " + temp[0].text
 print "La sesacion termica: " + sTerm[1].text
 
 # Tiempo en segundos para ejecutarse nuevamente
 time.sleep(15)
 
 # Boramos los datos viejos, para Windows es "cls"
 os.system("clear")

Script que devuelve temperatura
Script que devuelve temperatura

Solo resta decir que tengo más por compartirles, pero lo veremos en futuras entradas. Pueden seguir investigando por su cuenta y cualquier aporte o comentario siempre es bienvenido. Saludos, Diego.

martes, 19 de julio de 2016

Estructura de datos (Listas en Python)



Llegó el momento de usar estructura  de datos en Python. Comenzaremos con Listas.
Las listas pueden asemejarse a  gran casillero, donde dentro puede contener más casilleros, objetos sueltos, etc.
Las listas pueden ser numéricas, booleanas, de cadenas de caracteres
 Las listas son un almacenaje ordenado
Las listas se pueden indexar (acceder a los elementos).
l=[2,"PythonDiario",True,"musica"]
print(l[0])

Ese print nos dará 2, que es el contenido de la “caja 0”(posición cero) de la lista.
Elementos de una lista:
len(lista)
Índices para listas__________________________________
Los índices para listas pueden ser:
Negativos:
lista[-1]
Va de atrás para adelante es decir…
Una variable:
posicion=3
lista[posicion]
Crear una lista___________________________________________
Podemos crear una lista a partir de random, por datos ingresados, o secuencias,etc.  
lista=[randint(10,20) for i in range(15)]
Te acuerdas de random, pues para crear una lista de números aleatorios.  
lista=[i for i in range(6)]
Su resultado:
[0, 1, 2, 3, 4, 5]
Funciones en listas___________________________________ 
A continuación escribo algunas:
¿Cómo llamamos a los métodos?   nombredelalista.metodo()
Nombraremos a la la lista x





Index nos muestra la PRIMERA posición en la que aparece el elemento, si no lo encuentra devuelve -1.


Como te pudiste dar cuenta, algunos de estos métodos retornan valor, lo cual en ciertos problemas podremos jugar con esos valores
Otras funcionalidades: Suma, mínimo, máximo de los elementos de una lista
sum(lista)
min(lista)
max(lista)
 
AGREGAR UN ELEMENTO
Podemos agregar un elemento a una lista mediante: 
dato=int(input("Ingrese su número: "))
lista.append(dato)
lista=lista+[dato]

Como puedemos ver, tenemos las dos opciones para agregrar, mendiante el método o por concatenación.
#Aleatoriedad en listas
from random import*
Pizza=["Jalapeño","Jamón y Pizza","Mozarella"]
print(choice(Pizza))
Como consejo para manejar esta nueva estructura de datos, es que aprendas a dominar todas sus funciones, esto nos permitirá más adelante usarlas eficientemente para resoluciones de ejercicios más complejos.


Iterar sobre listas___________________________________
Podemos iterar a través de:
#ITERANDO POR ELEMENTO
lista=["Adameo","Mateo",14.56,False,0.789,34,"Melissa"]
for i in lista:
    print(i)
print("Lista: ",lista)
#ITERANDO POR ÍNDICE
for i in range(len(lista)):
    print("Posición",i,"contiene",lista[i])

1.-Dada una lista con contendido repetido, depurarla de tal manera que muestre por pantalla los elementos no repetidos.
Programando en Pycharm
 El resultado:

2.-Permitir al usuario crea una lista con contenido ingresado por pantalla
3.-Cree un programa que imprima posiciones impares del valor almacenado
4.-Defina una lista de 15 números. Llene la lista de valores aleatorios entre 10 y 20
·       - Muestre cuantos números pares hay en su lista
·        -Imprima los números impares de la lista
·        -Muestre los números primos que hay en la lista

from random import*
lista=[randint(10,20) for i in range(15)]
print(lista)
ci=0
for n in lista:
    if n%2==0:
        print("Numero par:",n)
    else:
        ci+=1
print("Numeros impares: ",ci)
for num in lista:
    cprimo=0
    for d in range(1,num+1):
        if num%d==0:
            cprimo+=1
    if cprimo==2:
        print("Numero Primo:",num)


¿Qué imprime este código?
Para adentrarse en la programación es necesario identificar errores, dominar ejercicios como este:
a=[5,4,3,2,1,0]
print(a[0],a[a[0]],a[a[-1]],a[a[a[a[2]+1]]])

La salida por pantalla del siguiente código:
a)5555 
b)5051
c)5411
d)Ninguna de las anteriores 



 
 

Entradas más recientes

E-mail Newsletter

Registra tu correo para recibir las noticias de ulima hora

Articulos Recientes

© 2014 Mi diario Python | Distributed By My Blogger Themes | Created By BloggerTheme9
TOP