feat(shell): auto-commit con 31 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
---
|
||||
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.
|
||||
Reference in New Issue
Block a user