Learning Python

Python: Cómo recolectar datos de webs de terceros, generar APIs, persistir datos, crear un bot y desplegarlo como servicios desde cero (PARTE I)

Iniciamos hoy una nueva serie compuesta por seis artículos en los que aprenderemos paso a paso a:

  1. Montar un entorno de desarrollo aislado para Python.
  2. Gestionar de manera correcta las constantes del proyecto mediante ficheros de configuración de la mano de dotenv.
  3. Obtener datos de webs de terceros mediante scraping.
  4. Incluir un sistema de logs.
  5. Persistir los datos recolectados en base de datos mediante dataset.
  6. Generar un API Rest a la cual poder atacar como servicio.
  7. Montar un bot de telegram el cual nos reporte de manera programada los nuevos artículos publicados en la web “scrapeada”.
  8. Ejecutar tanto el API como el bot mediante systemd como servicios independientes.
  9. Preparación de tests en previsión de futuros desarrollos y mantenimientos.

Puede que para algunos lectores el contenido presente un exceso de definiciones. Quisiera aclarar que el público objetivo de esta serie son todas aquellas personas que acaban de iniciarse en algún lenguaje de programación o tienen unas bases poco sólidas y tienen ganas de iniciarse en Python de una manera rápida y con buenas prácticas a la hora de componer código.

Si sabes lo que son los bucles for, los condicionales if..else y puedes abrir un terminal sin excesivo miedo a cagarla, te invito a que continues leyendo :)

Nota: Esta guía ha sido desarrollada sobre un GNU/Linux, por lo que las rutas a directorios podrían diferir si estás trabajando sobre un Windows, ten la precaución de cambiar las contrabarras ( ) por barras ( / ) si estas en un Windows y cambiar aquellas rutas que sean necesarias.

Preparación del entorno de desarrollo

Cuando comenzamos un nuevo proyecto en cualquier ámbito el primer paso consiste en preparar el puesto de trabajo y las herramientas; la programación no es una excepción.

Como herramientas tendrás un editor de código, llamado comúnmente IDE (Integrated Development Environment), un gestor de dependencias (pip), un gestor de entornos virtuales (pipenv) y finalmente el propio Python.

Python

Si estás usando un GNU/Linux o un Mac dispondrás por defecto de una versión de Python, por lo que no será necesario su instalación, en caso de que estés trabajando con Windows tendrás que pasarte por el siguiente artículo para realizar la instalación de Python (Solo será necesario realizar el apartado Install Python).

El IDE

Al igual que una persona que se dedica a realizar facturación debe saber utilizar las hojas de cálculo de excel, un programador debe de ser capaz de desenvolverse con un IDE.

En este momento, como programador, el IDE será la herramienta más importante de las que dispongas para trabajar. En el mercado dispondremos de muchas opciones viables, será la experiencia la que con el tiempo te lleve a tu editor preferido, de momento y bajo mi recomendación utilizaremos Visual Studio Code, un editor open source que resulta intuitivo, bonito y sencillo de primeras, con una buena gestión de plugins.

Podemos descargarlo desde su sitio web.

Conforme comiences a utilizar Visual Studio Code veras que te va recomendando la instalación de plugins. Dile que si a todos ya que te reportaran una experiencia de usuario mucho más agradable.

El gestor de dependencias

Para poder explicar que es un gestor de dependencias lo mejor es comenzar por buscar análogos. Has visto la tienda de aplicaciones de Google o de iOS? Tanto Google Play como Apple Store son aplicaciones que permiten realizar la instalación de otras aplicaciones; este tipo de aplicaciones son grosso modo gestores de dependencias.

Para nosotros nuestro “Google Play” se llamará pip, y será donde acudirás para descargar dependencias (siendo las aplicaciones de Google Play el análogo directo de dichas dependencias).

Si quieres saber donde consultar el contenido descargable que te proporciona pip, puedes dirigirte a pypi.

Pip es una herramienta de línea de comando. Una herramienta de línea de comando es aquella que se ejecuta escribiendo las acciones que deseas realizar. Para utilizarla será necesario abrir un terminal y que escribas algo parecido a pip --help por ejemplo.

Dependiendo del sistema operativo que estés utilizando, la instalación de pip podría diferir. Para evitar extender el artículo dejaré en tus manos acudir al sitio web de pip para seguir las instrucciones.

El siguiente paso tras la instalación de pip será actualizarlo, para ello ejecuta el siguiente comando en el terminal: python -m pip install --upgrade pip

El gestor de entornos virtuales

Una vez instalado pip, podrás instalar nuestro gestor de entornos virtuales.

Un gestor de entornos virtuales permite aislar todas las dependencias que requiera nuestra aplicación para que estas no interfieran con otros proyectos; expliquemos un poco en detalle esto.

Imagina que estás trabajando en un proyecto para el cual necesitas tener la dependencia python-telegram-bot en su última versión, la 12.7. Pasados cinco meses, un amigo, te pide que le ayudes en su proyecto y te proporciona su código fuente para que lo trabajes en tu casa, hasta aquí todo perfecto… perfecto hasta que ves que hace uso de la versión inestable de python-telegram-bot, la 13.0! Debido al salto de versión mayor (de la 12 a la 13 se considera un salto de versión mayor) no puedes ejecutar el proyecto porque te saltan errores ya que el código de tu amigo hace uso de cosas que en tu versión instalada (la 12.7) no existen… Tenemos un problemón montado del copón… La solución? Virtualizar entornos para aislar las dependencias instaladas, si tuvieras tu proyecto gestionado con pipenv podrías tener en el mismo pc los dos proyectos cada uno con una versión de python-telegram-bot diferente (dependencia). Por ese motivo nos interesa tener un gestor de entornos virtuales.

Muy bien! Expuesto el principal motivo por el cual nos interesa gestionar nuestros proyectos en entornos virtualizados, comenzamos con la instalación de pipenv. Recuerdas que ya tenemos instalado pip, nuestro bienamado gestor de dependencias? Pues vamos a usarlo! Abre el terminal y ejecuta: pip install pipenv.

Creando la estructura del proyecto

Llegado a este punto ya tienes todo lo que necesitas para comenzar a programar!

Abre un terminal, que vamos a crear un par de directorios y ficheros de nuestro proyecto por línea de comandos:

mkdir ~/project
cd ~/project
mkdir src
cd src
touch .env
touch settings.py

Nota: Mencionar que en programación es usual referirse a directorios cuando hablamos de carpetas y a ficheros cuando hablamos de archivos. De ahora en adelante ten presente esta nueva nomenclatura, pues lo normal será no ver referencias a las palabras “archivos” o “carpetas”

Nota: En GNU/Linux el signo ~ representa el directorio principal del usuario, en Windows llamado “Carpeta personal”.

Paso a explicar lo que hemos hecho:

  • mkdir, reconocido como make directory, crea el directorio recibido como parámetro. Es decir, mkdir ~/project creará el directorio “project” en nuestro directorio personal (~).
  • cd, reconocido como change directory, nos moverá al directorio recibido como parámetro. Es decir, cd ~/project entrará dentro del directorio project. Podrás observar que estás dentro de la carpeta porque la línea del terminal te marcará que has entrado.
  • touch .env crea un fichero llamado como el parámetro recibido (en este caso .env) en el directorio actual.

Resumidas cuentas, has creado el directorio project, el cual contiene el directorio src y finalmente dentro de este has creado dos ficheros llamados .env y settings.py

El directorio project será nuestro proyecto y como tendremos ciertos ficheros de configuración que te iré revelando progresivamente conforme avancemos en los artículos de esta serie, separamos el código del proyecto en el subdirectorio src (del inglés, source), en el cual alojaremos el código.

Nota: Si en algún momento te pierdes con algún comando te recomiendo que tengas a mano la web explainshell, donde podrás consultar gran cantidad de comandos y lo que hacen.

Mencionar que aquellos comandos instalados con pip no serán reconocidos (por ejemplo, pipenv).

explainshell

Teniendo creada la estructura básica del proyecto, el siguiente paso será crear el entorno virtual para nuestro proyecto. Para ello ejecuta estos comandos:

cd ~/project
pipenv --python 3.7
pipenv shell
pipenv install python-dotenv==0.13.0

Que qué has hecho? Sencillo, has inicializado un nuevo entorno virtual para la versión de Python 3.7 en el directorio ~/project, después has entrado en el entorno virtual gracias a pipenv shell y finalmente has instalado tu primera dependencia dentro del entorno virtual, ajena al resto de proyectos o futuros proyectos.

Por cierto, habrás observado que la línea de comandos ha cambiado, ahora será algo parecida a: (project) miusuario@mipc ~/project $. Esto permite detectar que estás dentro del entorno virtual de tu proyecto “project”.

Se me olvidó mencionarlo, pipenv es como el primo de zumosol de pip, una vez tengamos pipenv instalado no vamos a utilizar más a pip puesto que pipenv cubre las funcionalidades que da pip más la gestión de entornos virtuales.

Es hora de abrir el IDE instalado, Visual Studio Code. Puedes encontrarlo en el menú de aplicaciones. Cuando lo tengas abierto tienes que buscar en el menú Archivos (File) la opción de abrir carpeta (Open Folder) y selecciona el directorio “~/project”. Si lo prefieres, puedes hacerlo también desde el terminal entrando en el directorio ~/project con los comandos: cd ~/project y code .

Si has hecho todos los pasos correctamente, estarás delante de Visual Studio Code con el árbol de directorios de tu proyecto:

code_tree

Si observas, los ficheros Pipfile y Pipfile.lock no los has creado tú. Qué hacen ahí? Sencillo, fueron creados automáticamente tras preparar el entorno virtual con pipenv. Si abres el Pipfile te encontrarás el siguiente contenido:

code_Pipfile

Ey! Python 3.7 y python-dotenv, recuerdas? Eso sí que lo has instalado tú (con pipenv --python 3.7 y pipenv install python-dotenv==0.13.0)! Que no te preocupen estos ficheros, tanto Pipfile como Pipfile.lock ignoralos, ya que pipenv se encargará de actualizarlos y mantenerlos conforme vayas lanzando instalaciones de dependencias.

El proyecto debería quedar así.

Vamos a lo que nos interesa, a ver los ficheros .env y settings.py

Preparar la gestión de constantes del proyecto

Hablar de buenas, o malas, prácticas es difícil si no hay una base previa, digamos que cuando comenzamos a programar una de las normas más importantes es no escribir variables de configuración que deberían ser accesibles a pelo por el código. La manera correcta es tenerlas todas centralizadas en un único punto para que el usuario pueda cambiar los valores a placer sin perder la cabeza leyendo miles y miles de líneas de código en busca de un valor.

Entonces, tendremos un fichero llamado .env donde alojar las variables y otro fichero llamado settings.py que será el encargado de leer, convertir al tipo de dato necesario y almacenar los valores de .env para poder ser usadas desde cualquier parte del proyecto. De esta manera dotas al usuario de la capacidad para modificar las constantes declaradas en .env sin tener que ahondar en el código.

El contenido de ambos ficheros será el siguiente:

# .env
URL_FEED = https://www.apsl.net/blog/feed
# settings.py
import os

from dotenv import load_dotenv, find_dotenv


load_dotenv(find_dotenv())


def _env(key: str, default: str=None) -> str:
   """Wrapper for os.getenv. Force the raise Exception when key not exists."""
   value = os.getenv(key, default)

   if value is None and default is None:
       raise KeyError(f'Environment key "{key}" not exists.')

   return value


class Settings:
   URL_FEED = _env('URL_FEED')

El fichero settings.py contiene una función de utilería, la cual se encarga de buscar en el fichero .env la constante recibida como parámetro (key), en caso de no existir la constante lanzará un error; y será la clase Settings la encargada de manejar las constantes. De esta forma forzamos que toda variable de la clase Settings debe existir en el fichero .env

Puedes contrastar los cambios aplicados en el repositorio.

Prueba que funciona, abre un terminal y ejecuta Python.

Python se abre desde el terminal escribiendo “python”.

user@pc ~/project/src $ python
Python 3.7.3 (default, Dec 20 2019, 18:57:59)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

Tras hacerlo verás que la nueva línea de comandos donde puedes escribir ha cambiado de formato, tiene >>> en vez del nombre de tu máquina y la carpeta en la que te ubicas. Esto es python en el terminal. Ahora podrás escribir código de Python con naturalidad, importa el fichero settings y prueba que la variable URL_FEED contiene la información almacenada en el fichero .env:

>>> from settings import Settings
>>> Settings.URL_FEED
'https://www.apsl.net/blog/feed'
>>>

Si tras ejecutar Settings.URL_FEED te muestra nuestra dirección web, ENHORABUENA, FUNCIONA! Ya tenemos la primera parte de nuestro tutorial.

El proyecto debería quedar así.

Importante: Si la línea from settings import Settings lanza algún error, cerciórate que ejecutaste el comando python en el directorio donde tienes el fichero settings.py, es decir, en: ~/projects/src.


Y hasta aquí por hoy, en el próximo artículo hablaremos del scrapping (o como recopilar información de webs de terceros) y del log de la aplicación. Espero que te haya resultado cómoda la lectura, hasta lue!