Visión general
TweetScraperR recolecta datos de X/Twitter —tweets, usuarixs y metadatos— para análisis y visualización en R, sin usar la API oficial de pago. Desde la versión 0.4.0, el scraping corre sobre un motor de Node.js + Playwright y consulta la API GraphQL interna de X, devolviendo datos estructurados desde JSON: texto completo (sin truncar), fecha exacta, métricas (respuestas, retweets, citas, me gusta, vistas), media, hashtags y menciones. La autenticación se hace importando la sesión real de tu navegador (cookies), ya que X bloquea el login automatizado. Es una alternativa flexible, gratuita y de código abierto.
TweetScraperR collects data from X/Twitter —tweets, users and metadata— for analysis and visualization in R, without using the paid official API. Since version 0.4.0, scraping runs on a Node.js + Playwright engine and queries X’s internal GraphQL API, returning structured data from JSON: full text, exact date, metrics, media, hashtags and mentions. Authentication works by importing your real browser session (cookies), since X blocks automated login. It is a flexible, free, and open-source alternative.
Instalacion de la version en desarrollo
Puedes instalar la versión de desarrollo de TweetScraperR desde GitHub con:
# install.packages("devtools")
devtools::install_github("agusnieto77/TweetScraperR")Requisitos
-
Node.js (>= 18): el motor de scraping está basado en Node.js + Playwright + stealth. Se instala una sola vez con
installPlaywrightEngine()(ver más abajo). - Chrome o Chromium: navegador basado en Chromium requerido por el motor de Playwright.
- Cuenta de X/Twitter: necesaria para las funciones que requieren autenticación.
-
Variables de entorno:
-
OPENAI_API_KEY: opcional, solo para las funciones de análisis (getTweetsSentiments()ygetTweetsImagesAnalysis()). -
XQUIK_API_KEY: opcional, solo paragetTweetsXquikSearch().
-
Nota: las variables
TWITTER_USER/TWITTER_PASS(y su fallback legacyUSER/PASS) y el login automatizado quedaron deprecados: X bloquea el login por automatización. La autenticación ahora se realiza importando la sesión real del navegador conimportSessionX()(ver la sección Autenticación).
Más detalles en Requisitos.md.
Instalación del motor
El scraping ya no usa chromote: corre sobre un motor de Node.js + Playwright + stealth.
- Necesitás Node.js (>= 18) instalado en tu sistema.
- Una sola vez, después de instalar el paquete, ejecutá:
library(TweetScraperR)
# Instala el motor de Node.js/Playwright (una sola vez)
installPlaywrightEngine()
# Verifica que el motor esté instalado y operativo
checkPlaywrightEngine()Autenticación
X bloquea el login automatizado, por lo que ya no es viable iniciar sesión desde R con usuario y contraseña. En su lugar, se importa la sesión real de tu navegador y se reutiliza para todas las funciones de scraping. El flujo es:
- Logueate a mano en X/Twitter desde tu navegador normal (por ejemplo, Chrome).
-
Copiá las cookies
auth_tokenyct0del dominiox.com. Abrí las herramientas de desarrollo (DevTools,F12) → pestaña Application (o Storage) → Cookies →https://x.com, y copiá los valores deauth_tokenyct0. -
Importá la sesión en R con
importSessionX():
library(TweetScraperR)
importSessionX(
auth_token = "TU_AUTH_TOKEN",
ct0 = "TU_CT0"
)A partir de ese momento, todas las funciones de scraping reutilizan esa sesión (persistida como storageState) sin necesidad de volver a loguearte.
Las cookies expiran. Cuando la sesión deje de funcionar, volvé a copiar
auth_tokenyct0desde el navegador y reimportalas conimportSessionX().
Scraping vía API GraphQL/JSON (recomendado)
La vía recomendada es la familia de funciones *API(): consultan la API GraphQL interna de X y devuelven datos estructurados directamente del JSON (texto completo sin truncar, fecha exacta y métricas: respuestas, retweets, citas, me gusta y vistas), sin selectores CSS frágiles. Todas reusan la sesión importada con importSessionX(). Las funciones de scraping por HTML siguen disponibles pero quedaron deprecadas en favor de estas.
| Función | Qué recupera |
|---|---|
getUserTweetsAPI() |
Timeline de unx usuarix |
getTweetsTimelinesAPI() |
Timeline combinado de varias cuentas |
getTweetsSearchAPI() |
Búsqueda (product = "Latest"/"Top"/"Media") |
getTweetsRepliesAPI() |
Tweet y sus respuestas (hilo) |
getTweetsDataAPI() |
Datos de tweets a partir de sus URLs |
getUserMediaAPI() |
Tweets con media (fotos/videos) de unx usuarix |
getTweetsRetweetsAPI() |
Usuarixs que repostearon un tweet |
getUserFollowersAPI() |
Seguidorxs de unx usuarix |
getUserFollowingAPI() |
Cuentas que sigue unx usuarix |
getUsersDataAPI() |
Datos de perfil de usuarixs |
Las funciones de tweets devuelven un tibble rico: texto completo, fecha, idioma, métricas (respuestas/retweets/citas/me gusta/vistas), y list-columns media, hashtags, menciones, urls_externas y emoticones — listo para analizar con plotTime(), plotWords(), plotEmojis() o getTweetsSentiments().
library(TweetScraperR)
importSessionX(auth_token = "tu_auth_token", ct0 = "tu_ct0")
tw <- getTweetsSearchAPI("#RStats", n_tweets = 100, product = "Latest")Uso responsable / Aviso legal
- El scraping autenticado de X/Twitter puede violar sus Términos de Servicio y derivar en la suspensión de la cuenta utilizada. Usalo bajo tu propia responsabilidad.
- El contenido recolectado está sujeto a los derechos de X/Twitter y de lxs autorxs de los tweets; su almacenamiento y redistribución pueden estar limitados por esos derechos y por la normativa de protección de datos aplicable.
-
getTweetsSentiments()ygetTweetsImagesAnalysis()envían los datos recolectados (textos e imágenes de terceros) a la API de OpenAI. - Se recomienda usar una cuenta dedicada de investigación (no tu cuenta personal) y respetar los marcos éticos de investigación de tu institución.
Funciones
El listado completo de funciones, organizado por categoría y con su estado de ciclo de vida, está en la referencia del sitio de documentación:
👉 https://agusnieto77.github.io/TweetScraperR/reference/
Las recomendadas son la familia *API() (ver la tabla de arriba). Las funciones de scraping por HTML (getTweetsTimeline(), getTweetsHistoricalSearch(), getTweetsData(), getUsersData(), la familia getUrls*(), las variantes *For(), etc.) quedaron deprecadas en favor de sus equivalentes *API(); siguen funcionando con una advertencia de ciclo de vida.
Uso del paquete
require(TweetScraperR)
# 1) Importás tu sesión UNA vez (cookies auth_token y ct0 del navegador)
importSessionX(auth_token = "TU_AUTH_TOKEN", ct0 = "TU_CT0")
# 2) Búsqueda: tweets recientes que mencionan un hashtag
tweets <- getTweetsSearchAPI("#RStats", n_tweets = 100, product = "Latest")
# 3) Timeline de una cuenta
timeline <- getUserTweetsAPI("rstatstweet", n_tweets = 200)
# 4) Timeline COMBINADO de varias cuentas (curaduría de investigación)
combinado <- getTweetsTimelinesAPI(
c("elravignani", "NucleoIdaes", "BNMMArgentina"),
n_tweets = 100
)
# 5) Datos de perfil de usuarixs
perfiles <- getUsersDataAPI(c("NASA", "rstatstweet"))Cada función de tweets devuelve un tibble con datos estructurados (21 columnas), listo para analizar:
dplyr::glimpse(tweets)
#> Rows: 100
#> Columns: 21
#> $ fecha <dttm> 2026-06-13 21:42:13, 2026-06-13 12:10:47, ...
#> $ user <chr> "@RosanaFerrero", "@aRtsy_package", ...
#> $ texto <chr> "...texto completo, sin truncar..."
#> $ idioma <chr> "es", "en", ...
#> $ megustas <int> 7203, 0, 8221, ...
#> $ retweets <int> 1194, 323, 1465, ...
#> $ views <int> 470857, 34, 378665, ...
#> $ media <list> ["https://pbs.twimg.com/media/...jpg"], [], ...
#> $ hashtags <list> ["RStats"], [], ...
#> $ menciones <list> ["Space_Station", "SpaceX"], [], ...
#> $ urls_externas <list> ["https://go.nasa.gov/..."], [], ...
#> $ emoticones <list> ["✈"], [], ...
#> # ... respuestas, citas, es_retweet, es_cita, tweet_citado_id,
#> # media_tipo, conversation_id, url, tweet_idY analizás/visualizás directo, sin renombrar columnas:
plotTime(tweets) # serie temporal (columna fecha)
plotWords(tweets) # nube de palabras (columna texto)
plotEmojis(tweets) # ranking de emojis (columna emoticones)
getTweetsSentiments(tweets$texto) # análisis de sentimiento (vía OpenAI)