Construir un acortador de URLs con Flask y MySQL

HTMLHTMLAdvanced
Practicar Ahora

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

Este proyecto te guía a través de la creación de un servicio simple de encurtido de URL utilizando Flask y MySQL. Aprenderás a configurar una base de datos, diseñar una interfaz web y implementar la funcionalidad para acortar URLs, buscar URLs por etiquetas y ver análisis. El proyecto es amigable para principiantes y ofrece una visión integral del desarrollo web con Python y la gestión de bases de datos.

El proyecto se basa en https://github.com/highoncarbs/shorty, que originalmente está licenciado bajo la licencia MIT.

👀 Vista previa

Convertir la URL con/sin sufijo personalizado, Buscar URLs por etiqueta, Acceder al enlace:

Ver información sobre el sistema operativo y la plataforma utilizada para acceder al enlace:

🎯 Tareas

En este proyecto, aprenderás:

  • Cómo conectar una aplicación Flask a una base de datos MySQL
  • Cómo crear y administrar un esquema de base de datos MySQL para almacenar información de URL
  • Cómo implementar páginas web front-end utilizando HTML y CSS para interactuar con el backend
  • Cómo manejar datos de formulario y solicitudes en Flask para crear URLs cortas
  • Cómo desarrollar la funcionalidad para redirigir a los usuarios de una URL corta a la URL original
  • Cómo crear una característica de análisis simple para rastrear el uso de URLs, incluyendo conteos de clics y información básica de navegador/plataforma
  • Cómo diseñar un manejo de errores amigable para el usuario y páginas 404 personalizadas para una mejor experiencia del usuario

🏆 Logros

Después de completar este proyecto, podrás:

  • Realizar operaciones básicas con MySQL, incluyendo la creación de bases de datos y tablas, inserción de datos y consultas
  • Comprender los fundamentos de Flask, incluyendo enrutamiento, manejo de solicitudes y renderizado de plantillas
  • Trabajar con formularios HTML y procesar datos en una aplicación Flask
  • Aplicar principios básicos de diseño front-end y utilizar CSS para crear una interfaz web visualmente atractiva
  • Implementar un análisis simple para recopilar y mostrar datos sobre el uso de URLs
  • Implementar las mejores prácticas para el manejo de errores en aplicaciones web para mejorar la confiabilidad y la experiencia del usuario

Configurar el entorno del proyecto

Primero, debemos configurar el entorno de nuestro proyecto en la terminal. Esto implica instalar el paquete de Python necesario para la conectividad con MySQL y iniciar el servicio MySQL. Una vez que el servicio está en ejecución, crearemos una base de datos y una tabla para almacenar nuestras URLs.

Instalar PyMySQL:

pip install PyMySQL==1.1.0

Iniciar el servicio MySQL e ingresar a la shell de MySQL:

sudo service mysql start
mysql -u root

Dentro de la shell de MySQL, ejecute los siguientes comandos para crear la base de datos y la tabla:

Crear base de datos:

CREATE DATABASE IF NOT EXISTS SHORTY;
USE SHORTY;

Crear tabla:

CREATE TABLE IF NOT EXISTS WEB_URL
(
    ID             INT AUTO_INCREMENT,
    URL            VARCHAR(512),
    S_URL          VARCHAR(80),
    TAG            VARCHAR(80),
    COUNTER        INT DEFAULT 0,
    CHROME         INT DEFAULT 0,
    FIREFOX        INT DEFAULT 0,
    SAFARI         INT DEFAULT 0,
    OTHER_BROWSER  INT DEFAULT 0,
    ANDROID        INT DEFAULT 0,
    IOS            INT DEFAULT 0,
    WINDOWS        INT DEFAULT 0,
    LINUX          INT DEFAULT 0,
    MAC            INT DEFAULT 0,
    OTHER_PLATFORM INT DEFAULT 0,
    PRIMARY KEY (ID)
);

Esta declaración SQL crea una tabla llamada WEB_URL en la base de datos SHORTY, diseñada para almacenar información relacionada con URLs acortadas y algunos análisis asociados.

  • CREATE TABLE IF NOT EXISTS WEB_URL: Este comando crea una nueva tabla llamada WEB_URL solo si no existe ya en la base de datos. Esto ayuda a evitar errores cuando el script se ejecuta varias veces.
  • ID INT AUTO_INCREMENT: Esta columna se designa como la clave primaria de la tabla y está configurada para incrementarse automáticamente con cada nueva entrada. Esto significa que cada vez que se agrega un nuevo registro, MySQL asignará automáticamente un ID único, incrementando en 1 a partir del último.
  • URL VARCHAR(512): Esta columna almacena las URLs originales que se están acortando. El tipo de datos VARCHAR(512) significa que puede almacenar cadenas de longitud variable, hasta 512 caracteres.
  • S_URL VARCHAR(80): Esta es la columna para la cadena de la URL acortada, con una longitud máxima de 80 caracteres.
  • TAG VARCHAR(80): Esta columna está destinada a almacenar etiquetas asociadas a las URLs para fines de categorización o búsqueda, con una longitud máxima de 80 caracteres.
  • COUNTER INT DEFAULT 0: Esta columna entera probablemente se utiliza para rastrear el número de veces que se ha accedido a una URL acortada. Por defecto, es 0 al crear un nuevo registro.
    Las siguientes columnas se diseñan para almacenar datos de análisis para las URLs acortadas:
  • CHROME, FIREFOX, SAFARI, OTHER_BROWSER: Estas columnas se utilizan para rastrear el número de visitas de diferentes navegadores web. Cada una es una columna entera que por defecto es 0.
  • ANDROID, IOS, WINDOWS, LINUX, MAC, OTHER_PLATFORM: Similar a las columnas de navegador, estas se destinan a rastrear visitas de diferentes sistemas operativos/plataformas, con cada columna por defecto siendo 0.
  • PRIMARY KEY (ID): Esta parte de la declaración especifica que la columna ID es la clave primaria de la tabla. Una clave primaria es un identificador único para cada registro de la tabla, lo que garantiza que no hay dos registros con el mismo ID.

Esta estructura de tabla permite almacenar, recuperar y analizar datos sobre URLs acortadas, incluyendo cuántas veces se acceden, desde qué navegadores y desde qué sistemas operativos.

Para salir de la shell de MySQL, puede ejecutar el siguiente comando:

EXIT;

Crear la plantilla de la página de índice

La página de índice es donde los usuarios interactuarán con el encurtidor de URL. Usaremos HTML y el lenguaje de plantillas de Flask para crear contenido dinámico.

En templates/index.html, agregue el siguiente código HTML:

<!doctype html>
<html>
  <head>
    <title>Shorty</title>
    <!-- Agregar imagen SVG local al hospedar. -->
    <link
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
      rel="stylesheet"
    />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.7.1/clipboard.min.js"></script>
    <link rel="stylesheet" type="text/css" href="../static/skeleton.css" />
    <link rel="stylesheet" type="text/css" href="../static/normalize.css" />
    <link rel="stylesheet" type="text/css" href="../static/main.css" />
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:300,400,700,900"
      rel="stylesheet"
    />
  </head>
  <body>
    <div class="container  main_header">
      <h3 align="left"><a href="{{url_for('index')}}">Shorty</a></h3>
      <p>Un servicio muy simple de encurtido de URL.</p>
    </div>

    <div class="u-full-width shorty">
      <div class="container"></div>
    </div>
  </body>
</html>

A continuación, una descripción general de sus componentes principales:

  • Íconos de Material de Google: La etiqueta <link> importa la biblioteca de iconos de Material de Google, lo que permite el uso de iconos predefinidos para una interfaz de usuario más atractiva.
  • Clipboard.js: La etiqueta <script> incluye la biblioteca Clipboard.js, una popular biblioteca de JavaScript para copiar contenido al portapapeles. Esto puede ser útil para un encurtidor de URL, ya que permite a los usuarios copiar fácilmente las URLs acortadas.
  • Hojas de estilo: La plantilla se vincula a varios archivos CSS para el estilo:
    • skeleton.css: Un marco de trabajo CSS ligero que proporciona un estilo básico y un sistema de cuadrícula responsiva.
    • normalize.css: Restablece los estilos predeterminados del navegador para mantener un estilo consistente en diferentes navegadores.
    • main.css: Contiene estilos personalizados específicos del servicio "Shorty".
  • Tipografías de Google: Otra etiqueta <link> importa la familia de fuentes "Roboto" de Google Fonts, proporcionando una variedad de pesos de fuente para el diseño tipográfico.
  • Dentro del <body>, un div con la clase container main_header se utiliza para crear una sección de encabezado, que incluye:
    • Un título (<h3>) que contiene un enlace (<a>) que redirige a la página de índice, facilitado por la función url_for de Flask, que genera dinámicamente la URL para la ruta 'index'.
    • Un párrafo (<p>) que describe el servicio como "Un servicio muy simple de encurtido de URL."
✨ Revisar Solución y Practicar

Implementar el encurtido de URL y la búsqueda basada en etiquetas

En este paso, mejoraremos la interfaz web integrando dos características clave: el encurtido de URL y la búsqueda de URL basada en etiquetas. Esto permitirá a los usuarios no solo acortar URLs, sino también organizarlas y recuperarlas de manera eficiente utilizando etiquetas.

Encurtido de URL

Primero, crearemos un formulario en la página de índice donde los usuarios pueden ingresar la URL que desean acortar. Los campos opcionales para sufijos personalizados y etiquetas permitirán URLs cortas personalizadas y categorización para un manejo más fácil.

Agregue el siguiente código a templates/index.html:

<!-- Search URL block -->
<div class="search_url_block">
  <form method="post" action="/search" name="search_tag_block">
    <input type="text" name="search_url" placeholder="Buscar etiquetas " />
    <button type="submit" class="button-primary search_url_btn" value="Buscar">
      Buscar
    </button>
  </form>
</div>
<!-- end block -->

El primer bloque de código agrega un formulario diseñado para buscar URLs por sus etiquetas asociadas:

  • search_url_block: Este contenedor contiene el formulario de búsqueda, convirtiéndolo en una sección distinta de la página para una mejor organización y estilo.
  • <form>: Define un formulario que envía una solicitud POST al punto final /search cuando se hace clic en el botón de búsqueda. Este formulario se denomina search_tag_block para su identificación.
  • <input>: Un campo de entrada de texto donde los usuarios pueden ingresar las etiquetas que desean buscar. El atributo placeholder proporciona una pista al usuario sobre el propósito del campo.
  • <button>: Un botón de envío que inicia la presentación del formulario. La clase button-primary probablemente agrega un estilo específico definido en el CSS.

Búsqueda basada en etiquetas

Para complementar la característica de encurtido de URL, también implementaremos una funcionalidad que permite a los usuarios buscar URLs por etiquetas. Esta característica se integrará en la plantilla de índice, proporcionando un formulario simple donde los usuarios pueden ingresar etiquetas para encontrar las URLs correspondientes.

Agregue el siguiente código a templates/index.html:

<!-- URL Input block -->
<form method="post" action="" name="generate_block">
  <div class="row">
    <input type="text" name="url_input" placeholder="Ingrese URL" />
    <input
      type="text"
      name="url_custom"
      placeholder="Ingrese Sufijo Personalizado"
    />
    <input type="text" name="url_tag" placeholder="Etiquetar URL" />
    <button class="button-primary generate">Generar</button>
  </div>
</form>
<!-- end block -->

El segundo bloque de código introduce un formulario para que los usuarios acorten URLs, con campos adicionales para la personalización:

  • Todo el formulario está envuelto en un elemento <form> con method="post" y un atributo action no especificado. Esto significa que los datos del formulario se enviarán a través de una solicitud POST a la URL actual cuando se hace clic en el botón de generación.
  • Dentro del formulario, un <div> con la clase row probablemente ayuda con el diseño y el alineamiento, asegurando que los campos de entrada y el botón estén adecuadamente organizados.
  • Se proporcionan tres elementos <input type="text"> con diferentes propósitos:
    • El primer campo de entrada es para que los usuarios ingresen la URL original que desean acortar.
    • El segundo permite un sufijo personalizado opcional para la URL acortada, lo que permite a los usuarios personalizar sus enlaces cortos.
    • El tercer campo está destinado a etiquetas, lo que permite a los usuarios categorizar o agregar etiquetas descriptivas a sus URLs acortadas para una recuperación y gestión más fáciles.
  • Un <button> con la clase button-primary y el texto "Generar" sirve como botón de envío del formulario. Hacer clic en este botón envía los datos al servidor para crear una URL acortada con la información proporcionada.

Estas mejoras mejoran significativamente la experiencia del usuario al ofrecer más funcionalidad más allá del encurtido básico de URL. La capacidad de buscar URLs por etiquetas permite un manejo y recuperación eficientes de enlaces acortados, mientras que la opción de agregar sufijos y etiquetas personalizados permite la personalización y categorización de URLs. Esta configuración aprovecha los formularios HTML para recopilar la entrada del usuario, que luego será procesada por la aplicación Flask del lado del servidor para realizar las acciones deseadas.

✨ Revisar Solución y Practicar

Manejar errores y mostrar URLs acortadas

En este paso, nos centramos en mejorar la experiencia del usuario al manejar los mensajes de error y mostrar las URLs acortadas.

Manejar errores

En primer lugar, agregamos funcionalidad para mostrar mensajes de error a los usuarios. Esto es crucial para proporcionar retroalimentación cuando algo sale mal, como cuando un usuario envía una URL no válida o una etiqueta que no existe. Un manejo adecuado de errores hace que la aplicación sea más robusta y amigable para el usuario.

Agregue el siguiente código a templates/index.html:

<!-- Error Display block -->
{% if error!= '' %}
<p class="error_disp">{{error}}</p>
{% endif %} {% if shorty_url %}
<!-- end block-->

Este bloque está diseñado para proporcionar retroalimentación al usuario si se produce un error durante el proceso de encurtido de URL:

  • {% if error!= '' %}: Esta es una declaración condicional que utiliza la sintaxis de plantillas de Flask, Jinja2. Verifica si la variable error no está vacía. Se espera que la variable error se pase desde el backend de Flask a la plantilla. Si hay un mensaje de error, la condición se evalúa como True.
  • <p class="error_disp">{{error}}</p>: Cuando la condición es True, se renderiza este elemento de párrafo, mostrando el mensaje de error contenido en la variable error. La clase error_disp probablemente se utiliza para dar estilo al mensaje de error, haciéndolo visualmente distinto para llamar la atención del usuario.
  • {% endif %}: Cierra el bloque condicional. Si la variable error está vacía, nada de este bloque se renderiza en la página.

Mostrar URLs acortadas

En segundo lugar, después de que una URL se ha acortado con éxito, mostramos la URL acortada al usuario. Esto implica crear una sección en la página de índice que muestre dinámicamente la URL acortada después de la presentación del formulario, junto con un botón para copiar al portapapeles para una fácil compartición.

Agregue el siguiente código a templates/index.html:

<!-- URL Generator Display block -->
<div class="gen_block">
  <p class="gen_url">
    La URL acortada de Shorty es
    <b><a id="short-url" href="{{shorty_url}}">{{shorty_url}}</a></b>
  </p>
  <button
    class="button-primary copy-btn"
    data-clipboard-action="copy"
    data-clipboard-target="#short-url"
  >
    Copiar
  </button>
</div>
{% endif %}
<!-- end block -->

Este bloque se muestra cuando una URL se ha acortado con éxito y proporciona una forma para que los usuarios copien fácilmente la URL acortada:

  • {% if shorty_url %}: Otra declaración condicional que verifica si la variable shorty_url existe y no está vacía. Esta variable debe contener la URL acortada generada por el servicio.
  • <p class="gen_url">: Este párrafo muestra un mensaje que indica la URL acortada. Dentro de él, <a id="short-url" href="{{shorty_url}}">{{shorty_url}}</a> crea un hipervínculo con la URL acortada como tanto el texto del enlace como el atributo href, lo que permite a los usuarios hacer clic en él directamente.
  • <button>: Este botón está diseñado para copiar la URL acortada al portapapeles para una fácil compartición. Utiliza clases para el estilo (button-primary) y la funcionalidad (copy-btn). El atributo data-clipboard-action especifica la acción a realizar (copiar), y data-clipboard-target indica el elemento objetivo a copiar (el enlace de la URL acortada). Esta configuración asume la integración de Clipboard.js (o una biblioteca similar) para manejar la funcionalidad de copia.
  • {% endif %}: Cierra el bloque condicional para mostrar la URL acortada y el botón de copia. Si shorty_url no está configurado o está vacío, esta sección no se renderizará.

Estas mejoras contribuyen significativamente a la usabilidad del servicio de encurtido de URL. El mensaje de error proporciona retroalimentación esencial, guiando a los usuarios a corregir errores o informándoles sobre problemas, mientras que la visualización de URLs acortadas con una función de copia fácil permite una experiencia sin problemas en la creación y compartición de enlaces acortados.

✨ Revisar Solución y Practicar

Listar y administrar URLs acortadas

El último paso es crear una sección que liste todas las URLs acortadas almacenadas en la base de datos, junto con sus URLs originales, el número de clics que han recibido y enlaces a análisis detallados. Esta característica permite a los usuarios ver y administrar sus URLs acortadas en un solo lugar, lo que hace que la aplicación sea más funcional y amigable para el usuario.

Agregue el siguiente código a templates/index.html:

        <!-- URL List Block -->
        {% if not error %}
        {% if not shorty_url %}
        <!-- Add Empty list case -> 'Wow. Such Empty!' -->
        <div style="overflow-x:auto;">
            <div class="table_list u-full-width">
                <table>
                    <thead>
                    <tr>
                        <th>URL original</th>
                        <th>URL corta</th>
                        <th>Clics</th>
                        <th>Info</th>
                    </tr>
                    </thead>

                    <tbody>
                    {% for url in table %}
                    <tr>
                        <td style="padding-left: 5px;">{{url[1]}}</td>
                        <td><a href="{{host+url[2]}}">{{ host+url[2]}}</a></td>
                        <td style="text-align: center;">{{url[4]}}</td>
                        <td id="info"><a href=" {{url_for('analytics',short_url=url[2])}} "><i class="material-icons">info_outline</i></a>
                        </td>
                    </tr>

                    {% endfor %}
                    </tbody>
                </table>
            </div>
        </div>
        {% endif %}
        {% endif %}
    </div>
</div>
<script type="text/javascript">
    var clipboard = new Clipboard('.copy-btn');
</script>
</html>

Este código está diseñado para listar todas las URLs acortadas almacenadas en la base de datos, proporcionando información como la URL original, la URL acortada, el número de clics y enlaces a análisis más detallados. A continuación, una descripción detallada de sus componentes:

  • El bloque comienza con una condición {% if not error %} para asegurarse de que la lista solo se muestre cuando no hay errores. Esto ayuda a mantener una interfaz de usuario limpia, especialmente cuando se necesitan mostrar mensajes de error.
  • Otra condición {% if not shorty_url %} verifica si una nueva URL acortada no se ha generado recientemente. Esta condición puede usarse para evitar que la lista se muestre inmediatamente después de que se acorta una nueva URL, centrando la atención del usuario en la URL acortada recién creada en lugar de eso.
  • Un estilo overflow-x:auto; se aplica a un div para asegurarse de que la tabla sea desplazable horizontalmente en pantallas más pequeñas, mejorando la respuesta y la usabilidad.
  • El elemento table está estructurado con una sección thead que define los encabezados de columna para "URL original", "URL corta", "Clics" e "Info". Este diseño ayuda a los usuarios a entender los datos presentados.
  • La sección tbody se llena dinámicamente con datos usando un bucle Flask/Jinja2: {% for url in table %}. Este bucle itera sobre una colección de URLs (table) pasada desde el backend de Flask, mostrando los datos de cada URL en una nueva fila de tabla (<tr>).
  • Dentro de cada fila, la URL original se muestra en una celda (<td>) con un poco de relleno para la estética. La URL acortada se presenta como un enlace clicable (<a>), construido agregando la ruta acortada (url[2]) al nombre del host (host), que también debe ser pasado desde el backend.
  • La columna "Clics" muestra el número de veces que se ha accedido a la URL acortada, centrada para una mejor legibilidad.
  • La columna "Info" contiene un enlace a la página de análisis para cada URL acortada. Este enlace se genera usando la función url_for de Flask, creando dinámicamente una URL a la ruta de análisis con la URL acortada como parámetro. Un icono (<i class="material-icons">info_outline</i>) del conjunto de iconos de Material de Google se utiliza para representar visualmente el enlace de análisis.
  • La etiqueta {% endfor %} cierra el bucle, asegurando de que se cree una fila para cada URL en la colección table.
  • Los bloques condicionales se cierran con las etiquetas {% endif %}.
  • Al final, una etiqueta <script> inicializa Clipboard.js para la clase .copy-btn, que podría haber sido usada en secciones anteriores (por ejemplo, para copiar la URL acortada). Este script asegura de que cualquier elemento con la clase copy-btn tendrá la funcionalidad de copiar al portapapeles habilitada, aprovechando la biblioteca Clipboard.js.

Este último paso completa la funcionalidad del servicio de encurtido de URL "Shorty" al proporcionar a los usuarios una visión general completa de sus URLs acortadas, lo que hace más fácil administrar y analizar sus enlaces. La integración de la representación dinámica de datos con Flask/Jinja2, combinada con un diseño de interfaz de usuario cuidadoso, garantiza una experiencia amigable para el usuario.

✨ Revisar Solución y Practicar

Crear la plantilla de la página de búsqueda

Para permitir a los usuarios buscar URLs por etiquetas, necesitaremos una página de búsqueda.

En templates/search.html, agregue el siguiente código HTML:

<!DOCTYPE html>
<html>
<head>
    <title>Shorty</title>
    <link href="https://fonts.googleapis.com/icon?family=Material+Icons"
          rel="stylesheet">
    <link rel="stylesheet" type="text/css" href="../static/skeleton.css">
    <link rel="stylesheet" type="text/css" href="../static/normalize.css">
    <link rel="stylesheet" type="text/css" href="../static/main.css">
    <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,700,900" rel="stylesheet">
</head>
<body>
<div class="container main_header">
    <h3 align="left"><a href="{{url_for('index')}}">Shorty</a></h3>
    <p>Un servicio de encurtido de URL muy sencillo.</p>
</div>
<!-- Resultados de búsqueda  -->
<div class=" container search_header">
    <h4>Resultados de búsqueda para : <b> {{ search_tag }} <b></h4>

    <div style="overflow-x:auto;">
        <div class="table_list u-full-width">
            <table>
                <thead>
                <tr>
                    <th>URL original</th>
                    <th>URL corta</th>
                    <th>Clics</th>
                    <th>Info</th>

                </tr>
                </thead>

                <tbody>
                {% for url in table %}
                <tr>
                    <td style="padding-left: 5px;">{{url[1]}}</td>
                    <td><a href="{{ host+url[2]}}">{{host+url[2]}}</a></td>
                    <td style="text-align: center;">{{url[4]}}</td>
                    <td id="info"><a href=" {{url_for('analytics',short_url=url[2])}} "><i class="material-icons">info_outline</i></a>
                    </td>
                </tr>
                {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</div>
</body>
</html>

Este código crea una plantilla para la página de resultados de búsqueda en el servicio de encurtido de URL "Shorty". Esta página está diseñada para mostrar los resultados de la búsqueda de URLs por etiquetas realizada por un usuario. A continuación, una descripción detallada de la plantilla:

  • Dentro del <body>, la sección de encabezado (<div class="container main_header">) es similar a la página de índice, proporcionando una apariencia y sensación consistentes. Incluye el nombre del servicio ("Shorty") como un enlace clicable que redirige a la página de índice ({{url_for('index')}}) y una breve descripción del servicio.
  • La sección <div class="container search_header"> introduce el área de resultados de búsqueda, comenzando con un encabezado (<h4>) que muestra dinámicamente la etiqueta utilizada para la búsqueda ({{ search_tag }}).
  • Los resultados se presentan en una tabla dentro de un div con estilo para desplazamiento horizontal (overflow-x:auto;), lo que garantiza la accesibilidad en dispositivos con pantallas más pequeñas.
  • La estructura de la tabla (<table>) consta de secciones de encabezado (<thead>) y cuerpo (<tbody>). El encabezado define columnas para "URL original", "URL corta", "Clics" e "Info", similar a la lista mostrada en la página de índice.
  • El cuerpo de la tabla se llena dinámicamente usando un bucle ({% for url in table %}), iterando sobre una colección de URLs (table) pasada desde el backend de Flask. Cada iteración crea una nueva fila (<tr>) en la tabla para una URL:
    • La URL original se muestra con un poco de relleno para una mejor legibilidad.
    • La URL acortada se presenta como un enlace clicable, construido agregando la ruta acortada al nombre del host, ambos de los cuales se insertan dinámicamente usando la sintaxis de plantillas de Flask.
    • La columna "Clics" muestra cuántas veces se ha accedido a la URL acortada, con el texto centrado para mayor claridad.
    • La columna "Info" proporciona un enlace a análisis detallados para cada URL, usando la función url_for de Flask para generar dinámicamente la URL y un icono (<i class="material-icons">info_outline</i>) para la representación visual.

Esta plantilla de resultados de búsqueda mejora el servicio "Shorty" al permitir a los usuarios encontrar y administrar efectivamente URLs basadas en etiquetas, proporcionando una experiencia de usuario fluida e intuitiva. El uso consistente de estilos y elementos de diseño de la página de índice garantiza un diseño cohesivo en toda la aplicación.

✨ Revisar Solución y Practicar

Crear la plantilla de la página de análisis

La página de análisis mostrará información detallada sobre el uso de una URL corta, incluyendo estadísticas de clics, navegador y plataforma.

En templates/data.html, agregue el siguiente código HTML:

<!doctype html>
<html>
  <head>
    <title>Shorty</title>

    <!-- Add Local SVG image when hosting. -->
    <link
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
      rel="stylesheet"
    />

    <link rel="stylesheet" type="text/css" href="../static/skeleton.css" />
    <link rel="stylesheet" type="text/css" href="../static/normalize.css" />
    <link rel="stylesheet" type="text/css" href="../static/main.css" />
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:300,400,700,900"
      rel="stylesheet"
    />
  </head>
  <body>
    <div class="container  main_header">
      <h3 align="left"><a href="{{url_for('index')}}">Shorty</a></h3>
      <p>Un servicio de encurtido de URL muy sencillo.</p>
    </div>
    <div class=" container modal-content">
      <!-- Índice del array -> 
      navegador : 
          CHROME,
          FIREFOX,
          SAFARI,
          OTRO_NAVEGADOR,
      plataforma:
          ANDROID,
          IOS,
          WINDOWS,
          LINUX,
          MAC,
          OTRO_PLATAFORMA
       -->
      <div class="url_info">
        <h4>
          Datos de análisis para :
          <a href="{{host+info[1]}}">{{'localhost/'+info[1]}}</a>
        </h4>
        <p>
          URL original :
          <a style="text-decoration: none" href="{{info[0]}}">{{info[0]}}</a>
        </p>
      </div>
      <div class="data_block">
        <div class="browser_list">
          <h4>Navegador</h4>
          <table>
            <thead>
              <tr>
                <th>Chrome</th>
                <th>Firefox</th>
                <th>Safari</th>
                <th>Otros navegadores</th>
              </tr>
            </thead>

            <tbody>
              <tr>
                <td style="padding-left: 5px;">{{browser[0]}}</td>
                <td>{{browser[1]}}</td>
                <td>{{browser[2]}}</td>
                <td>{{browser[3]}}</td>
              </tr>
            </tbody>
          </table>
        </div>
        <div class="platform_list">
          <h4>Plataforma</h4>
          <table>
            <thead>
              <tr>
                <th>Android</th>
                <th>IOS</th>
                <th>Windows</th>
                <th>Linux</th>
                <th>Mac</th>
                <th>Otras plataformas</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td style="padding-left: 5px;">{{platform[0]}}</td>
                <td>{{platform[1]}}</td>
                <td>{{platform[2]}}</td>
                <td>{{platform[3]}}</td>
                <td>{{platform[4]}}</td>
                <td>{{platform[5]}}</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
    </div>
  </body>
</html>

Este código incluye información sobre el número de clics, el uso del navegador y la distribución de plataformas. A continuación, se detalla su estructura y componentes:

  • Un div con las clases container modal-content encapsula la información de análisis, con un estilo similar a un modal o un bloque de contenido distinto dentro de la página.
  • El div url_info presenta:
    • Un encabezado <h4> que indica que los siguientes datos se refieren al análisis de una URL corta específica. La URL corta se muestra como un enlace clicable, construido utilizando las variables host e info[1], donde info[1] contiene la ruta corta.
    • Un párrafo (<p>) que muestra la URL original como un enlace clicable, lo que facilita el acceso al contenido original.
  • Dos secciones separadas, browser_list y platform_list, cada una contiene una tabla que muestra las estadísticas de uso para navegadores y plataformas, respectivamente:
    • La sección browser_list incluye una tabla con encabezados para Chrome, Firefox, Safari y Otros navegadores. La sección <tbody> muestra las estadísticas correspondientes, que se extraen del array variable browser pasado a la plantilla.
    • Del mismo modo, la sección platform_list tiene una tabla para el uso de plataformas, con encabezados para Android, iOS, Windows, Linux, Mac y Otras plataformas. Las estadísticas de uso se muestran en el cuerpo de la tabla, provenientes de la variable de matriz platform.
  • Las tablas usan <thead> para los encabezados y <tbody> para los datos reales, lo que garantiza un HTML semántico y facilita el estilo y la accesibilidad.
  • Las celdas de datos (<td>) dentro de las tablas muestran los recuentos respectivos para cada navegador y plataforma, alineados y con estilo para una mejor legibilidad.

Esta plantilla comunica efectivamente los datos de análisis al usuario, ofreciendo información sobre cómo se está accediendo a la URL corta, incluyendo los navegadores y plataformas utilizados por la audiencia. El diseño limpio, combinado con la clara separación de los datos en secciones distintas, hace que sea fácil para los usuarios entender e interpretar el rendimiento de su URL.

✨ Revisar Solución y Practicar

Crear la plantilla de la página 404

Una página 404 personalizada mejora la experiencia del usuario al proporcionar un mensaje de error más útil cuando no se encuentra una URL corta.

En templates/404.html, agregue el siguiente código HTML:

<!doctype html>
<html>
  <head>
    <title>Shorty</title>

    <!-- Add Local SVG image when hosting. -->
    <link
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
      rel="stylesheet"
    />

    <link rel="stylesheet" type="text/css" href="../static/skeleton.css" />
    <link rel="stylesheet" type="text/css" href="../static/normalize.css" />
    <link rel="stylesheet" type="text/css" href="../static/main.css" />
    <link
      href="https://fonts.googleapis.com/css?family=Roboto:300,400,700,900"
      rel="stylesheet"
    />
  </head>
  <body>
    <div class="lost">
      <h2>Oi, parece que estás perdido!</h2>
    </div>
  </body>
</html>

Esta plantilla de página 404 personalizada comunica efectivamente a los usuarios que la página que están buscando no existe, mientras mantiene un tono ameno.

✨ Revisar Solución y Practicar

Diseña la interfaz web

A continuación, diseñaremos la interfaz web. Comencemos creando el archivo CSS principal para dar estilo a nuestra aplicación.

En static/main.css, agregue el siguiente código CSS para dar estilo a los elementos HTML:

html {
  border-top: 5px solid #d9edf7;
}
body {
  font-family: "Roboto", sans-serif;
  margin-top: 50px;
  margin-bottom: 0;
}
h3 {
  padding: 0;
  margin: 0;
}
h3 a {
  font-weight: 700;
  text-decoration: none;
  color: black;
}
h3 a:hover {
  color: grey;
  transition: 0.2s all;
}
/** Encabezado principal */
.main_header {
  margin-bottom: 20px;
}
/* Bloque de búsqueda de URL */
.search_url_block {
  padding: 15px;
  background-color: #d9edf7;
  color: #31708f;
  border-radius: 5px;
  margin-bottom: 10px;
}
form {
  margin: 0;
}

.search_header {
  margin-top: 20px;
}

.material-icons {
  padding: 5px;
  padding-top: 7px;
  opacity: 0.7;
}

.material-icons:hover {
  opacity: 1;
}
/* Bloque de generación de URL */

.gen_block {
  margin-top: 10px;
  padding: 15px;
  background-color: #dff0d8;
  color: #2b542c;
  border-radius: 5px;
  width: auto;
  font-size: 20px;
}
/* Mostrar error */
.error_disp {
  padding: 15px;
  border-radius: 5px;
  background-color: #fcf8e3;
  color: #b84442;
  width: auto;
  font-size: 20px;
  margin-top: 10px;
}

/* Bloque de visualización de tabla*/

.table_list {
  padding-top: 10px;
  margin-top: 40px;
  border-top: 2px solid lightgrey;
}
table {
  font-size: 20px;
  width: 100%;
}
thead {
  font-weight: 700;
  padding: 2px;
}
tbody {
  font-weight: 400;
}
th {
  padding: 5px;
}
td {
  padding: 5px;
}
tr {
  padding: 5px;
}
tbody tr:hover {
  background-color: #f5f5f5;
  transition: 0.1s all ease-out;
}

/* Bloque de análisis*/
.url_info {
  margin-top: 10px;
  padding: 15px;
  background-color: #d9edf7;
  color: #31708f;
  border-radius: 5px;
  margin-bottom: 10px;
}
.url_info h4,
p {
  margin: 0;
  padding: 0;
}
.data_block {
  margin-top: 20px;
}

/* 404. Perdido*/
.lost {
  margin-top: 20px;
}
.lost h2 {
  font-weight: 700;
  font-size: 40px;
  text-align: center;

  color: #31708f;
}
.lost p {
  font-weight: 400;
  font-size: 20px;
  text-align: center;
}

El diseño general utiliza una combinación de colores de fondo, colores de texto y relleno para crear una interfaz limpia y moderna que es fácil de navegar. El uso de bordes redondeados en varios elementos le da a la interfaz una sensación más suave y amigable, mientras que los efectos al pasar el cursor mejoran la interactividad. El uso consistente de la fuente Roboto mantiene una apariencia coherente en toda la aplicación.

✨ Revisar Solución y Practicar

Funciones de conexión y operación de la base de datos

Las funciones de utilidad manejarán las conexiones a la base de datos, las validaciones de URL, la actualización de los contadores de navegador y plataforma y la generación de tokens aleatorios para las URL cortas.

Conexión a la base de datos

Primero, configurará la conexión a la base de datos usando pymysql. Esto es crucial para permitir que su aplicación Flask interactúe con la base de datos MySQL.

En utils.py, agregue el siguiente código de Python:

from urllib.parse import urlparse
import random
import string

import pymysql


db_config = {
    "host": "localhost",
    "user": "root",
    "password": "",
    "db": "SHORTY"
}


def get_db_connection() -> pymysql.Connection:
    """Crea y devuelve una nueva conexión a la base de datos."""
    return pymysql.connect(**db_config)
  • La librería pymysql se utiliza para conectarse a la base de datos MySQL. Esta librería permite que las aplicaciones de Python interactúen con las bases de datos MySQL usando una API simple.
  • El diccionario db_config contiene los parámetros de conexión a la base de datos, como host, usuario, contraseña y nombre de la base de datos. Estos se importan de un módulo config separado, presumiblemente para mayor seguridad y modularidad. Mantener las configuraciones separadas permite ajustes más fáciles sin modificar la base de código principal.
  • La función get_db_connection() crea y devuelve una nueva conexión a la base de datos usando la función pymysql.connect(**db_config). La sintaxis **db_config se utiliza para desempaquetar el diccionario en argumentos de palabras clave.

Funciones de operación de la base de datos

Después de establecer una conexión a la base de datos, el siguiente paso implica crear funciones que realicen operaciones en la base de datos. Estas incluyen listar datos para una URL corta dada y actualizar los contadores basados en el uso del navegador y la plataforma.

En utils.py, agregue el siguiente código de Python:

def list_data(shorty_url: str) -> tuple:
    """
    Toma short_url como entrada.
    Devuelve contador, navegador, marcas de tiempo de plataforma.
    """
    with get_db_connection() as conn, conn.cursor() as cursor:

        su = [shorty_url]
        info_sql = "SELECT URL, S_URL, TAG FROM WEB_URL WHERE S_URL = %s; "
        counter_sql = "SELECT COUNTER FROM WEB_URL WHERE S_URL = %s; "
        browser_sql = "SELECT CHROME, FIREFOX, SAFARI, OTHER_BROWSER FROM WEB_URL WHERE S_URL = %s;"
        platform_sql = "SELECT ANDROID, IOS, WINDOWS, LINUX, MAC, OTHER_PLATFORM FROM WEB_URL WHERE S_URL = %s;"

        cursor.execute(info_sql, su)
        info_fetch = cursor.fetchone()
        cursor.execute(counter_sql, su)
        counter_fetch = cursor.fetchone()
        cursor.execute(browser_sql, su)
        browser_fetch = cursor.fetchone()
        cursor.execute(platform_sql, su)
        platform_fetch = cursor.fetchone()

    return info_fetch, counter_fetch, browser_fetch, platform_fetch

def update_counters(cursor: pymysql.Connection, short_url: str, browser_dict: dict, platform_dict: dict) -> None:
    """Actualiza los contadores de navegador y plataforma en la base de datos para la short_url dada."""
    counter_sql = """UPDATE WEB_URL SET COUNTER = COUNTER + 1,
                     CHROME = CHROME + %s, FIREFOX = FIREFOX + %s, SAFARI = SAFARI + %s, OTHER_BROWSER = OTHER_BROWSER + %s,
                     ANDROID = ANDROID + %s, IOS = IOS + %s, WINDOWS = WINDOWS + %s, LINUX = LINUX + %s, MAC = MAC + %s, OTHER_PLATFORM = OTHER_PLATFORM + %s
                     WHERE S_URL = %s;"""
    cursor.execute(counter_sql, (browser_dict['chrome'], browser_dict['firefox'], browser_dict['safari'], browser_dict['other'],
                                 platform_dict['android'], platform_dict['iphone'], platform_dict[
                                     'windows'], platform_dict['linux'], platform_dict['macos'], platform_dict['other'],
                                 short_url))
  • La función list_data(shorty_url) está diseñada para recuperar varios tipos de información de la tabla WEB_URL para una URL corta dada (shorty_url). Establece una conexión a la base de datos y ejecuta cuatro consultas SQL para obtener la URL original, la etiqueta asociada, el contador de acceso, el navegador y la información analítica de la plataforma. Cada consulta se ejecuta por separado, y los resultados se recuperan y devuelven.
  • La función update_counters(cursor, short_url, browser_dict, platform_dict) actualiza el contador de acceso, el navegador y los conteos de plataforma para una URL corta dada en la base de datos. Esta función toma un cursor de base de datos, la URL corta y dos diccionarios que contienen los conteos para cada navegador y plataforma como argumentos. Construye una declaración SQL UPDATE para incrementar los contadores para la URL corta basada en los datos proporcionados. La función asume que la información del navegador y la plataforma se ha determinado previamente antes de llamar a esta función, y que esta información se pasa como diccionarios (browser_dict y platform_dict), con claves que corresponden a las columnas en la tabla WEB_URL.

Esta configuración es un patrón típico para aplicaciones web que usan Flask y MySQL, donde se definen funciones de utilidad para las operaciones comunes de la base de datos. Estas funciones luego se pueden importar y usar en toda la aplicación para interactuar con la base de datos, abstraiendo el acceso directo a la base de datos y las consultas SQL de la lógica principal de la aplicación.

✨ Revisar Solución y Practicar

Implementa funciones de utilidad no relacionadas con la base de datos

Por último, implementa funciones de utilidad que no interactúen con la base de datos. Estas incluyen la generación de tokens aleatorios para las URL cortas y la validación de URLs.

En utils.py, agregue el siguiente código de Python:

def random_token(size: int = 6) -> str:
    """
    Genera una cadena aleatoria de 6 caracteres, utiliza el argumento size
    para cambiar el tamaño del token.
    Devuelve un token válido del tamaño deseado,
    *el valor predeterminado es de 6 caracteres
    """
    BASE_LIST = string.digits + string.ascii_letters

    token = ''.join((random.choice(BASE_LIST)) for char in range(size))
    return token


def url_check(url: str) -> bool:
    """
    Espera una cadena como argumento.
    Devuelve True si la URL es válida, de lo contrario False.
    Para obtener documentación detallada, consulte urlparse.
    """
    try:
        result = urlparse(url)
        if all([result.scheme, result.netloc]):
            return True
        else:
            return False
    except:
        return False
  • La función random_token genera una cadena aleatoria que sirve como token para crear URLs cortas. Por defecto, crea un token de 6 caracteres pero se puede ajustar con el argumento size.
    • Utiliza una combinación de dígitos (string.digits) y letras (string.ascii_letters) como lista base para generar el token.
    • El token se genera seleccionando aleatoriamente caracteres de la BASE_LIST el número de veces especificado por el parámetro size. Esto se hace mediante una comprensión de lista y random.choice(), que selecciona un elemento aleatorio de la secuencia especificada.
    • El token generado se devuelve como una cadena. Este token se puede usar como identificador de la URL corta.
  • La función url_check valida una URL dada para asegurarse de que esté en un formato adecuado.
    • Utiliza la función urlparse del módulo urllib.parse para analizar la URL dada en componentes.
    • La función verifica si la URL tiene tanto un esquema (como http, https) como una ubicación de red (netloc, por ejemplo, www.example.com). Ambos son componentes esenciales para que una URL se considere válida.
    • Si ambos componentes están presentes, la función devuelve True, lo que indica que la URL es válida. Si falta cualquiera de ellos, o si se produce una excepción durante el análisis (por ejemplo, si la entrada no es una cadena), la función devuelve False.
    • Esta validación es importante para asegurarse de que solo se procesen y almacenen URLs válidas por la aplicación.

Estas funciones de utilidad son esenciales para el servicio de acortamiento de URLs, ya que proporcionan capacidades esenciales para generar identificadores únicos para las URLs acortadas y para garantizar que solo se acepten URLs válidas por el sistema.

✨ Revisar Solución y Practicar

Inicializa e implementa la ruta principal

Finalmente, construiremos el núcleo de nuestro servicio de acortamiento de URLs: la aplicación Flask.

Comencemos configurando la ruta principal. Esta ruta servirá la página principal y manejará tanto solicitudes GET como POST. En una solicitud GET, muestra todas las URLs acortadas. En una solicitud POST, acepta una nueva URL para acortar, genera un token único y la guarda en la base de datos.

En app.py, agregue el siguiente código de Python:

from flask import Flask, request, redirect, render_template, make_response

from utils import get_db_connection, list_data, random_token, update_counters, url_check


app = Flask(__name__)


@app.route('/', methods=['GET', 'POST'])
def index():
    with get_db_connection() as conn, conn.cursor() as cursor:
        ## Obtiene todos los datos para mostrar en la página principal
        cursor.execute("SELECT * FROM WEB_URL;")
        result_all_fetch = cursor.fetchall()

        if request.method == 'POST':
            og_url = request.form.get('url_input')
            custom_suff = request.form.get('url_custom', '')
            tag_url = request.form.get('url_tag', '')

            token_string = random_token() if not custom_suff else custom_suff

            if og_url and url_check(og_url):
                cursor.execute(
                    "SELECT S_URL FROM WEB_URL WHERE S_URL = %s FOR UPDATE", (token_string,))
                if cursor.fetchone() is None:
                    cursor.execute(
                        "INSERT INTO WEB_URL(URL, S_URL, TAG) VALUES(%s, %s, %s)", (og_url, token_string, tag_url))
                    conn.commit()
                    return render_template('index.html', shorty_url=f"{shorty_host}{token_string}")
                else:
                    error = "El sufijo personalizado ya existe. Por favor, use otro sufijo o déjelo en blanco para uno aleatorio."
            else:
                error = "Se proporcionó una URL no válida. Por favor, ingrese una URL válida."

            return render_template('index.html', table=result_all_fetch, host=shorty_host, error=error)

        return render_template('index.html', table=result_all_fetch, host=shorty_host)

La función index dentro de app.py configura la funcionalidad central del servicio de acortamiento de URLs utilizando Flask, un microframework web escrito en Python. Esta función define cómo se comporta la ruta principal (/) de la aplicación y procesa tanto solicitudes GET como POST. Aquí hay una explicación detallada del código:

Configuración de Flask

  • La aplicación Flask se inicializa con app = Flask(__name__).
  • El decorador @app.route('/', methods=['GET', 'POST']) especifica que la función index maneja las solicitudes a la URL raíz (/) y acepta ambos métodos GET y POST.

Manejo de solicitudes GET

  • Cuando la función recibe una solicitud GET, se conecta a la base de datos utilizando la función de utilidad get_db_connection() y obtiene todos los registros de la tabla WEB_URL. Esto es para mostrar todas las URLs acortadas en la página principal.
  • Los registros obtenidos se pasan a la función render_template, junto con la URL del host (shorty_host), para renderizar la plantilla index.html. Esta plantilla probablemente incluye una tabla o lista para mostrar cada URL acortada y sus detalles.

Manejo de solicitudes POST

  • Para las solicitudes POST, generalmente enviadas desde un formulario en la página principal, la función extrae la URL original (og_url), un sufijo personalizado opcional (custom_suff) y una etiqueta opcional (tag_url) de los datos del formulario.
  • Luego, genera un token aleatorio para la URL acortada utilizando random_token() a menos que se proporcione un sufijo personalizado. Este token (o sufijo personalizado) sirve como el identificador único para la URL acortada.
  • Antes de continuar, la función valida la URL original utilizando url_check(og_url). Si la URL es válida y el token/sufijo es único (no está ya en la base de datos), se inserta un nuevo registro en la tabla WEB_URL con la URL original, el token/sufijo como URL corta y la etiqueta.
  • Si la operación es exitosa, la función vuelve a renderizar la plantilla index.html, mostrando la URL acortada recién creada (shorty_url) junto con todos los registros existentes.
  • Si el token/sufijo ya existe en la base de datos o la URL original es inválida, se establece un mensaje de error y se renderiza la plantilla index.html con el mensaje de error y los registros existentes.

Manejo de errores y renderizado de plantillas

  • La función render_template se utiliza ampliamente para renderizar la plantilla index.html, pasando varios parámetros como la lista de todos los registros (table), la URL base del host para los enlaces acortados (host), la URL acortada recién creada (shorty_url) y cualquier mensaje de error (error). Esta función facilita el renderizado de contenido dinámico en Flask al insertar variables de Python en plantillas HTML.

Esta aplicación Flask sirve como el backend del servicio de acortamiento de URLs, manejando las interacciones con la base de datos, la validación de URLs y la generación de tokens, mientras también genera dinámicamente páginas web basadas en las interacciones del usuario y el contenido de la base de datos.

✨ Revisar Solución y Practicar

Implementa la ruta de redirección y la ruta de análisis

Ruta de redirección

A continuación, crea una ruta para manejar la redirección de una URL corta a la URL original. Esta ruta captura cualquier URL corta, la busca en la base de datos y redirige al usuario a la URL original.

Agrega el siguiente código a app.py:

@app.route('/<short_url>')
def reroute(short_url):
    with get_db_connection() as conn, conn.cursor() as cursor:
        platform = request.user_agent.platform or 'other'
        browser = request.user_agent.browser or 'other'
        browser_dict = {'firefox': 0, 'chrome': 0,'safari': 0, 'other': 0}
        platform_dict = {'windows': 0, 'iphone': 0,
                         'android': 0, 'linux': 0,'macos': 0, 'other': 0}

        ## Incrementa los contadores de navegador y plataforma
        browser_dict[browser] = browser_dict.get(browser, 0) + 1
        platform_dict[platform] = platform_dict.get(platform, 0) + 1

        cursor.execute(
            "SELECT URL FROM WEB_URL WHERE S_URL = %s;", (short_url,))
        try:
            new_url = cursor.fetchone()[0]
            update_counters(cursor, short_url, browser_dict, platform_dict)
            conn.commit()
            return redirect(new_url)
        except Exception:
            return render_template('404.html'), 404
  • El decorador @app.route('/<short_url>') crea una ruta dinámica que coincide con cualquier segmento de ruta que siga la URL raíz. Este segmento (short_url) se pasa a la función reroute como argumento.
  • Dentro de la función, se establece una conexión a la base de datos y se inicializan diccionarios para rastrear el navegador y la plataforma desde la cual proviene la solicitud. Se utiliza request.user_agent de Flask para determinar el navegador y la plataforma.
  • Luego, ejecuta una consulta SQL para encontrar la URL original asociada con la short_url dada. Si se encuentra, actualiza los contadores para el navegador y la plataforma en la base de datos utilizando la función update_counters.
  • Después de confirmar los cambios en la base de datos, la función utiliza la función redirect de Flask para enviar al usuario a la URL original.
  • Si la short_url no se encuentra en la base de datos, o ocurre cualquier otra excepción, la función renderiza una página de error 404 utilizando render_template('404.html').

Ruta de análisis

Crea una ruta de análisis que muestra información detallada sobre una URL corta específica, como el número de veces que se accedió y desde qué plataformas y navegadores.

Agrega el siguiente código a app.py:

@app.route('/analytics/<short_url>')
def analytics(short_url):
    info_fetch, counter_fetch, browser_fetch, platform_fetch = list_data(
        short_url)
    return render_template("data.html", host=shorty_host, info=info_fetch, counter=counter_fetch, browser=browser_fetch, platform=platform_fetch)
  • El decorador @app.route('/analytics/<short_url>') define una ruta para acceder a los análisis sobre una URL corta específica. La short_url se captura desde la ruta de la URL y se pasa a la función analytics.
  • La función llama a list_data(short_url), que consulta la base de datos para obtener información sobre la URL corta, incluyendo el número de veces que se ha accedido y la distribución del acceso en diferentes navegadores y plataformas.
  • Los datos recuperados (info_fetch, counter_fetch, browser_fetch, platform_fetch) se pasan a la función render_template junto con la URL del host (shorty_host) para renderizar la plantilla data.html. Esta plantilla probablemente presenta los datos de análisis en un formato amigable para el usuario, como tablas o gráficos.

Estas rutas amplían la funcionalidad del servicio de acortamiento de URLs, permitiendo no solo redirigir a los usuarios de las URLs cortas a sus destinos originales, sino también proporcionar información sobre cómo se están utilizando esas URLs cortas, incluyendo los conteos de acceso y los tipos de dispositivos y navegadores desde los cuales se acceden a los enlaces. Esta información puede ser valiosa para entender la repercusión y el impacto de las URLs compartidas.

✨ Revisar Solución y Practicar

Implementa la ruta de búsqueda y ejecuta la aplicación

Ruta de búsqueda

Configura una ruta de búsqueda para permitir que los usuarios encuentren URLs acortadas por etiquetas. Esta ruta maneja ambas solicitudes GET y POST, mostrando un formulario de búsqueda y procesando consultas de búsqueda, respectivamente.

Agrega el siguiente código a app.py:

@app.route('/search', methods=['GET', 'POST'])
def search():
    s_tag = request.form.get('search_url', '')
    if not s_tag:
        return render_template('index.html', error="Por favor, ingrese un término de búsqueda.")

    with get_db_connection() as conn, conn.cursor() as cursor:
        cursor.execute("SELECT * FROM WEB_URL WHERE TAG = %s", (s_tag,))
        search_tag_fetch = cursor.fetchall()
        return render_template('search.html', host=shorty_host, search_tag=s_tag, table=search_tag_fetch)
  • El decorador @app.route('/search', methods=['GET', 'POST']) configura la ruta en /search, manejando ambas solicitudes GET y POST. Mientras que la solicitud GET podría usarse para mostrar un formulario de búsqueda, la solicitud POST procesa los datos del formulario enviados por los usuarios.
  • Dentro de la función search, request.form.get('search_url', '') intenta recuperar el término de búsqueda de los datos del formulario enviados. El segundo parámetro ('') es el valor predeterminado si 'search_url' no se encuentra, lo que hace que el término de búsqueda sea una cadena vacía en tales casos.
  • Si no se proporciona un término de búsqueda (not s_tag), la función redirige al usuario a la página principal con un mensaje de error indicando que se requiere un término de búsqueda.
  • Si se proporciona un término de búsqueda, la función se conecta a la base de datos y ejecuta una consulta SQL para encontrar todos los registros en la tabla WEB_URL donde la columna TAG coincide con el término de búsqueda proporcionado. Esto permite a los usuarios encontrar todas las URLs acortadas asociadas con una etiqueta particular.
  • Los resultados de esta consulta (search_tag_fetch) se pasan a la función render_template, junto con la URL del host (shorty_host) y el término de búsqueda (s_tag), para renderizar la plantilla search.html. Esta plantilla probablemente muestra los resultados en un formato de lista o tabla, permitiendo a los usuarios ver todos los registros coincidentes y posiblemente interactuar con ellos (por ejemplo, visitar las URLs originales, ver análisis).

Ejecuta la aplicación

Finalmente, agrega el código para ejecutar tu aplicación Flask. Esto incluye configurar el host y el puerto en el que la aplicación escuchará, así como especificar las variables de entorno.

Agrega el siguiente código al final de app.py:

shorty_host = "https://****.labex.io/"

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

Nota: Debes reemplazar la URL en shorty_host con la URL del entorno actual. Puedes encontrarla cambiando a la pestaña Web 8080, y la URL debe terminar con /.

URL de la pestaña Web 8080

Ahora, puedes ejecutar el proyecto usando el siguiente comando:

python app.py

Cambia a la pestaña "Web 8080" y recarga la página web para ver los siguientes efectos.

Convierte la URL con/ sin sufijo personalizado, Busca URLs por etiqueta, Accede al enlace:

Ver información sobre el sistema operativo y la plataforma utilizados para acceder al enlace:

✨ Revisar Solución y Practicar

Resumen

¡Felicitaciones por completar el proyecto de acortador de URLs! Esta herramienta simplifica la compartición de URLs largas al crear enlaces más cortos y manejables. Sin embargo, hay un par de consideraciones importantes de las que debes tener en cuenta:

  1. Longitud de la URL base: Si la URL base del propio acortador es larga, las URLs acortadas resultantes pueden no ser tan cortas como se esperaba (como en el proyecto). La longitud total de la URL acortada incluye la URL base, lo que puede limitar la efectividad del acortador. Para obtener las URLs más concisas, considera usar una URL base o nombre de dominio más corto para tu servicio.

  2. Restricciones de inserción en sitios web: Puedes encontrar problemas como "Se negó a mostrar 'https://scholar.google.com/' en un marco porque estableció 'X-Frame-Options' en'sameorigin'". Este error se produce porque algunos sitios web usan el encabezado HTTP X-Frame-Options para evitar que su contenido se muestre en iframes de otros dominios, mejorando la seguridad contra ataques de "clickjacking". Cuando un sitio establece este encabezado en sameorigin, restringe la inserción a iframes que comparten el mismo origen. Esto no es una limitación del acortador de URLs sino una medida de seguridad implementada por el sitio web destino. Para una redirección sin problemas, es mejor usar las URLs acortadas como enlaces directos en lugar de insertarlas en iframes.

Estas consideraciones ponen de relieve el equilibrio entre comodidad y seguridad en el desarrollo web y la importancia de la conciencia del usuario para el uso óptimo de la herramienta.