Fuentes de sentimiento sin comprometer cuenta — Surtidito
2026-09-06 · verificado en vivo (curl) contra las APIs nombradas
Contexto
feed.py ya trae X vía RSSHub local (token de sesión propio, grey zone ToS) y
RSS de medios. Para análisis de sentimiento se necesitan corpus con VOLUMEN y
RESPUESTAS, sin exponer la cuenta personal.
Auditoría de la respuesta de otro asistente (lo que está mal)
- snscrape → MUERTO para X. Última release 2023-06; X cerró la guest API en julio-2023. No devuelve nada. No usar.
pysentimiento/spanish-twitter-sentiment→ dataset INVENTADO. Lo real es el MODELOpysentimiento/robertuito-sentiment-analysis(verificado HF API).cardiffnlp/twitter-xlm-roberta-base-sentiment→ es modelo, no dataset (verificado). Sirve como clasificador EN/multilingüe.kazanova/sentiment140→ real pero tweets de 2009 en inglés. Inútil para sentimiento MX-2026.- Mastodon scraping con BeautifulSoup → innecesario, pero ojo: el timeline público de mastodon.social AHORA exige auth (verificado: 401 anónimo). Token read-only gratis, 2 min.
- datos sintéticos para MEDIR sentimiento → circular: no puedes generar el dato que mides. Solo valen para fine-tunear el clasificador.
Lo que sí funciona (verificado hoy)
- Bluesky API pública SIN cuenta —
https://public.api.bsky.app/xrpc/app.bsky.feed.getAuthorFeed?actor=...responde 200 anónimo. El SDKatprotoni siquiera hace falta para leer. ⚠️ Cobertura MX fina: los medios deFUENTESno tienen cuenta oficial (solo periodistas individuales). Busque “contralinea”, “rompeviento”, etc. - Reddit (PRAW) — app gratuita, OAuth 100 qpm, r/mexico tiene volumen real de noticias MX y los COMENTARIOS son respuestas genuinas = el único corpus con reply-level sentiment accesible legalmente hoy.
- RSS de los propios medios — ya cubierto en feed.py, cero riesgo.
Stack recomendado (mínimo real)
- Recolección: función
obtener_bluesky(actor)+obtener_reddit(sub, q)en feed.py, mismo formato de item ({titulo, publicado, url, medio, tipo}). Sin cuenta propia = sin nada que bloquear. - Clasificador local:
pysentimiento/robertuito-sentiment-analysis(entrenado en tweets ES, corre en CPU; encaja local-first). - Agregación: columna sentimiento en los items del feed →
nlp.pypromedia por tema/día (ya tiene la machinery de emergentes). - Validación: buscar datasets ES anotados en HF con
api.list_datasets(search="sentiment spanish")— solo para calibrar el modelo, no como corpus vivo.
twikit (d60/twikit) — auditado mismo día
- Features que RSSHub no da: search por consulta, replies, métricas (likes/RTs).
- PERO: requiere login con credenciales (riesgo de baneo de cuenta; el repo trae ToProtectYourAccount.md). PyPI congelado en 2.3.3 (feb-2025), último commit real abr-2025. Issues 2026: KeyError post-abr-2026, SearchTimeline 404, 429 constantes, y X pidiendo palm-liveness scan al loguear (jul-2026).
- Veredicto: solo para deep-dive manual con cuenta desechable + cookies reutilizadas. Nunca en cron diario. El pipeline vive en Reddit/Bluesky/RSS.
twitterapi.io — PROBADO EN VIVO 2026-09-06 (key en .env.local)
Funciona y cuesta centavos. Recipes verificados:
GET /twitter/user/info?userName=X→ OK (perfiles vivos).GET /twitter/user/tweets?userName=X→ MUERTO: devuelve “User is suspended” hasta para elonmusk (pool de scrape quemado en ese endpoint). NO USAR.GET /twitter/tweet/advanced_search?query=from:handle&queryType=Latest→ OK: 20 tweets frescos con retweetCount/likeCount/viewCount/lang. El reemplazo directo de user/tweets. Soporta min_replies:, since_time:.GET /twitter/tweet/replies/v2?tweetId=X→ OK: replies reales con autor y likes (34 de 191 en la prueba). Esto es el corpus de sentiment.- Precio test completo (6 llamadas, ~100 tweets): $0.014.
- Plan de integración: en feed.py una obtener_x(handle) que use advanced_search from: y guarde JSON crudo en data/x/ (el dato pagado se persiste; si el proveedor muere, el corpus queda). Sentimiento: replies/v2 solo para tweets con replyCount>umbral. Docs: https://docs.twitterapi.io/llms.txt
SerpApi y Cloudflare Browser Run — veredicto 2026-09-06
- SerpApi: su motor Google-Twitter MURIÓ (Google mató la SERP de Twitter; serpapi.com/google-twitter-api → 404). Lo que queda (Google News/Bing, $75/5k búsquedas) es lo mismo que Google News RSS gratis — ya integrado en sentimiento.py como collect_gnews (45 titulares/3 temas, balance -0.53). Contratar SerpApi hoy = pagar por un RSS gratuito. No.
- Cloudflare Browser Run (ex Browser Rendering, renombre abr-2026): free 10 min browser/día; paid 10h + $0.09/h extra. NO sirve para X: muro de login para navegadores anónimos + AS13335 ya flaggeado; meter tus cookies de X ahí = el mismo riesgo con IP ajena. SÍ sirve como upgrade de /leer: quick action POST /markdown para páginas JS-pesadas (fuentes CN tech) donde trafilatura se queda corto. Token MCP actual sin scope browser-rendering.
- Corrida 2026-09-06 2a: 197 textos / 5 fuentes (gnews nuevo), misma firma negativa: Culiacán -0.56, judiciales -0.58, Sheinbaum -0.36.
Fuentes añadidas
- fast.ai (2026-09-06): feed real =
https://www.fast.ai/index.xml(RSS2; /feed.xml y /feeds.xml dan 404). Añadida a TECH_RSS en feed.py, categoria AI, en=True → entra al feed-tech y al hn-tech con traduccion automatica. Post frecuente para el boletin tech: “My friends all hate AI…” ago-2026.
Reddit MUERTO para devs pequeños (r/redditdev, verificado sep-2026)
- Responsible Builder Policy (nov-2025): prefs/apps redirige a la politica, Data Access Requests rechazadas con plantilla, clientes OAuth legados revocados, RSS a ~1 req/60s, .json 403. NO hay ruta self-serve — borrar de cualquier plan la idea de “crear la app”.
- Nuevas fuentes de RESPUESTAS ES verificadas hoy:
- Bluesky getPostThread — ANONIMO funciona (depth=2). Implementado como expandir_hilos_bluesky() en sentimiento.py (tope 8 hilos/corrida).
- YouTube via yt-dlp —write-comments — el default client sirve los comentarios (video Ayotzinapa: 14/14; player_client=tv NO). Filtro antispam (paypal/donaciones/urls-solamente). collect_yt + flag —yt. Es EL corpus ES de replies con volumen, sin cuenta, sin API key. Truco: videos muy nuevos = 0 comentarios; usar los de dias atras.
- HN Algolia (anonimo, con volumen) — solo util para lo TECH (EN) y robertuito no puntua EN; esperar a tener clasificador EN si acaso.
- sentimiento.py ahora reporta buckets separados: bluesky / bluesky (respuestas) / youtube / reddit / gnews / newsapi / mastodon / prensa. Los logs de Reddit dicen la verdad del cierre.
Pulso: X solo a peticion expresa 2026-09-06 (tarde)
pulso.pydefault = MODO SOCIAL (reddit+bluesky+newsapi via sentimiento.py; sin ninguna cuenta X).pulso.py --x= tuits feed.json + metricas twitterapi.io (~$0.01). Actualizar_hn.sh usa el default.- Bug cazado: generar_social no cargaba dotenv → NewsAPI se omitia en silencio (filas=1). Fix: load_dotenv al inicio. Leccion: los colectores deben loguear SIEMPRE su estado, no solo exititos.
- Nota: sin REDIT_CLIENT_ID, reddit .rss trae likes=0 → nunca rankea arriba; la app de reddit sigue siendo la mejora de mayor impacto pendiente.
Todo local 2026-09-06 (Gemini prepay agotado → ollama por default)
- proponer._llm_texto default LLM_BACKEND=ollama (gemma4 @ localhost:11434); REMOVIDO format:json de ese branch — era la CAUSA de las traducciones envueltas en {“translation”:…} (el modelo forzaba objeto JSON).
- nlp._traducir_terminos ya no usa genai directo: via proponer (40/40 EN traducidos local, nube OK).
- .env.local: LLM_BACKEND=ollama OLLAMA_MODEL=gemma4; portadas IMAGEN_PROVEEDOR=vertex + GCP_PROJECT (ADC vivo) — no verificado con imagen real, primera portada lo dirá.
- Vercel NO cambia: allá ya tienen LLM_BACKEND en su env de producción.
- Verificado: traducir 3 titulares ZH frescos → ES limpio sin chatarra.
Version completa 2026-09-06 (preview-edicion con todo)
pulso.py --htmlreusable + canonicareporte/pulso.json|html; paso 2.5 en scripts/actualizar_hn.sh (falla suave).- Preview: reporte/2026-09-06-preview.{json,html,md} = edicion aprobada 09-05
- seccion TECNOLOGIA·CHINA (2 QbitAI, Zhihu, TechNode, Phoronix; titulares chinos TRADUCIDOS, 0 CJK en los 4 renders) + bloque Pulso.
- Backend LLM: GEMINI_API_KEY agotada (429 prepay) — usar LLM_BACKEND=ollama (gemma4/qwen3.6). traduciones.py endurecido: prompt JSON, unwrap de claves arbitrarias ({“es”:…}), _chatarra() valida cache de lectura y escritura. El cache viejo puede traer porqueria: se ignora solo al leer.
Sección “Pulso en X” del boletín — implementada 2026-09-06
pulso.py: feed.json (posts X vía RSSHub, ventana 2d) → twitterapi.io /twitter/tweets (by_ids, 50/lote, 100% metrics) → robertuito → top 6 con techo de 2 por handle (sin techo: AJ inglés se comía el bloque) → reporte/pulso-YYYY-MM-DD.json.- Render email-safe reutilizado en 3 lados: reporte.py (web .html/.md) y mailing.py (_cuerpo_html + _cuerpo_texto). Se activa solo si la edición JSON tiene clave “pulso” — no rompe ediciones viejas.
- Flujos de producción:
python pulso.py --edicion reporte/FECHA.jsony luegopython reporte.py .../python mailing.py send .... Coste por edición: ~$0.01. Preview: reporte/preview-pulso.html. - Enfoque editorial “sin rostro”: el bloque declara método y muestra en el pie (“las etiquetas miden tono, no verdad”) + barra pos/neu/neg.
NewsAPI.org — integrado 2026-09-06 (key solo en .env.local, gitignored)
- Endpoint útil:
GET newsapi.org/v2/everything?q="tema"&language=es(la zona “developer.newsapi.org” NO existe — NXDOMAIN; api.newsapi.org con query param apiKey funciona). top-headlines?country=mx = 0 resultados. - Free dev: 100 req/día — el collector usa 1 por tema. Sin comillas en q
mezcla basura turca; con
q="exacto"+ language=es: La Jornada y prensa MX fresca. - Corrida con 7 fuentes: 305 textos. Culiacán -0.65 · Sheinbaum -0.40 · judiciales -0.59. newsapi coincide con gnews (cobertura más negativa que nuestros propios titulares, -0.13).
Primera corrida real 2026-09-06 (152 textos, 4 fuentes, $0)
| fuente | n | balance |
|---|---|---|
| mastodon (#hashtags anon) | 76 | -0.46 |
| prensa (titulos feed.json) | 60 | -0.13 |
| reddit (.rss, titulos) | 15 | -0.40 |
| bluesky (feed anon) | 1 | — |
| Temas: Culiacán -0.57 · elecciones judiciales -0.56 · Sheinbaum -0.30. | ||
| La prensa propia (neutra) vs la conversación social (negativa) ES el insight. |
- Anonimo disponible YA: mastodon.social + hachyderm.io /timelines/tag/ (el /timelines/public pide token desde 2024-25; el de tags NO).
- Reddit: hot.rss funciona pero inestable (200→vacio→403); PRAW con app es la version confiable y da COMENTARIOS (el sentiment bueno esta ahi).
- GDELT: rate-limit agresivo por IP, descartado por ahora.
- Pendiente humano (~10 min): Reddit app (prefs/apps) → REDDIT_CLIENT_ID/ SECRET; Talkwalker alertas → TALKWALKER_RSS; Bluesky opcional → BSKY_IDENTIFIER/BSKY_APP_PASSWORD (search sin cuenta esta 403 dura).
Implementado 2026-09-06 — sentimiento.py (sin tuits, por decisión)
sentimiento.py: Reddit + Bluesky + Talkwalker → robertuito. Corpus persistente en data/corpus/*.jsonl (merge por id al puntuar), resumen en reporte/sentimiento.json (balance por fuente/tema).- robertuito validado en CPU (arm64): NEG “mendigo traidor” 0.94, NEU nota climática 0.54, POS elogio 0.94.
- Bluesky: searchPosts ANONIMA fue CERRADA (403 con cualquier UA); getAuthorFeed sigue 200 anonimo. Con cuenta gratis + app password → BSKY_IDENTIFIER/BSKY_APP_PASSWORD habilita búsqueda por tema.
- Reddit .json sin OAuth: 403 Blocked. Falta que Inventiva cree la app (reddit.com/prefs/apps, “script”, 2 min) → REDDIT_CLIENT_ID/SECRET.
- Talkwalker: falta que Inventiva cree alertas (alerts.talkwalker.com, usa el correo del boletin) y pegue los RSS en TALKWALKER_RSS (.env.local, separados por coma). Queries sugeridas: “Sheinbaum”, “Culiacán seguridad”, “periodistas México agresión”.
- Cron sugerido:
python sentimiento.py --limite 251x/dia. Cuesta $0 y no toca ninguna identidad X.
Regla de oro
Si un método necesita la cuenta X de Inventiva corriendo un loop, no es para el pipeline diario. RSSHub actual queda solo para display (volumen bajo, fallback a RSS del medio ya existe).