Python · YouTube

Monitoriza las estadísticas de vídeos de YouTube con Python

YouTube muestra el número actual de visualizaciones de un vídeo, pero no cómo ha llegado hasta ahí. Si quieres saber lo rápido que crece un vídeo (tuyo, de un competidor o de una campaña que has pagado), tienes que anotar las cifras con regularidad. Esta guía crea un pequeño script que lo hace por ti.

Una vez al día pide a everydata.io las visualizaciones, los me gusta y los comentarios actuales de cada vídeo de tu lista, añade una línea a un archivo CSV e imprime cuántas visualizaciones ha ganado cada vídeo desde la última ejecución. Opcionalmente, también recoge las subidas más recientes de un canal, para que los vídeos nuevos se sigan desde su primer día.

Actualizado el · por everydata.io

Lo que tendrás al final

  • Un archivo CSV con una fila por vídeo y día: visualizaciones, me gusta, comentarios.
  • El crecimiento de visualizaciones desde la consulta anterior, impreso en cada ejecución.
  • Seguimiento automático de las nuevas subidas de un canal.

Lo que necesitas

  • Python 3.10 o posterior y pip install requests.
  • Una clave de API gratuita de everydata.io (créala aquí) en la variable de entorno EVERYDATA_API_KEY.
  • Los vídeos que quieres seguir: el ID que va después de v= en el enlace, o el enlace completo.

01Mira qué devuelve la API para un vídeo

El endpoint de detalles del vídeo recibe un ID o un enlace de vídeo en id y devuelve las cifras públicas de la página del vídeo. Ejemplo documentado, reducido:

Respuesta de ejemplo · GET /ytb/youtube-video-details
{
  "responseStatus": "PAGE_FOUND",
  "responseMessage": "Page successfully found!",
  "videoId": "kJQP7kiw5Fk",
  "title": "Luis Fonsi - Despacito ft. Daddy Yankee",
  "channelName": "LuisFonsiVEVO",
  "viewCount": 9125159593,
  "likeCount": 56673581,
  "likeCountText": "56M",
  "commentCount": 4300000,
  "publishedAt": "2017-01-12T21:00:02-08:00",
  "duration": 282
}

viewCount, likeCount y commentCount son números simples, listos para guardar y comparar. likeCountText es la etiqueta redondeada que YouTube muestra en la página.

02Registra las cifras en cada ejecución

El script lee del archivo CSV el último número de visualizaciones de cada vídeo, obtiene las cifras actuales, añade una fila nueva e imprime la diferencia.

monitor.py
"""Record views, likes and comments of YouTube videos and print the growth since the last check."""
import csv
import os
import re
import time
from datetime import datetime, timezone
from pathlib import Path

import requests

API = "https://api.everydata.io"
KEY = os.environ["EVERYDATA_API_KEY"]
CSV_FILE = Path("video_stats.csv")
VIDEOS = ["kJQP7kiw5Fk"]  # video IDs or full YouTube links


def api_get(path: str, params: dict) -> dict:
    """GET an everydata.io endpoint. Waits when rate limited (429) and retries a failed page load (5xx) once."""
    retried = False
    for _ in range(4):
        resp = requests.get(f"{API}{path}", params=params, headers={"x-api-key": KEY}, timeout=60)
        if resp.status_code == 429:
            # Too many requests at once. The answer says how long to wait: "... Try again in 12 seconds."
            wait = re.search(r"in (\d+) seconds", resp.text)
            time.sleep(int(wait.group(1)) + 1 if wait else 60)
            continue
        if resp.status_code >= 500 and not retried:
            retried = True  # 5xx answers are not counted against your quota
            time.sleep(10)
            continue
        resp.raise_for_status()  # 4xx (wrong key, quota used up, bad parameter) or a second 5xx
        return resp.json()
    raise RuntimeError("still rate limited after several waits – try again later")


def video_details(video: str) -> dict:
    return api_get("/ytb/youtube-video-details", {"id": video})


def last_views() -> dict[str, int]:
    """Most recent view count per video from earlier runs."""
    if not CSV_FILE.exists():
        return {}
    with CSV_FILE.open(newline="") as f:
        return {r["video_id"]: int(r["views"]) for r in csv.DictReader(f) if r["views"]}


def main() -> None:
    before = last_views()
    now = datetime.now(timezone.utc).isoformat(timespec="seconds")
    new_file = not CSV_FILE.exists()

    with CSV_FILE.open("a", newline="") as f:
        writer = csv.writer(f)
        if new_file:
            writer.writerow(["checked_at", "video_id", "title", "views", "likes", "comments"])
        for video in VIDEOS:
            try:
                v = video_details(video)
            except (requests.RequestException, RuntimeError) as exc:
                print(f"{video}: could not check this time ({exc}) – the next run tries again")
                continue  # one failed video does not stop the others
            video_id = v.get("videoId") or video
            views = v.get("viewCount")
            writer.writerow([now, video_id, v.get("title"), views or "",
                             v.get("likeCount") or "", v.get("commentCount") or ""])
            if views is not None and video_id in before:
                print(f"{v.get('title')}: +{views - before[video_id]:,} views since the last check")


if __name__ == "__main__":
    main()

Ejecútalo con python3 monitor.py. A partir de la segunda ejecución verás líneas como “+12,345 views since the last check”. api_get espera y continúa cuando envías demasiadas solicitudes a la vez (429) y reintenta una vez una carga de página fallida (5xx); un vídeo que sigue fallando se notifica y se vuelve a intentar en la siguiente ejecución.

03Recoge los vídeos nuevos de un canal

En lugar de añadir a mano cada vídeo nuevo, pide las últimas subidas de un canal e inclúyelas en la lista. El endpoint de vídeos del canal acepta un ID de canal o un enlace de canal.

monitor.py (añadir debajo de video_details)
def latest_uploads(channel: str) -> list[str]:
    """IDs of the newest regular videos of a channel (channel ID or URL such as https://www.youtube.com/@WWE)."""
    data = api_get("/ytb/youtube-channel-videos", {"id": channel, "filter": "videos_latest"})
    return [item["videoId"] for item in data.get("items", []) if item.get("type") == "video"]


# In main(): watch the five newest uploads of a channel as well as your fixed list
# for video in VIDEOS + latest_uploads("https://www.youtube.com/@WWE")[:5]:
Respuesta de ejemplo · GET /ytb/youtube-channel-videos
{
  "responseStatus": "PAGE_FOUND",
  "responseMessage": "Page successfully found!",
  "channelId": "UCJ5v_MCY6GNUBTO8-D3XoAg",
  "filter": "videos_latest",
  "items": [
    {
      "type": "video",
      "videoId": "b7kl_pcHa0A",
      "title": "Blake Monroe vows to get payback against Giulia: SmackDown exclusive, Sept. 18, 2026",
      "viewCount": 6800,
      "publishedTimeText": "47 minutes ago"
    }
  ]
}

04Ejecútalo una vez al día

Programa el script con cron (Mac, Linux), el Programador de tareas de Windows o una tarea programada de CI:

crontab
0 6 * * * cd /home/you/yt-monitor && EVERYDATA_API_KEY=ds_your_key /usr/bin/python3 monitor.py >> monitor.log 2>&1

Cada consulta de vídeo y cada consulta de canal es una solicitud. Por ejemplo, tres vídeos consultados una vez al día son unas 90 solicitudes al mes, dentro del plan gratuito de 100. Para cifras diarias de muchos vídeos, consulta los precios.

Abre video_stats.csv en una hoja de cálculo y representa las visualizaciones frente a checked_at para ver la curva de crecimiento.

Endpoints utilizados en esta guía

GET/ytb/youtube-video-details

Video Details · API de YouTube

GET/ytb/youtube-channel-videos

Channel Videos · API de YouTube

Todos los parámetros en la referencia de la API

Pruébalo con tus propios datos

El plan gratuito incluye 100 solicitudes al mes, utilizables en todas las plataformas: suficiente para seguir esta guía de principio a fin.