Bienvenidos sean a este post, hoy veremos como crear una interfaz para hacer lo mismo que en el post anterior pero de forma visual.
Para crear una interfaz grafica para nuestros codigos se disponen varias, mencionemos algunas:
- TkInter
- wxPython
- PyGTK
- PyQT
Estas son distintas librerias que nos permiten crear ventanas para los distintos escritorios de cada S.O. pero para este ejemplo nos centraremos en el primero porque es el mas estandar y difundido por todos los sistemas operativos, pero primero veamos si esta instalado mediante el siguiente comando:
$ python3 -m tkinter
En el caso de funcionar debe abrir una pequeña ventanita que nos servira de notificacion pero en caso contrario para Debian deben usar el siguiente comando:
$ sudo apt-get install python3-tk
Este instalara el modulo necesario para la version 3 de python pero en caso de necesitarlo para la version 2 simplemente cambien el paquete a python-tk, con esto instalado podemos pasar a crear nuestra interfaz grafica y para ello crearemos un nuevo archivo llamado guiscrape.py al lado del archivo del post anterior, con nuestro archivo creado vamos a hablar un poco sobre la interfaz, veamos como quedara proximamente.

Esta es una imagen un poco burda pero es para que se hagan una idea de que va a corresponder cada parte de nuestra GUI, cuando hablemos de Raiz, sera la ventana que contendra a todo, el cuadro principal sera el que contendra los elementos, este contendra a los cuadros para la URL, para las imagenes, y por ultimo para el estado, cuando nos referimos a URL sera la pagina que investigaremos, la de imagenes nos dira las que podremos descargar y con que formato y por ultimo la de estado nos indicara los diferentes estados del programa, en el ejemplo vemos el inicial, esto es una idea simplemente ahora comenzaremos a agregar primero el codigo para importar los modulos necesarios, luego crearemos a los elementos que describimos y por ultimo la logica que le dara vida a todo, comencemos con el primer paso.
Creando la ventana
Tal como hicimos en el post anterior vamos a primero agregar los modulos que necesitaremos para nuestro codigo:
from tkinter import *
from tkinter import ttk, filedialog
import base64
import json
import os
from bs4 import BeautifulSoup
import requests
A diferencia del post anterior esta vez no importamos a argparse dado que no necesitamos mas de la linea de comandos por hacerlo a traves de una ventana pero lo reemplazaremos por las dos primeras lineas, la primer linea es muy habitual para tkinter pero esto no es una buena practica porque podemos tener colisiones con otros metodos o clases, o bien una sobrecarga de memoria porque el paquete es demasiado grande, la siguiente linea importa tres clases especificas para trabajar sobre nuestra ventana, ttk es una libreria para los nuevos widgets de estilos en las ventanas y el filedialog es para una ventana de seleccion de ubicacion de archivos para guardarlos, el resto de las importaciones trabajan de la misma forma que en el post anterior, lo bueno es que si hicieron el script anterior no necesitan instalar nada de lo contrario les recomiendo ver como instalar el modulo BeautifulSoup4 en el post anterior, como no tenemos necesidad de utilizar argumentos, a diferencia del script, el condicional que teniamos al final del archivo lo usaremos para generar la ventana, para ello agregaremos esta primera parte:
if __name__ == "__main__":
_raiz = Tk()
_raiz.title('Aplicacion de Scrape')
_cuadroPpal = ttk.Frame(_raiz, padding='5 5 5 5')
_cuadroPpal.grid(row=0, column=0, sticky=(E, W, N, S))
De vuelta chequeamos si estamos en la funcion principal, en caso de ser verdadero crearemos un objeto de tipo Tk que sera el encargado de almacenar todos los elementos que crearemos a continuacion, a este objeto le agregaremos un valor a la propiedad title que representara al titulo de la ventana principal, despues crearemos al elemento que sera el cuadro principal y que contendra realmente a todos los elementos, para ello usamos a la libreria ttk y la clase Frame, le pasaremos donde debe crearla y las separaciones dentro de este, despues usaremos a grid para ubicar a nuestro elemento en el objeto raiz, pasa la primera fila y columna para ubicarlo dentro de esto y usamos a sticky quien sera el encargado de estirarlo en base a las direcciones coordinales informadas:
- E, representa el ESTE
- W, representa el OESTE (WEST)
- N, representa el NORTE
- S, representa el SUR
Nota: Si se preguntan por sticky lo obtenemos cuando importamos a todos con el asterisco (*)
Con esto tenemos el cuadro principal, pasemos a crear el siguiente elemento:
_cuadro_url = ttk.LabelFrame(
_cuadroPpal, text='URL', padding='5 5 5 5')
_cuadro_url.grid(row=0, column=0, sticky=(E, W))
_cuadro_url.columnconfigure(0, weight=1)
_cuadro_url.rowconfigure(0, weight=1)
Aqui crearemos el cuadro que sera para los elementos para informar el URL, primero crearemos un elemento de ttk llamado LabelFrame, le pasamos la ubicacion que sera el objeto creado anteriormente, luego completamos la propiedad text y establecemos el padding o la separacion interna entre elementos, luego volvemos a usar el grid para ubicar a este elemento dentro del cuadro principal, observen que esta vez usamos el sticky pero para que se ajuste de izquierda a derecha, despues usaremos dos funciones para hacer que nuestros elementos se comporten correctamente al momento de establecer la fila y la columna, agreguemos el siguiente bloque:
_url = StringVar()
_url.set('http://localhost:8000')
_entrada_url = ttk.Entry(
_cuadro_url, width=40, textvariable=_url)
_entrada_url.grid(row=0,column=0,sticky=(E, W, S, N), padx=5)
_boton_busqueda = ttk.Button(
_cuadro_url,text='Busqueda de info',command=buscar_url)
_boton_busqueda.grid(row=0, column=1, sticky=W, padx=5)
La primera sera una variable que usaremos para almacenar la direccion web, luego por medio de set estableceremos un valor predeterminado pero que lo podamos modificar, luego crearemos un elemento para ingresar el valor llamado Entry, equivaldria a un inputbox, le pasamos donde lo guardaremos, establecemos el ancho del mismo y le pasamos la variable que creamos antes, por ultimo estableceremos por medio de grid al elemento, y pasaremos la separacion del eje X de los elementos, despues crearemos un nuevo elemento que sera el boton para buscar en la pagina informada, para ello usamos a Button, le pasamos el objeto donde sera creado, luego un titulo y por ultimo en command le decimos que funcion debe llamar, que aun no existe pero luego lo definiremos, por ultimo (como siempre) usaremos a grid para ubicarlo dentro del mismo,la diferencia va a estar en la columna en este caso y como sera la direccion para estirarlo, con esto comentado agreguemos el siguiente bloque:
_cuadro_img = ttk.LabelFrame(
_cuadroPpal, text='Contenido', padding='9 0 0 0')
_cuadro_img.grid(row=1, column=0, sticky=(N, S, E, W))
_imagenes = StringVar()
_listbox_img = Listbox(
_cuadro_img, listvariable=_imagenes,height=6,width=25)
_listbox_img.grid(row=0, column=0, sticky=(E,W), pady=5)
_barraScroll = ttk.Scrollbar(
_cuadro_img, orient=VERTICAL, command=_listbox_img.yview)
_barraScroll.grid(row=0,column=1,sticky=(S, N), pady=6)
_listbox_img.configure(yscrollcommand=_barraScroll.set)
_cuadro_radio = ttk.Frame(_cuadro_img)
_cuadro_radio.grid(row=0, column=2, sticky=(N, S, W, E))
Procedemos a crear el cuadro que usaremos para manipular las imagenes, el objeto sera de tipo LabelFrame donde le diremos el objeto que lo contendra, en Text el titulo del mismo y su separacion entre elementos, luego con grid lo ubicaremos fijense que ahora usamos a row con 1 para ubicarlo debajo del anterior y el sticky cambio parcialmente sus direcciones, luego crearemos una variable llamada _imagenes al igual que en el caso anterior por medio de StringVa, despues generamos un ListBox que lo ubicaremos en el objeto anterior, tendra una lista que usara a la variable antes creada y las dimensiones del mismo, por ultimo lo establecemos por medio de grid, en este caso establecemos que la direccion de acomplamiento lo haga de izquierda a derecha y establecemos la separacion de elementos en el eje Y, luego crearemos un Scrollbar para el ListBox anterior, para ello lo ubicaremos en el mismo objeto que en el anterior, le diremos que la orientacion sea vertical, y en command le diremos que nos muestre el eje Y del listbox anterior, luego lo ubicamos por medio de grid y observen que es la columna siguiente al elemento anterior, esta vez sticky sera de abajo hacia arriba y volvemos a usar el padding para el eje Y, por ultimo para este elemento por medio de la propiedad informada establecemos el comando que usara, por ultimo creamos un nuevo objeto de tipo Frame dentro del elemento que estuvimos usando y por medio de grid lo ubicamos al lado del anterior, gracias al column, con esto comentado pasemos a agregar el siguiente bloque:
_etq_eleccion = ttk.Label(
_cuadro_radio, text="Elige como guardar imagenes")
_etq_eleccion.grid(row=0, column=0, padx=5, pady=5)
_metodo_guardar = StringVar()
_metodo_guardar.set('img')
Lo siguiente sera un objeto de tipo Label que la ubicaremos dentro del ultimo objeto anterior, y le asignaremos un texto en su propiedad correspondiente, por ultimo como siempre con grid lo ubicaremos dentro del mismo, despues crearemos una variable llamada _metodo_guardar y le asignaremos el valor de img y ya veremos para que, agreguemos el siguiente bloque:
_img_radio = ttk.Radiobutton(
_cuadro_radio, text='Como imagenes',
variable=_metodo_guardar, value='img')
_img_radio.grid(
row=1, column=0, padx=5, pady=2, sticky=W)
_img_radio.configure(state='normal')
_json_radio = ttk.Radiobutton(
_cuadro_radio, text='Como JSON',
variable=_metodo_guardar, value='json')
_json_radio.grid(row=2, column=0, padx=5, pady=2, sticky=W)
En este caso crearemos dos objetos iguales de tipo RadioButton pero uno sera para guardar los archivos como imagenes y otro como JSON, por esta razon comentaremos uno solo, al momento de crearlo como siempre le indicaremos donde deber ser creado, el texto que mostrara la variable donde lo almacenara y por ultimo el valor, seguido de un grid para ubicarlo, por ultimo para el caso de las imagenes (_img_radio) usamos un configure para establecer a state como normal para que aparezca tildado en la ventana, para JSON es exactamente lo mismo pero varia unicamente el valor de row, no tiene el configure y pasamos otro valor para diferenciarlo, con esto creamos las dos opciones de tipo radio para seleccionar el formato de descarga, pasemos a agregar el siguiente bloque:
_btn_scrapear = ttk.Button(
_cuadroPpal, text='Scrapealo a todos!', command=guardar)
_btn_scrapear.grid(row=2, column=0, sticky=E, pady=5)
Este sera el objeto para el boton que hara la verdadera magia, lo ubicaremos en el cuadro principal, le establecemos un texto y la accion que estara relacioanda, por ultimo con grid establecemos su ubicacion y con sticky que se expandira desde la derecha hacia la izquierda, con una separacion de elementos (padding) del eje Y, agreguemos el ultimo bloque:
_cuadro_estado = ttk.Frame(
_raiz, relief='sunken', padding='2 2 2 2')
_cuadro_estado.grid(row=1, column=0, sticky=(E, W, S))
_msj_estado = StringVar()
_msj_estado.set('Tipea una URL para comenzar...')
_estado = ttk.Label(
_cuadro_estado, textvariable=_msj_estado, anchor=W)
_estado.grid(row=0, column=0, sticky=(E, W))
Por ultimo vamos a crear el cuadro para el estado, usamos un objeto de tipo Frame donde le pasaremos la ubicacion que no sera otro que _raiz, usamos a relief como ‘sunken’ que es una constante propia de esta propiedad, luego el padding, nuestro siguiente es ubicarlo por medio de grid tal como hasta ahora, luego crearemos una variable para los mensajes de este cuadro, en este caso guardaremos un valor predeterminado porque consideramos que todavia no hicimos nada, luego creamos otro objeto de tipo Label para los estados, esta vez lo ubicamos dentro del nuevo cuadro que almacenara la variable antes creada, por ultimo el grid para ubicarlo, pasemos a agregar la ultima linea:
_raiz.mainloop()
Esta sera la verdadera encargada de llamar a main para que podamos ver todo lo establecido anteriormente, si quisieran podrian probarlo pero les devolvera un error por las funciones que llama para los botones y estos no existen las cuales agregaremos en el proximo post, pero antes de terminar veamos como quedo nuestro codigo hasta ahora:
guiscrape.py
from tkinter import *
from tkinter import ttk, filedialog, messagebox
import base64
import json
import os
from bs4 import BeautifulSoup
import requests
if __name__ == "__main__":
_raiz = Tk()
_raiz.title('Aplicacion de Scrape')
_cuadroPpal = ttk.Frame(_raiz, padding='5 5 5 5')
_cuadroPpal.grid(row=0, column=0, sticky=(E, W, N, S))
_cuadro_url = ttk.LabelFrame(
_cuadroPpal, text='URL', padding='5 5 5 5')
_cuadro_url.grid(row=0, column=0, sticky=(E, W))
_cuadro_url.columnconfigure(0, weight=1)
_cuadro_url.rowconfigure(0, weight=1)
_url = StringVar()
_url.set('http://localhost:8000')
_entrada_url = ttk.Entry(
_cuadro_url, width=40, textvariable=_url)
_entrada_url.grid(row=0,column=0,sticky=(E, W, S, N), padx=5)
_boton_busqueda = ttk.Button(
_cuadro_url,text='Busqueda de info',command=buscar_url)
_boton_busqueda.grid(row=0, column=1, sticky=W, padx=5)
_cuadro_img = ttk.LabelFrame(
_cuadroPpal, text='Contenido', padding='9 0 0 0')
_cuadro_img.grid(row=1, column=0, sticky=(N, S, E, W))
_imagenes = StringVar()
_listbox_img = Listbox(
_cuadro_img, listvariable=_imagenes,height=6,width=25)
_listbox_img.grid(row=0, column=0, sticky=(E,W), pady=5)
_barraScroll = ttk.Scrollbar(
_cuadro_img, orient=VERTICAL, command=_listbox_img.yview)
_barraScroll.grid(row=0,column=1,sticky=(S, N), pady=6)
_listbox_img.configure(yscrollcommand=_barraScroll.set)
_cuadro_radio = ttk.Frame(_cuadro_img)
_cuadro_radio.grid(row=0, column=2, sticky=(N, S, W, E))
_etq_eleccion = ttk.Label(
_cuadro_radio, text="Elige como guardar imagenes")
_etq_eleccion.grid(row=0, column=0, padx=5, pady=5)
_metodo_guardar = StringVar()
_metodo_guardar.set('img')
_img_radio = ttk.Radiobutton(
_cuadro_radio, text='Como imagenes',
variable=_metodo_guardar, value='img')
_img_radio.grid(
row=1, column=0, padx=5, pady=2, sticky=W)
_img_radio.configure(state='normal')
_json_radio = ttk.Radiobutton(
_cuadro_radio, text='Como JSON',
variable=_metodo_guardar, value='json')
_json_radio.grid(row=2, column=0, padx=5, pady=2, sticky=W)
_btn_scrapear = ttk.Button(
_cuadroPpal, text='Scrapealo a todos!', command=guardar)
_btn_scrapear.grid(row=2, column=0, sticky=E, pady=5)
_cuadro_estado = ttk.Frame(
_raiz, relief='sunken', padding='2 2 2 2')
_cuadro_estado.grid(row=1, column=0, sticky=(E, W, S))
_msj_estado = StringVar()
_msj_estado.set('Tipea una URL para comenzar...')
_estado = ttk.Label(
_cuadro_estado, textvariable=_msj_estado, anchor=W)
_estado.grid(row=0, column=0, sticky=(E, W))
_raiz.mainloop()
En resumen, hoy hemos visto como generar la parte grafica de un script, hemos explicado brevemente como se compondra, hemos visto el nuevo modulo que usaremos para esto, hemos visto el paso de como se generan cada uno de los elementos que conforman nuestra ventana, espero les haya gustado sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.


Donación
Es para mantenimento del sitio, gracias!
$1.50
