--- name: scrape_tiktok_creative kind: function lang: py domain: datascience version: "1.0.0" purity: impure signature: "def scrape_tiktok_creative(country: str = 'ES', kind: str = 'hashtag', limit: int = 50, period: int = 7) -> list[dict]" description: "Capta tendencias del TikTok Creative Center (hashtags, canciones, creadores y videos virales con metricas reales) via su API JSON interna creative_radar_api. Headers realistas con requests, paginacion, parseo tolerante a cambios de schema. Devuelve filas 1:1 con la tabla Postgres tiktok_trends. Impure: hace HTTP a un endpoint interno no publico que puede romperse o exigir anti-bot." tags: [tiktok, social, trends, market-intel, datascience] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: [requests] params: - name: country desc: "Codigo ISO de pais del ranking (ej. 'ES', 'US', 'MX'). El Creative Center segmenta las tendencias por mercado. Default 'ES'." - name: kind desc: "Tipo de tendencia: 'hashtag' (default, el mas estable), 'song', 'creator' o 'video'. Cada uno usa un endpoint interno distinto. Empieza por hashtag si no estas seguro." - name: limit desc: "Numero maximo de filas a devolver. El endpoint pagina de 50 en 50; la funcion concatena paginas hasta alcanzar limit o agotar resultados. Default 50." - name: period desc: "Ventana temporal en dias. Solo acepta 7 (default), 30 o 120 — el endpoint rechaza otros valores con error de validacion." output: "Lista de dicts con EXACTAMENTE las claves: country (str), kind (str), name (str|None), rank (int|None), views (int|None, BIGINT), growth_pct (float|None), industry (str|None), url (str|None). Mapea 1:1 con la tabla Postgres tiktok_trends (sin id/snapshot_date/scraped_at). Devuelve [] si el endpoint responde OK pero sin items para el segmento. Lanza ValueError (kind/period invalidos) o RuntimeError (403 anti-bot, HTTP de error, JSON invalido, code de error logico)." tested: false tests: [] test_file_path: "" file_path: "python/functions/datascience/scrape_tiktok_creative.py" notes: | ESTRATEGIA: el Creative Center (ads.tiktok.com/business/creativecenter) es una SPA JS-rendered, pero alimenta sus rankings desde una API interna de facto bajo https://ads.tiktok.com/creative_radar_api/v1/popular_trend/... Esta funcion habla directamente con ese endpoint con requests (mucho mas barato que un navegador headless CUANDO responde). El parseo tolera variaciones del schema (data.list, data.hashtags, data.items...) y nombres de campo distintos por kind. REALISMO: en pruebas reales desde un entorno headless/datacenter el endpoint respondio con code=40101 ("no permission") — rechazo anti-bot por falta de los tokens de sesion firmados (anonymous-user-id, user-sign, timestamp) que la SPA genera en cliente y que no se pueden falsear fuera del navegador. La funcion NO inventa datos: en ese caso lanza RuntimeError con un mensaje claro. Se considera el comportamiento esperado, no un bug de la funcion. --- ## Ejemplo ```python from datascience.scrape_tiktok_creative import scrape_tiktok_creative # Top 50 hashtags virales en Espana, ultimos 7 dias. rows = scrape_tiktok_creative(country="ES", kind="hashtag", limit=50, period=7) # rows[0] -> { # "country": "ES", "kind": "hashtag", "name": "fyp", "rank": 1, # "views": 12450000, "growth_pct": 42.0, "industry": "Entertainment", # "url": "https://ads.tiktok.com/business/creativecenter/hashtag/fyp/pc/en" # } # Canciones en tendencia en US, ventana de 30 dias. songs = scrape_tiktok_creative(country="US", kind="song", limit=20, period=30) # Las filas casan 1:1 con un INSERT en la tabla Postgres tiktok_trends # (sin id/snapshot_date/scraped_at, que los pone la BD). ``` ## Cuando usarla Usala cuando necesites market intelligence de TikTok: detectar hashtags, canciones, creadores o productos virales por pais con metricas reales (views, ranking, crecimiento) para alimentar la tabla `tiktok_trends`, un dashboard de tendencias o un analisis de oportunidad de contenido. Empieza por `kind="hashtag"` (el endpoint mas estable) antes de probar song/creator/video. Si el fetch HTTP devuelve RuntimeError por anti-bot, baja al browser MCP/CDP del ecosistema. ## Gotchas - **El endpoint interno NO es una API publica versionada.** `creative_radar_api/v1/popular_trend` es un contrato de facto que TikTok cambia sin aviso: ruta, parametros, schema del JSON y claves de campo pueden romperse en cualquier deploy. El parseo es tolerante pero no inmune; si TikTok mueve la lista a otra ruta, la funcion devuelve [] o lanza RuntimeError. - **Anti-bot real y frecuente.** Desde IPs de datacenter o entornos headless el endpoint suele responder `403` o `code=40101 (no permission)`. Los rankings se sirven solo a clientes con los tokens de sesion firmados que la SPA genera en navegador (`anonymous-user-id`, `user-sign`, `timestamp`). Esos tokens NO se pueden falsear con requests. **Verificado en self-test: respondio code=40101.** - **Alternativa robusta cuando el HTTP esta bloqueado:** usar el browser MCP/CDP del ecosistema (regla `flow_replay.md`) navegando el Creative Center con una sesion de chrome real, dejando que el cliente genere los tokens, y leyendo el JSON de la respuesta XHR o el DOM renderizado. Es mas caro pero pasa el anti-bot. - **No inventa datos.** Si no puede extraer de verdad, lanza una excepcion clara con el codigo HTTP / code logico para diagnostico, en vez de devolver filas falsas. - **growth_pct heuristico:** el Creative Center expresa el crecimiento como ratio (0.42) o como porcentaje (42) segun campo/version; la funcion normaliza ratios en [-1, 1] a porcentaje (*100). Si TikTok cambia la convencion, revisar `_row_from_item`. - **Rate limiting:** la paginacion hace una request por pagina de 50. Para `limit` altos puedes encadenar varias requests rapidas — anade backoff propio si scrapeas muchos paises seguidos para no acelerar el bloqueo.