Twitter/X Scraping for R via Python’s twscrape
twscrape sin instalar software automáticamentetwscrape: Usa la librería
Python twscrape desde R mediante
reticulatetwscrape# Instalar desde GitHub
library(devtools)
install_github("agusnieto77/twscrapeR")Requisito importante del entorno Python: usá
twscrape >= 0.18.0 con Python >= 3.10. La versión
twscrape 0.17.0 quedó rota para SearchTimeline
después de cambios en X/Twitter y puede fallar con
IndexError: list index out of range. Desde
twscrape 0.18.0, el fix viene upstream y
twscrapeR ya no necesita aplicar un monkeypatch local.
Instalá o actualizá twscrape fuera de las funciones del
paquete, por ejemplo en una terminal:
python -m pip install "twscrape>=0.18.0"library(twscrapeR)
# Configuración guiada (solo verifica el entorno; no instala software)
setup_twscraper()La función setup_twscraper() te guiará a través de: 1.
Detección de Python >= 3.10 2. Verificación de la librería Python
twscrape 3. Configuración del entorno
Si no tenés Python o twscrape
instalado, setup_twscraper() mostrará
instrucciones para instalarlo manualmente fuera de R.
Opción recomendada: guardá tus credenciales en .Renviron
y agregá la cuenta sin escribir secretos en el script.
# En .Renviron
TWS_USERNAME='tu_usuario'
TWS_PASSWORD='tu_password'
TWS_EMAIL='tu@email.com'
TWS_EMAIL_PASSWORD='email_pass'
# Opción A: cookie completa
TWS_COOKIES='auth_token=valor_auth_token; ct0=valor_ct0'
# Opción B: valores separados; add_account_from_env() arma la cookie
TWS_AUTH_TOKEN='valor_auth_token'
TWS_CT0='valor_ct0'
# En R
add_account_from_env()Para varias cuentas podés repetir el esquema con otro prefijo y
pasarlo a la función, por ejemplo TWS2_USERNAME,
TWS2_PASSWORD, TWS2_COOKIES, etc. y luego
add_account_from_env(prefix = "TWS2_").
También podés pasar todo explícitamente:
add_account(
username = "tu_usuario",
password = "tu_password",
email = "tu@email.com",
email_password = "email_pass",
cookies = "auth_token=...; ct0=..."
)Nota IMPORTANTE: Las cookies son
OBLIGATORIAS para que la cuenta se active
correctamente. Podés pasarlas como TWS_COOKIES o como
TWS_AUTH_TOKEN + TWS_CT0.
auth_token y ct0"auth_token=valor1; ct0=valor2"# Buscar tweets
tweets <- search_tweets("rstats", n = 100)
# Por defecto busca Latest; para tweets destacados/populares usá Top
top_tweets <- search_tweets("rstats", n = 100, product = "Top")
# Convertir a dataframe
df <- to_dataframe(tweets)
View(df)
# Guardar
save_csv(tweets, "tweets_rstats.csv")# Búsqueda general
tweets <- search_tweets("machine learning", n = 100)
# Latest es el valor por defecto; Top devuelve resultados destacados/populares
latest <- search_tweets("machine learning", n = 100, product = "Latest")
top <- search_tweets("machine learning", n = 100, product = "Top")
# Por hashtag
tweets <- search_hashtag("rstats", n = 50)
tweets <- search_hashtag("#datascience", n = 100) # Con o sin #
# Menciones de un usuario
mentions <- search_mentions("hadleywickham", n = 50)
# Búsquedas avanzadas
tweets <- search_tweets("rstats lang:en", n = 100) # Solo inglés
tweets <- search_tweets("from:hadleywickham", n = 50) # De un usuario específico# Obtener tweets de un usuario
tweets <- user_tweets("hadleywickham", n = 100)
# Ver información del usuario
user <- get_user("hadleywickham")
print(user)# Listar cuentas configuradas
list_accounts()
# Eliminar una cuenta
delete_account("usuario")# Convertir a dataframe
df <- to_dataframe(tweets)
# Guardar como CSV
save_csv(tweets, "tweets.csv")
# Guardar como JSON
save_json(tweets, "tweets.json")# Filtrar por idioma
tweets_es <- filter_by_lang(tweets, "es")
tweets_en <- filter_by_lang(tweets, "en")
# Filtrar por fecha
tweets_recent <- filter_by_date(tweets, from = "2025-10-01")
tweets_range <- filter_by_date(tweets, from = "2025-10-01", to = "2025-10-26")
# Ordenar por likes
top_tweets <- sort_tweets(tweets, by = "like_count")
# Ordenar por fecha (más recientes primero)
recent_first <- sort_tweets(tweets, by = "date", decreasing = TRUE)# Configuración inicial del sistema
setup_twscraper()
# Agregar cuenta - se activa automáticamente con cookies
add_account_from_env()
# O pasar los datos explícitamente
add_account(
username = "usuario",
password = "pass",
email = "email@example.com",
email_password = "email_pass",
cookies = "auth_token=...; ct0=..." # OBLIGATORIO
)
# Listar todas las cuentas configuradas (muestra estado activo/inactivo)
accounts <- list_accounts()
# Eliminar una cuenta
delete_account("usuario")
# Verificar configuración del sistema
check_setup()# Búsqueda general de tweets; product acepta "Latest" o "Top"
tweets <- search_tweets("machine learning", n = 100)
top_tweets <- search_tweets("machine learning", n = 100, product = "Top")
# Buscar por hashtag
tweets <- search_hashtag("rstats", n = 50)
tweets <- search_hashtag("#datascience", n = 100) # Con o sin #
# Buscar menciones a un usuario
mentions <- search_mentions("hadleywickham", n = 50)# Obtener tweets de un usuario
tweets <- user_tweets("rstudio", n = 100)
# Obtener tweets Y respuestas de un usuario
tweets_replies <- user_tweets_and_replies("hadleywickham", n = 100)
# Obtener solo tweets con media (imágenes/videos)
media_tweets <- user_media("NASA", n = 50)# Obtener información detallada de un usuario
user <- get_user("hadleywickham")
print(user$followers_count)
print(user$following_count)
print(user$description)# Obtener detalles completos de un tweet
tweet_id <- "1234567890123456789"
details <- tweet_details(tweet_id)
# Obtener respuestas a un tweet
replies <- tweet_replies(tweet_id, n = 50)
# Obtener quién retuiteó un tweet
retweeters <- get_retweeters(tweet_id, n = 100)
# Obtener retweeters para varios tweets
tweets <- search_tweets("rstats", n = 10)
retweeters <- get_retweeters_batch(tweets, n = 50)
retweeters_df <- to_dataframe(retweeters) # incluye source_tweet_id
# Si querés mantenerlos agrupados por tweet
retweeters_by_tweet <- get_retweeters_batch(tweets, n = 50, flatten = FALSE)# Obtener seguidores de un usuario
followers <- get_followers("rstudio", n = 100)
# Obtener a quién sigue un usuario
following <- get_following("hadleywickham", n = 100)
# Obtener solo seguidores verificados
verified <- verified_followers("elonmusk", n = 50)# Convertir tweets a dataframe
tweets <- search_tweets("rstats", n = 100)
df_tweets <- to_dataframe(tweets)
# También funciona con usuarios
followers <- get_followers("rstudio", n = 50)
df_users <- to_dataframe(followers)# Filtrar tweets por idioma
tweets_es <- filter_by_lang(tweets, "es")
tweets_en <- filter_by_lang(tweets, "en")
# Filtrar por fecha
tweets_recent <- filter_by_date(tweets, from = "2025-10-01")
tweets_range <- filter_by_date(
tweets,
from = "2025-10-01",
to = "2025-10-26"
)
# Ordenar tweets
top_tweets <- sort_tweets(tweets, by = "like_count")
recent_tweets <- sort_tweets(tweets, by = "date", decreasing = TRUE)# Guardar como CSV
save_csv(tweets, "tweets.csv")
# Guardar como JSON
save_json(tweets, "tweets.json")library(twscrapeR)
library(dplyr)
library(ggplot2)
# 1. Configurar
setup_twscraper()
add_account(...)
# 2. Buscar tweets
tweets <- search_tweets("#rstats", n = 1000)
# 3. Convertir a dataframe
df <- to_dataframe(tweets)
# 4. Análisis con dplyr
df %>%
filter(lang == "en") %>%
arrange(desc(like_count)) %>%
select(username, text, like_count, retweet_count) %>%
head(10)
# 5. Visualización
df %>%
count(date = as.Date(date)) %>%
ggplot(aes(date, n)) +
geom_line() +
labs(title = "Tweets sobre #rstats por día",
x = "Fecha", y = "Número de tweets")
# 6. Top usuarios
df %>%
count(username, sort = TRUE) %>%
head(10) %>%
ggplot(aes(reorder(username, n), n)) +
geom_col() +
coord_flip() +
labs(title = "Top 10 usuarios", x = "", y = "Tweets")Si setup_twscraper() no encuentra Python:
# Especificar ruta a Python ya instalado
setup_twscraper(python_path = "C:/Python/python.exe")Instalá Python 3.10+ manualmente desde https://www.python.org/downloads/ o con tu gestor de
entornos preferido. Después instalá twscrape en ese entorno
y ejecutá setup_twscraper() nuevamente.
# Verificar si todo está correcto
check_setup()
# Ver configuración de Python
reticulate::py_config()Si una cuenta aparece como active = FALSE:
# 1. Listar cuentas para ver el estado
list_accounts()
# 2. Eliminar la cuenta inactiva
delete_account("usuario")
# 3. Volver a agregarla CON cookies válidas y actuales
add_account(
username = "usuario",
password = "pass",
email = "email@example.com",
email_password = "email_pass",
cookies = "auth_token=...; ct0=..." # OBLIGATORIO
)Importante: - Las cookies son OBLIGATORIAS para activar cuentas - Si una cuenta no se activa, las cookies están expiradas o son inválidas - Obtén nuevas cookies desde tu navegador (ver sección “¿Cómo obtener cookies?”)
Twitter/X aplica límites por tipo de consulta y twscrape
los administra por cola. Si ves un mensaje como este:
No account available for queue "Followers". Next available at 20:25:08
significa que todas las cuentas disponibles para esa cola llegaron temporalmente a su límite. No es un error de R: hay que esperar o distribuir mejor la carga.
Qué hacer:
n: empezá con valores chicos
(n = 50 o n = 100) y subí de a poco.twscrape
rota automáticamente entre cuentas activas.list_accounts() y confirmá que aparezcan como
active = TRUE.Ejemplo con varias cuentas:
add_account("usuario1", "pass1", "email1@example.com", "email_pass1", "auth_token=...; ct0=...")
add_account("usuario2", "pass2", "email2@example.com", "email_pass2", "auth_token=...; ct0=...")
list_accounts()No hay un número universal que evite siempre el bloqueo: depende de
la cola (Search, Followers,
UserTweets, etc.), de la edad/estado de las cuentas y de la
carga reciente. La regla práctica es pedir lotes más chicos y dejar que
la rotación haga su trabajo.
IndexError: list index out of range en twscrapeX/Twitter cambia con frecuencia sus bundles web. En
twscrape 0.17.0 eso puede romper el cálculo interno de
x-client-transaction-id y bloquear consultas reales aunque
la cuenta figure activa.
La solución actual es usar twscrape >= 0.18.0, donde
el arreglo ya viene incluido upstream. twscrapeR no aplica
un monkeypatch local para este caso.
python -m pip install "twscrape>=0.18.0"setup_twscraper()Después de actualizar, una prueba corta como
search_tweets("Milei", n = 5) debería funcionar si la
cuenta y las cookies están activas.
tweet <- tweets[[1]]
str(tweet)Campos disponibles: - id: ID del tweet -
date: Fecha y hora (POSIXct) - text: Texto
completo del tweet - username: Usuario que publicó -
user_displayname: Nombre mostrado del usuario -
user_id: ID del usuario - reply_count: Número
de respuestas - retweet_count: Número de retweets -
like_count: Número de likes - quote_count:
Número de quote tweets - views_count: Número de vistas -
lang: Idioma del tweet - url: URL del tweet -
user_followers: Seguidores del usuario -
user_verified: Usuario verificado (TRUE/FALSE)
user <- get_user("username")
str(user)Campos: - id: ID del usuario - username:
@usuario -
displayname: Nombre mostrado - description:
Biografía - followers_count: Seguidores -
following_count: Siguiendo - tweets_count:
Total de tweets - verified: Cuenta verificada -
created: Fecha de creación - location:
Ubicación - url: URL del perfil -
profile_image_url: URL de la foto de perfil
Las contribuciones son bienvenidas! Por favor:
git checkout -b feature/AmazingFeature)git commit -m 'Add some AmazingFeature')git push origin feature/AmazingFeature)MIT License - ver archivo LICENSE
twscrapeR es posible gracias a dos proyectos excepcionales de Python:
snscrape por JustAnotherArchivist: Arquitectura base de scraping, parsers y modelos de datos.
twscrape por vladkens: Sistema multi-cuenta, rate limiting y generación de X-Client-Transaction-ID.
Y al ecosistema de R:
Este paquete es para propósitos educativos y de investigación. Asegúrate de cumplir con los términos de servicio de Twitter/X al usarlo.