Saltar al contenido principal
Powerstream es nuestra API de streaming en tiempo real más rápida para acceder a datos públicos de X. Al igual que la API heredada GNIP Powetrack, utiliza reglas para filtrar Publicaciones según palabras clave, operadores y metadatos. Una vez que se establece una conexión HTTP persistente con el endpoint de Powerstream, puedes empezar a recibir Publicaciones que coincidan casi en tiempo real. Actualmente, Powerstream permite definir hasta 1.000 reglas y cada regla puede tener 2048 caracteres.

Características clave:

  • Entrega de datos en tiempo real: Obtén datos que cumplan tus reglas casi en tiempo real.
  • Filtrado preciso: Filtra exactamente los datos que estás buscando usando consultas booleanas con operadores.
  • Entrega: Respuesta JSON mediante HTTP/1.1 con codificación de transferencia fragmentada (chunked transfer encoding).
  • Compatibilidad con centros de datos locales: Obtén Publicaciones solo del centro de datos local para reducir la latencia al evitar el retardo de replicación.
La API de Powerstream es una oferta premium disponible en determinados planes Enterprise.Si estás interesado en acceder a Powerstream o en obtener más información sobre nuestras soluciones Enterprise, comunícate con nuestro equipo de ventas enviando el Formulario de solicitud Enterprise. Estaremos encantados de analizar cómo Powerstream puede satisfacer tus necesidades.

Inicio rápido

Esta sección muestra cómo comenzar rápidamente con los endpoints de PowerStream usando Python con la biblioteca requests. Instálala con pip install requests. Todos los ejemplos usan autenticación OAuth 2.0 con Bearer Token. Reemplaza YOUR_BEARER_TOKEN con tu token real (almacénalo de forma segura, por ejemplo, mediante os.getenv('BEARER_TOKEN')). Veremos cada endpoint con fragmentos de código. Supón que tienes estas importaciones al inicio:
import requests
import json
import time
import sys
import os  # Para vars de entorno

Configuración

bearer_token = os.getenv('BEARER_TOKEN') or "YOUR_BEARER_TOKEN"  # Usar variable de entorno por seguridad
base_url = "https://api.x.com/2/powerstream"
rules_url = f"{base_url}/rules"  # Para la gestión de reglas
headers = {
   "Authorization": f"Bearer {bearer_token}",
   "Content-Type": "application/json"
}

1. Crear reglas (POST /rules)

Añade reglas para filtrar tu stream.
data = {
   "rules": [
       {
           "value": "(cat OR dog) lang:en -is:retweet",
           "tag": "pet-monitor"
       },
       # Agrega más reglas según sea necesario (hasta 100)
   ]
}

response = requests.post(rules_url, headers=headers, json=data)
if response.status_code == 201:
   rules_added = response.json().get("data", {}).get("rules", [])
   print("Reglas agregadas:")
   for rule in rules_added:
       print(f"ID: {rule['id']}, Value: {rule['value']}, Tag: {rule.get('tag', 'N/A')}")
else:
   print(f"Error {response.status_code}: {response.text}")

2. Eliminar reglas (POST /rules)

Elimina reglas mediante id (recomendado) o por valor.
data = {
   "rules": [
       {
           "value": "(cat OR dog) lang:en -is:retweet",
           "tag": "pet-monitor"
       },
       # Agrega más reglas según sea necesario (hasta 100)
   ]
}

response = requests.delete(rules_url, headers=headers, json=data)
if response.status_code == 200:
   deleted = response.json().get("data", {})
   print(f"Deleted count: {deleted.get('deleted', 'N/A')}")
   if 'not_deleted' in deleted:
       print("Not deleted:", deleted['not_deleted'])
else:
   print(f"Error {response.status_code}: {response.text}")
Consejo: Para eliminar todas las reglas, primero obténlas con GET, extrae sus id y luego elimínalas en bloque.

3. Obtener reglas (GET /rules)

Obtén todas las reglas activas.
response = requests.get(rules_url, headers=headers)
if response.status_code == 200:
   rules = response.json().get("data", {}).get("rules", [])
   if rules:
       print("Active rules:")
       for rule in rules:
           print(f"ID: {rule['id']}, Value: {rule['value']}, Tag: {rule.get('tag', 'N/A')}")
   else:
       print("No active rules.")
else:
   print(f"Error {response.status_code}: {response.text}")

4. PowerStream (GET /stream)

Conéctate al stream para recibir Publicaciones en tiempo real. Usa stream=True para la lectura línea por línea. Implementa lógica de reconexión para mayor robustez.
stream_url = base_url

def main():
   while True:
       response = requests.request("GET", stream_url, headers=headers, stream=True)
       print(response.status_code)
       for response_line in response.iter_lines():
           if response_line:
               json_response = json.loads(response_line)
               print(json.dumps(json_response, indent=4, sort_keys=True))
               if response.status_code != 200:
                   print(response.headers)
                   raise Exception(
                       "Request returned an error: {} {}".format(
                           response.status_code, response.text
                       )
                   )

Compatibilidad con el centro de datos local

Para optimizar la latencia, Powerstream ofrece una opción para recuperar solo las Publicaciones que se originaron o se crearon en el centro de datos local donde se establece la conexión. Esto evita la latencia de replicación, lo que resulta en una entrega más rápida en comparación con las Publicaciones de otros centros de datos. Para habilitar esto, agrega el parámetro de consulta ?localDcOnly=true al endpoint del stream (por ejemplo, /2/powerstream?localDcOnly=true). El centro de datos al que estás conectado se indicará tanto en la carga inicial de datos del stream como en un encabezado HTTP en la respuesta. Para usarlo en código:
# Solo para el centro de datos local:
stream_url = "https://api.x.com/2/powerstream?localDcOnly=true"
Si el parámetro localDcOnly está activado, cuando el stream se conecte por primera vez incluirá las siguientes cabeceras de respuesta, que indican qué centro de datos local se está utilizando:
'x-powerstream-datacenter': 'atla',
'x-powerstream-localdconly': 'true'
Además, enviará una carga útil inicial que especifica el centro de datos:
{
    "type": "connection_metadata",
    "datacenter": "atla",
    "timestamp": 1762557264155
}
Consejo: Para optimizar la latencia, configura conexiones desde diferentes ubicaciones geográficas (por ejemplo, una cerca de Atlanta en la costa este de EE. UU. y otra cerca de Portland en la costa oeste de EE. UU.), habilitando localDcOnly=true para cada una. Esto proporciona acceso más rápido a las Publicaciones desde cada centro de datos correspondiente. Agrega los streams de tu lado para combinar los datos entre centros de datos.

Operadores

Para definir reglas de filtrado, puedes usar palabras clave y operadores. Consulta la lista de operadores disponibles a continuación.

Operadores por campo

Operadores de usuario

OperadorResumenEjemplo
from:Coincide con publicaciones de un usuario específicofrom:xdevelopers o from:123456
to:Coincide con publicaciones dirigidas a un usuario específicoto:jvaleski
retweets_of:Coincide con reposts de un usuario específicoretweets_of:xdevelopers

Operadores de contenido

OperadorDescripciónEjemplo
contains:Coincide con Publicaciones que contienen texto o palabras clave específicascontains:hello o contains:-2345.432
url_contains:Coincide con Publicaciones con URL que contienen texto específicourl_contains:"com/willplayforfood"
lang:Coincide con Publicaciones en idiomas específicoslang:en

Operadores de entidades

OperadorResumenEjemplo
has:Devuelve publicaciones que contienen entidades específicas (opciones: mentions, geo, links, media, lang, symbols, images, videos)has:images, has:geo, has:mentions
is:Devuelve publicaciones de tipos específicos o con propiedades específicas (opciones: retweet, reply)is:retweet, is:reply

Operadores de ubicación

OperadorDescripciónEjemplo
place:Coincide con publicaciones de lugares o ubicaciones específicosplace:"Belmont Central", place:02763fa2a7611cf3
bounding_box:Coincide con publicaciones dentro de un recuadro geográfico delimitadobounding_box:[-112.424083 42.355283 -112.409111 42.792311]
point_radius:Coincide con publicaciones dentro de un radio con centro en un puntopoint_radius:[-111.464973 46.371179 25mi], point_radius:[-111.464973 46.371179 15km]

Operadores avanzados/de contenido

OperatorSummaryExample
bio:Coincide con Publicaciones de usuarios cuyo perfil incluye un contenido de biografía específico (utiliza coincidencia de frases)N/D
bio_name:Coincide con Publicaciones de usuarios cuyo perfil incluye un nombre específico en la biografía (utiliza coincidencia de frases)N/D

Operadores adicionales

OperadorResumenEjemplo
retweets_of_status_id:Coincide con republicaciones de publicaciones específicasretweets_of_status_id:1234567890123456789
in_reply_to_status_id:Coincide con respuestas a publicaciones específicasin_reply_to_status_id:1234567890123456789

Operadores no basados en campos

Operadores de sintaxis especial

OperadorResumenEjemplo
@Operador de mención@username
Coincidencia de frasesCoincide con frases exactas"exact phrase"

Operadores lógicos

OperadorDescripciónEjemplo
OROR lógico entre expresionesx OR facebook
Espacio/ANDAND lógico entre expresionesx facebook (ambos términos deben estar presentes)
()Agrupación para expresiones complejas(x OR facebook) iphone
-Negación/exclusiónx -facebook (x pero no facebook)

Respuestas

La carga útil de la API Powestream tiene el mismo formato que la API PowerTrack heredada de GNIP. Un ejemplo de respuesta JSON es el siguiente:
[
   {
       "created_at": "Tue Mar 21 20:50:14 +0000 2006",
       "id": 20,
       "id_str": "20",
       "text": "just setting up my twttr",
       "truncated": false,
       "entities": {
           "hashtags": [],
           "symbols": [],
           "user_mentions": [],
           "urls": []
       },
       "source": "<a href=\"http://x.com\" rel=\"nofollow\">X Web Client</a>",
       "in_reply_to_status_id": null,
       "in_reply_to_status_id_str": null,
       "in_reply_to_user_id": null,
       "in_reply_to_user_id_str": null,
       "in_reply_to_screen_name": null,
       "user": {
           "id": 12,
           "id_str": "12",
           "name": "jack",
           "screen_name": "jack",
           "location": "",
           "description": "no state is the best state",
           "url": "https://t.co/ZEpOg6rn5L",
           "entities": {
               "url": {
                   "urls": [
                       {
                           "url": "https://t.co/ZEpOg6rn5L",
                           "expanded_url": "http://primal.net/jack",
                           "display_url": "primal.net/jack",
                           "indices": [
                               0,
                               23
                           ]
                       }
                   ]
               },
               "description": {
                   "urls": []
               }
           },
           "protected": false,
           "followers_count": 6427829,
           "friends_count": 3,
           "listed_count": 32968,
           "created_at": "Tue Mar 21 20:50:14 +0000 2006",
           "favourites_count": 36306,
           "utc_offset": null,
           "time_zone": null,
           "geo_enabled": true,
           "verified": false,
           "statuses_count": 30134,
           "lang": null,
           "contributors_enabled": false,
           "is_translator": false,
           "is_translation_enabled": false,
           "profile_background_color": "EBEBEB",
           "profile_background_image_url": "http://abs.twimg.com/images/themes/theme7/bg.gif",
           "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme7/bg.gif",
           "profile_background_tile": false,
           "profile_image_url": "http://pbs.twimg.com/profile_images/1661201415899951105/azNjKOSH_normal.jpg",
           "profile_image_url_https": "https://pbs.twimg.com/profile_images/1661201415899951105/azNjKOSH_normal.jpg",
           "profile_banner_url": "https://pbs.twimg.com/profile_banners/12/1742427520",
           "profile_link_color": "990000",
           "profile_sidebar_border_color": "DFDFDF",
           "profile_sidebar_fill_color": "F3F3F3",
           "profile_text_color": "333333",
           "profile_use_background_image": true,
           "has_extended_profile": true,
           "default_profile": false,
           "default_profile_image": false,
           "following": null,
           "follow_request_sent": null,
           "notifications": null,
           "translator_type": "regular",
           "withheld_in_countries": []
       },
       "geo": null,
       "coordinates": null,
       "place": null,
       "contributors": null,
       "is_quote_status": false,
       "retweet_count": 122086,
       "favorite_count": 263321,
       "favorited": false,
       "retweeted": false,
       "lang": "en"
   }
]

Límites y mejores prácticas

  • Límites de tasa: 50 solicitudes/24 h para la gestión de reglas; sin límite en streams (pero se aplican límites de conexión).
  • Reconexión: backoff exponencial en caso de desconexión.
  • Monitoreo: usa encabezados Connection: keep-alive.