Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

La Web es una de las fuentes de información más grandes y diversas disponibles en la actualidad. Contiene datos estructurados, semiestructurados y no estructurados que pueden ser aprovechados para múltiples propósitos: análisis de datos, investigación, monitoreo de precios, agregación de noticias, entre otros. En este capítulo exploraremos el funcionamiento de la Web y cómo acceder a información a través de APIs.

1Introducción al Funcionamiento de la Web

1.1Arquitectura Cliente-Servidor

La World Wide Web funciona bajo un modelo cliente-servidor. El siguiente diagrama ilustra cómo interactúan estos componentes:

Arquitectura Cliente-Servidor

Arquitectura Cliente-Servidor

Arquitectura Cliente-Servidor

Arquitectura Cliente-Servidor

Los componentes principales son:

Cliente (Navegador)
Programa que solicita recursos web (páginas HTML, imágenes, videos, etc.). Los navegadores más comunes son Chrome, Firefox, Safari y Edge.
Servidor Web
Aplicación que responde a las solicitudes de los clientes, enviando los recursos solicitados. Ejemplos incluyen Apache, Nginx, y servidores de aplicaciones como Node.js o Python con frameworks como Django o FastAPI.
DNS (Domain Name System)
Sistema que traduce nombres de dominio legibles (como www.untref.edu.ar) a direcciones IP numéricas que los computadores pueden entender.

En primer lugar el cliente o browser realiza una consulta DNS para obtener la dirección IP del servidor web asociado al dominio. Luego, el cliente envía una solicitud HTTP al servidor, que procesa la solicitud y devuelve una respuesta con el recurso solicitado.

Hoy en día a través de la web no solo se puede obtener páginas HTML, sino también se pueden ejecutar aplicaciones web completas, donde el servidor puede enviar datos y código (generalmente JavaScript) que se ejecuta en el navegador del cliente, permitiendo interfaces interactivas y dinámicas.

1.2Web Estática vs Dinámica

En los inicios de la Web, la mayoría de los sitios eran de naturaleza estática: el servidor simplemente enviaba archivos HTML pre-existentes al cliente. Sin embargo, la Web moderna es mayoritariamente dinámica.

Web Estática
El contenido es el mismo para todos los usuarios y solo cambia cuando el desarrollador edita los archivos manualmente. Es eficiente pero limitada.
Web Dinámica
El contenido se genera en tiempo real (por ejemplo, resultados de búsqueda, perfiles de usuario). El servidor utiliza lenguajes como Python, Java o PHP para consultar bases de datos y construir el HTML justo antes de enviarlo.

Desde la perspectiva de la recuperación de información, la búsqueda en la “web profunda” (deep web) se refiere a este contenido generado dinámicamente que no es fácilmente accesible siguiendo enlaces estáticos.

1.3Estructura de la Web (The Bow-tie structure)

A gran escala, la estructura de la Web no es una red aleatoria. Investigaciones clásicas Manning et al., 2008 han demostrado que el grafo de la Web tiene una forma de moño o corbata de moño (bow-tie structure).

Esta estructura se compone de tres partes principales:

  1. IN: Páginas que tienen enlaces hacia el centro, pero no reciben enlaces desde él.

  2. SCC (Strongly Connected Component): El núcleo central, donde es posible llegar de cualquier página a otra siguiendo enlaces.

  3. OUT: Páginas a las que se llega desde el centro, pero que no tienen enlaces de regreso hacia él.

Además, existen “zarcillos” (tendrils) y páginas aisladas que no se conectan a estos componentes principales. Entender esta estructura es vital para diseñar algoritmos de crawling eficientes.

1.4El Protocolo HTTP

HTTP (HyperText Transfer Protocol) es el protocolo de comunicación que permite la transferencia de información en la Web. Define cómo los clientes y servidores intercambian mensajes.

HTTP fue diseñado para ser simple y flexible, permitiendo la transferencia de diferentes tipos de datos (HTML, JSON, imágenes, etc.) a través de una estructura de mensajes estándar.

El protocolo HTTP sigue un modelo de solicitud-respuesta (request-response), donde el cliente envía una solicitud al servidor y este responde con el recurso solicitado o un mensaje de error.

En el siguiente diagrama de secuencia se muestra una interacción típica entre un cliente y un servidor utilizando HTTP:

Interacción HTTP Cliente-Servidor

Interacción HTTP Cliente-Servidor

Interacción HTTP Cliente-Servidor

Interacción HTTP Cliente-Servidor

Petición enviada:

GET /contact HTTP/1.1
Host: example.com
User-Agent: curl/8.6.0
Accept: */*

La petición HTTP consta de varias líneas, donde la primera línea indica el método HTTP (GET), el recurso solicitado (/contact) y la versión del protocolo (HTTP/1.1). Las líneas siguientes son las cabeceras (headers) que proporcionan información adicional sobre la solicitud. En este caso, se especifica el host, el agente de usuario (navegador) y los tipos de contenido aceptados.

Respuesta recibida:

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Date: Fri, 21 Jun 2024 14:18:33 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Content-Length: 1234

<!doctype html>
<!-- HTML content follows -->

La respuesta HTTP también consta de varias líneas, donde la primera línea indica el protocolo que usa el servidor y el código de estado (200 OK), seguido de las cabeceras de respuesta y finalmente el cuerpo del mensaje que contiene el HTML de la página.

Características de HTTP

Sin estado (stateless)
Cada solicitud es independiente, el servidor no mantiene información sobre solicitudes anteriores (algunos servidores implementan algunos mecanismos para manejar sesiones, pero esto no es parte del protocolo HTTP en sí).
Basado en texto
Los mensajes son legibles por humanos
Extensible
Permite agregar nuevos métodos y cabeceras
Cliente-Servidor
Modelo de comunicación request-response

Métodos HTTP Principales

Los métodos HTTP definen las peticiones que se puede solicitar al servidor sobre un recurso específico:

GET
Solicita un recurso específico. Es el método más común para solicitar un recurso al servidor. Si no se especifica un recurso en particular, el servidor generalmente devuelve la página principal, normalmente index.html.
POST
Envía datos al servidor para crear un nuevo recurso. Comúnmente usado en formularios.
PUT
Actualiza un recurso existente con datos nuevos.
DELETE
Elimina un recurso específico.
HEAD
Similar a GET, pero solo solicita las cabeceras de la respuesta, sin el cuerpo.
PATCH
Aplica modificaciones parciales a un recurso.

Códigos de Estado HTTP

Las respuestas HTTP incluyen un código de estado que indica el resultado de la solicitud:

2xx (Éxito)
  • 200 OK: Solicitud exitosa

  • 201 Created: Recurso creado exitosamente

  • 204 No Content: Éxito pero sin contenido para devolver

3xx (Redirección)
  • 301 Moved Permanently: El recurso se ha movido permanentemente

  • 302 Found: Redirección temporal

  • 304 Not Modified: El recurso no ha sido modificado desde la última solicitud

4xx (Error del Cliente)
  • 400 Bad Request: Solicitud mal formada

  • 401 Unauthorized: Autenticación requerida

  • 403 Forbidden: Acceso denegado

  • 404 Not Found: Recurso no encontrado

  • 429 Too Many Requests: Límite de velocidad excedido

5xx (Error del Servidor)
  • 500 Internal Server Error: Error genérico del servidor

  • 502 Bad Gateway: El servidor actuó como gateway y recibió una respuesta inválida

  • 503 Service Unavailable: Servidor no disponible temporalmente

URL Normalización (Canonicalización)

Un problema común al procesar datos de la Web es que diferentes URLs pueden apuntar al mismo recurso. Por ejemplo:

La normalización de URLs es el proceso de convertir URLs a una forma estándar o canónica. Esto es fundamental para evitar que un crawler descargue la misma página varias veces. Algunas reglas comunes incluyen:

En Python, la biblioteca requests facilita la realización de solicitudes HTTP. Aquí hay un ejemplo básico de cómo hacer una solicitud GET:

import requests

try:
    # Realizar una solicitud GET
    response = requests.get("https://untref.edu.ar/", timeout=30)

    print(f"Código de estado: {response.status_code}")
    for k, v in response.headers.items():
        print(f"{k}: {v}")
    print(f"\nPrimeros 200 caracteres del contenido (página html):")
    print(f"{response.text[:200]}")
except requests.exceptions.RequestException as e:
    print(f"No se pudo conectar a untref.edu.ar: {e}")
Output
Código de estado: 200
Date: Sat, 04 Apr 2026 00:09:17 GMT
Server: Apache
Cache-Control: no-cache
Set-Cookie: XSRF-TOKEN=eyJpdiI6IjVlSE1wdGhha2JiWTZvbjVTaVorWXc9PSIsInZhbHVlIjoiT2oyMGlTc29jSXRjZlQweTdqa1ZrRzZpUkY5Z2VCa1ZwamtiazhyZXVvbTZHWHRUZEF5Q3pKOGpxdVgzeEU3a3R5aVJqNVBSRHV4R2pRNDhcL2R5MWd3PT0iLCJtYWMiOiJjYmI4OTliMmZhYTgwNmYxNzA2NGRiMTZkZWEzMzcxYjEyM2YzOWI5MDEyMGVkMTU2YmU2Y2I0YmExNjZhNjU0In0%3D; expires=Sat, 04-Apr-2026 02:09:18 GMT; Max-Age=7200; path=/, laravel_session=eyJpdiI6IjdUVE5oazBITGtUUm9QT0JmeWlxRXc9PSIsInZhbHVlIjoic2puc0pSdTVObXRFZU9hMWRDSUZvNmV5a3B1TURnUStiNW10aUl3OWdNcUE4SjdYOW51Q3BqZFoxWDRQMWFzMTV3Zm9nejgrbXZOTVNPTzlDdkIwQ3c9PSIsIm1hYyI6ImRmMjk5ZWZkZTQwMDNlMWU2Y2ZkMGYyZTg5YjYyN2Q2NDU0YTIwMmYzNGQ5MWEwNjI0MTE5ZWI1YzBjMWFjMmYifQ%3D%3D; expires=Sat, 04-Apr-2026 02:09:18 GMT; Max-Age=7200; path=/; HttpOnly
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8

Primeros 200 caracteres del contenido (página html):
<!DOCTYPE html>
<html lang="es">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

    <title>UNTREF 
</title>

    

    <meta name="viewport" content="width=device-wi

El intercambio entre cliente y servidor puede verse en “crudo” utilizando herramientas como curl en la línea de comandos. Aquí hay un ejemplo de cómo se vería una solicitud y respuesta HTTP:

curl -v https://untref.edu.ar/

Petición enviada:

GET / HTTP/1.1
Host: www.untref.edu.ar
User-Agent: curl/8.12.1
Accept: */*

Respuesta recibida:

HTTP/1.1 200 OK
Date: Mon, 06 Oct 2025 15:06:59 GMT
Server: Apache
Cache-Control: no-cache
Set-Cookie: XSRF-TOKEN=eyJpdiI6IkhZbnpaYmpEV0ZaM1ZaRVwvYUQzbDZRPT0iLCJ2YWx1ZSI6ImtcL240ZFRjS1BhYWZmZWNcL0t3a1FtNFwvVWRhY0Q5Wm5qakF4M09UekM0T3hvbW0zb2FDTkZ3ZGxPTExQUGpCNXY1WUZvRW1oODhrQ2pEWlV4OCtkT3RnPT0iLCJtYWMiOiIzZjM3OTcyYTU4YmVlZmZmNGVhODIwOWI1Y2U5MWQ2YjNkZjBiMmFhZGQ3MjU2OWYzZTExYTQzZTA4NDVlY2JhIn0%3D; expires=Mon, 06-Oct-2025 17:07:00 GMT; Max-Age=7200; path=/
Set-Cookie: laravel_session=eyJpdiI6IkxIeHIyRElDdm82bFV1WDdrRTRickE9PSIsInZhbHVlIjoiYTRMZklQZDk2RTgwMjdLMXlFQ2ltVjJoWjhsdzB1a2ZhSmVYYlo1amc4a1FwYU9EQUQrWUo2b2QweEVxQThPcTJnWTlTbklMMkNUYjdJVUtGYWsyOXc9PSIsIm1hYyI6ImExOTNmMGNhN2NjMGJlN2I2ZDAwZTIwNWMyMDg2ZTU3NTdlNjYwNTRmYTc4NTYyODU4NjBmMTI0YWQ4Y2JhNWYifQ%3D%3D; expires=Mon, 06-Oct-2025 17:07:00 GMT; Max-Age=7200; path=/; HttpOnly
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
<!DOCTYPE html>
<html lang="es">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

    <title>UNTREF</title>
...

1.5HTTPS: HTTP Seguro

HTTPS (HTTP Secure) es la versión segura de HTTP que utiliza encriptación TLS/SSL para proteger la comunicación entre cliente y servidor. Es fundamental para:

2APIs: Interfaces de Programación de Aplicaciones

Las APIs (Application Programming Interfaces) son interfaces que permiten que diferentes aplicaciones se comuniquen entre sí de manera programática. En el contexto web, las APIs proporcionan puntos de acceso (endpoints) que los desarrolladores pueden usar para acceder a datos y funcionalidades de un servicio.

Arquitectura de una API REST

Arquitectura de una API REST

Arquitectura de una API REST

Arquitectura de una API REST

Una aplicación cliente (por ejemplo una aplicación web o móvil) realiza solicitudes HTTP a una API REST, que procesa la solicitud, interactúa con bases de datos u otros servicios, y devuelve los datos en formatos como JSON o XML.

El protocolo base es HTTP, y los recursos se acceden a través de URLs específicas. Por ejemplo una URL típica de una API REST podría ser:

https://api.ejemplo.com/v1/usuarios/123

Donde:

Ante esta solicitud, la API podría devolver un JSON con los datos del usuario:

{
  "id": 123,
  "nombre": "Juan Pérez",
  "email": "juan.perez@ejemplo.com"
}

2.1API REST (Representational State Transfer)

REST es un estilo arquitectónico para diseñar servicios web que se basa en los principios de HTTP. Una API REST expone recursos a través de URLs y utiliza los métodos HTTP estándar para operaciones CRUD (Create, Read, Update, Delete).

Principios de REST

Arquitectura Cliente-Servidor
Separación de responsabilidades entre interfaz de usuario y almacenamiento de datos.
Sin Estado
Cada solicitud contiene toda la información necesaria; el servidor no mantiene sesiones.
Cacheable
Las respuestas deben indicar si pueden ser almacenadas en caché.
Interfaz Uniforme
Uso consistente de URLs y métodos HTTP.
Sistema en Capas
La arquitectura puede tener múltiples capas intermedias.

Ejemplo: Consumir una API REST Pública

Vamos a consumir una API pública para consultar resultados electorales de Argentina, disponible en https://resultados.mininterior.gob.ar.

import requests
import json

try:
    # Realizar una solicitud GET a la API del Ministerio del Interior
    response = requests.get(
        "https://resultados.mininterior.gob.ar/api/resultados/getResultados?"
        "anioEleccion=2019&tipoRecuento=1&tipoEleccion=2&categoriaId=1&"
        "distritoId=2&seccionProvincialId=1&seccionId=118",
        timeout=30
    )
    if response.status_code == 200:
        datos = response.json()
        print(json.dumps(datos, indent=2, ensure_ascii=False))
    else:
        print(f"Error al acceder a la API: {response.status_code}")
        print(json.dumps(response.json(), indent=2, ensure_ascii=False))
except requests.exceptions.RequestException as e:
    print(f"No se pudo conectar a resultados.mininterior.gob.ar: {e}")
Output
{
  "fechaTotalizacion": "2025-11-01T19:23:51.586Z",
  "estadoRecuento": {
    "mesasEsperadas": 0,
    "mesasTotalizadas": 777,
    "mesasTotalizadasPorcentaje": 0,
    "cantidadElectores": 270534,
    "cantidadVotantes": 222724,
    "participacionPorcentaje": 82.33
  },
  "valoresTotalizadosPositivos": [
    {
      "idAgrupacion": "131",
      "nombreAgrupacion": "FRENTE NOS",
      "votos": 3211,
      "votosPorcentaje": 1.47,
      "idAgrupacionTelegrama": "",
      "urlLogo": ""
    },
    {
      "idAgrupacion": "133",
      "nombreAgrupacion": "FRENTE DE IZQUIERDA Y DE TRABAJADORES - UNIDAD",
      "votos": 6596,
      "votosPorcentaje": 3.02,
      "idAgrupacionTelegrama": "",
      "urlLogo": ""
    },
    {
      "idAgrupacion": "137",
      "nombreAgrupacion": "CONSENSO FEDERAL",
      "votos": 16391,
      "votosPorcentaje": 7.52,
      "idAgrupacionTelegrama": "",
      "urlLogo": ""
    },
    {
      "idAgrupacion": "135",
      "nombreAgrupacion": "JUNTOS POR EL CAMBIO",
      "votos": 82191,
      "votosPorcentaje": 37.69,
      "idAgrupacionTelegrama": "",
      "urlLogo": ""
    },
    {
      "idAgrupacion": "136",
      "nombreAgrupacion": "FRENTE DE TODOS",
      "votos": 105968,
      "votosPorcentaje": 48.59,
      "idAgrupacionTelegrama": "",
      "urlLogo": ""
    },
    {
      "idAgrupacion": "87",
      "nombreAgrupacion": "UNITE POR LA LIBERTAD Y LA DIGNIDAD",
      "votos": 3728,
      "votosPorcentaje": 1.71,
      "idAgrupacionTelegrama": "",
      "urlLogo": ""
    }
  ],
  "valoresTotalizadosOtros": {
    "votosNulos": 1666,
    "votosNulosPorcentaje": 0.75,
    "votosEnBlanco": 2338,
    "votosEnBlancoPorcentaje": 1.05,
    "votosRecurridosComandoImpugnados": 635,
    "votosRecurridosComandoImpugnadosPorcentaje": 0.29
  }
}

En la solicitud anterior, se puede ver que se utilizan varios parámetros en la URL para especificar los datos que se quieren consultar

ParámetroValorSignificado
anioEleccion=20192019Año de la elección consultada.
tipoRecuento=111 = Recuento Provisional
tipoEleccion=222 = Elecciones Generales
categoriaId=111 = Presidente de la Nación.
distritoId=222 = Provincia de Buenos Aires.
seccionProvincialId=111 = Primera Sección Electoral.
seccionId=118118118 = Tres de Febrero.

La documentación de la API se puede descargar desde el sitio oficial del Ministerio del Interior.

La respuesta de la API es un JSON con los resultados detallados para Tres de Febrero.

Ejemplo: API de Información Geográfica

Muchas APIs REST proporcionan datos estructurados útiles. Vamos a consultar OpenStreetMap (OSM) que ofrece datos geográficos.

import requests
from lxml import etree as ET

try:
    # Realizar una solicitud GET a la API de Open Maps
    # Way Id = 1275831310 (Sede Caseros I de la UNTREF)
    response = requests.get(
        "https://api.openstreetmap.org/api/0.6/way/1275831310", timeout=30
    )
    if response.status_code == 200:
        # Parsear la respuesta XML
        root = ET.fromstring(response.content)
        # Recorrer el XML de OpenStreetMap

        # Buscar el elemento <way>
        way = root.find("way")
        if way is not None:
            print(f"ID del way: {way.get('id')}")
            print("Etiquetas asociadas:")
            for tag in way.findall("tag"):
                clave = tag.get("k")
                valor = tag.get("v")
                print(f"  {clave}: {valor}")
        else:
            print("No se encontró el elemento <way> en la respuesta.")
    else:
        print(f"Error al acceder a la API: {response.status_code}")
except requests.exceptions.RequestException as e:
    print(f"No se pudo conectar a api.openstreetmap.org: {e}")
Output
ID del way: 1275831310
Etiquetas asociadas:
  addr:city: Caseros
  addr:housenumber: 4828;4838
  addr:postcode: B1678ABJ
  addr:street: 602 - Valentín Gómez
  alt_name: Sede Caseros I
  amenity: university
  building: university
  name: UNTREF - Sede Caseros I
  official_name: Universidad Nacional de Tres de Febrero - Sede Caseros I
  source: https://www.untref.edu.ar/sedes
  website: https://www.untref.edu.ar/

La documentación de la API de OpenStreetMap está disponible en https://wiki.openstreetmap.org/wiki/API_v0.6.

Con el way ID 1275831310 también se puede obtener el mapa correspondiente a través del servicio Overpass API, que permite consultas más complejas. Aquí hay un ejemplo de cómo obtener la geometría del way en formato GeoJSON y visualizarlo en un mapa interactivo usando la librería folium:

import requests
import folium


def obtener_geojson_way(osm_way_id):
    # Consulta Overpass para el way específico
    url = "https://overpass-api.de/api/interpreter"
    # Query Overpass: way + nodos + metadata
    query = f"""
    [out:json];
    way({osm_way_id});
    out body;
    >;
    out meta;
    """
    response = requests.get(url, params={"data": query}, timeout=30)
    response.raise_for_status()
    return response.json()


def construir_mapa(geojson_data):
    # Extraer nodos del way y sus coordenadas
    # Overpass pone los nodos como elementos tipo "node" en el array "elements"
    nodes = {}
    for el in geojson_data.get("elements", []):
        if el["type"] == "node":
            nodes[el["id"]] = (el["lat"], el["lon"])
    # Construir lista ordenada de coordenadas del way
    coords = []
    for el in geojson_data.get("elements", []):
        if el["type"] == "way":
            for nid in el["nodes"]:
                if nid in nodes:
                    coords.append(nodes[nid])
    # Centrar el mapa en la primera coordenada
    if not coords:
        raise RuntimeError("No se hallaron coordenadas del way")
    centro = coords[0]
    mapa = folium.Map(location=centro, zoom_start=18)
    # Añadir polígono (o línea) al mapa
    folium.PolyLine(locations=coords, color="blue", weight=3).add_to(mapa)
    # También podrías usar folium.Polygon si es cerrado
    return mapa
    # Visualizar el mapa en el notebook


def main():
    osm_way_id = 1275831310  # el way de la Sede Caseros I
    try:
        geojson = obtener_geojson_way(osm_way_id)
        mapa = construir_mapa(geojson)
        # Mostrar el mapa en el notebook
        display(mapa)
    except requests.exceptions.RequestException as e:
        print(f"No se pudo obtener datos de Overpass API: {e}")
    except RuntimeError as e:
        print(f"Error al construir el mapa: {e}")


if __name__ == "__main__":
    main()

El fragmento de código anterior realiza los siguientes pasos:

  1. Extraer coordenadas de los nodos que forman el “way” desde un objeto GeoJSON.

  2. Centrar el mapa en la primera coordenada encontrada.

  3. Dibujar la línea (o polígono) sobre el mapa usando folium.PolyLine.

  4. Mostrar el mapa en un entorno interactivo (como Jupyter Notebook) usando display(mapa).

La función principal (main) obtiene el GeoJSON de un “way” específico, en este caso la Sede Caseros I, construye el mapa y lo muestra.

overpass-api.de es un servicio web que permite consultar y extraer datos de OpenStreetMap mediante un lenguaje de consultas específico (Overpass QL). Se usa para obtener información geográfica detallada, como nodos, caminos y relaciones, de la base de datos de OSM.

Los servicios que ofrece OpenStreetMap se pueden consultar en su wiki.

Autenticación en APIs REST

Las APIs frecuentemente requieren autenticación, sobre todo cuando se trata de servicios privados. Los métodos más comunes son:

API Keys
Una clave secreta que se envía en la URL o en las cabeceras.
OAuth 2.0
Protocolo de autorización más complejo pero seguro, usado por servicios como Google, Facebook, Twitter.
Bearer Tokens
Tokens de acceso que se envían en el header de autorización.

En general, antes de poder consultar una API, es necesario registrarse y obtener las credenciales necesarias.

3Mejores Prácticas para Usar APIs

  1. Leer la documentación: Entender límites de velocidad, autenticación y términos de uso

  2. Manejar errores: Implementar reintentos con backoff exponencial

  3. Cachear respuestas: Evitar solicitudes repetidas

  4. Monitorear cuotas: Estar atento a los límites de uso

  5. Versionar: Usar versiones específicas de APIs para evitar cambios inesperados

4Referencias y Recursos Adicionales

4.1Documentación Oficial

4.2APIs Públicas para Practicar

4.3Libros y Referencias Académicas

References
  1. Manning, C. D., Raghavan, P., & Schütze, H. (2008). Introduction to Information Retrieval. Cambridge University Press. https://nlp.stanford.edu/IR-book/