Twitter/X Scraping for R via Python's twscrape
- Características
- Instalación
- Inicio Rápido
- Funciones Principales
- Referencia Completa de Funciones ⭐ 26 funciones
- Análisis de Datos
- Solución de Problemas
- Estructura de Datos
- Agradecimientos
- Licencia
- ✅ Configuración Guiada: Verifica Python y
twscrapesin instalar software automáticamente - ✅ Basado en
twscrape: Usa la librería Pythontwscrapedesde R mediantereticulate - ✅ Interfaz R Nativa: Parece R puro, no necesitas saber Python
- ✅ Multi-cuenta: Soporta múltiples cuentas con rate limiting automático
- ✅ 26 Funciones: Funcionalidad completa y simplificada para scraping de Twitter/X
- ✅ Análisis de Redes: Followers, following, retweeters, verified followers
- ✅ Análisis de Conversaciones: Tweet details, replies, menciones
- ✅ Conversión Fácil: to_dataframe() convierte tweets y usuarios a dataframes para análisis en R
- ✅ Sin HTTP propio en R: delega scraping, rate limiting y colas a
twscrape
# 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:
- Detección de Python >= 3.10
- Verificación de la librería Python
twscrape - 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.
- Abre https://x.com en tu navegador (con sesión iniciada)
- Presiona F12 → "Application" → "Cookies" → "https://x.com"
- Copia los valores de
auth_tokenyct0 - Formato:
"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:
- Bajá
n: empezá con valores chicos (n = 50on = 100) y subí de a poco. - Agregá más cuentas válidas:
twscraperota automáticamente entre cuentas activas. - Verificá tus cuentas: usá
list_accounts()y confirmá que aparezcan comoactive = TRUE. - Esperá el reset: el propio mensaje indica cuándo vuelve a estar disponible la cola.
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.
X/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 tweetdate: Fecha y hora (POSIXct)text: Texto completo del tweetusername: Usuario que publicóuser_displayname: Nombre mostrado del usuariouser_id: ID del usuarioreply_count: Número de respuestasretweet_count: Número de retweetslike_count: Número de likesquote_count: Número de quote tweetsviews_count: Número de vistaslang: Idioma del tweeturl: URL del tweetuser_followers: Seguidores del usuariouser_verified: Usuario verificado (TRUE/FALSE)
user <- get_user("username")
str(user)Campos:
id: ID del usuariousername: @usuariodisplayname: Nombre mostradodescription: Biografíafollowers_count: Seguidoresfollowing_count: Siguiendotweets_count: Total de tweetsverified: Cuenta verificadacreated: Fecha de creaciónlocation: Ubicaciónurl: URL del perfilprofile_image_url: URL de la foto de perfil
Las contribuciones son bienvenidas! Por favor:
- Fork el repositorio
- Crea una rama para tu feature (
git checkout -b feature/AmazingFeature) - Commit tus cambios (
git commit -m 'Add some AmazingFeature') - Push a la rama (
git push origin feature/AmazingFeature) - Abre un Pull Request
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:
- reticulate: Integración perfecta entre R y Python
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.