메인 콘텐츠로 건너뛰기
Powerstream은 공개 X 데이터에 액세스할 수 있는 가장 빠른 실시간 스트리밍 API입니다. 레거시 GNIP Powetrack API와 유사하게, 키워드, 연산자, 메타데이터를 기반으로 포스트를 필터링하기 위해 규칙을 사용합니다. Powerstream 엔드포인트에 지속적인 HTTP 연결이 맺어지면, 거의 실시간에 가깝게 일치하는 포스트를 수신할 수 있습니다. 현재 Powerstream은 최대 1,000개의 규칙을 지원하며, 각 규칙의 길이는 최대 2048자입니다.

주요 기능:

  • 실시간 데이터 제공: 규칙과 일치하는 데이터를 거의 실시간으로 받아볼 수 있습니다.
  • 정밀한 필터링: 연산자가 포함된 Boolean 쿼리를 사용해 원하는 데이터만 정확하게 필터링합니다.
  • 전송 방식: HTTP/1.1 청크 전송 인코딩을 통한 JSON 응답.
  • 로컬 데이터 센터 지원: 복제 지연을 피해 지연 시간을 줄이기 위해 로컬 데이터 센터의 포스트만 가져옵니다.
Powerstream API는 일부 Enterprise 플랜에서 제공되는 프리미엄 서비스입니다.Powerstream 사용을 원하시거나 Enterprise 서비스에 대해 더 알고 싶으시다면, Enterprise Request Form을 제출해 영업 팀에 문의해 주세요. Powerstream이 귀사의 요구사항을 어떻게 지원할 수 있는지 논의해 보겠습니다.

빠른 시작

이 섹션에서는 Python과 requests 라이브러리를 사용해 PowerStream 엔드포인트를 빠르게 사용하기 시작하는 방법을 보여줍니다. pip install requests로 설치하세요. 모든 예제는 OAuth 2.0 Bearer 토큰 인증을 사용합니다. YOUR_BEARER_TOKEN을 실제 토큰으로 바꾸고, os.getenv('BEARER_TOKEN')와 같이 안전한 방법으로 보관하세요. 각 엔드포인트를 코드 스니펫과 함께 다룹니다. 파일 상단에 다음 import 문이 있다고 가정합니다:
import requests
import json
import time
import sys
import os  # 환경 변수용

설정

bearer_token = os.getenv('BEARER_TOKEN') or "YOUR_BEARER_TOKEN"  # 보안을 위해 환경 변수 사용
base_url = "https://api.x.com/2/powerstream"
rules_url = f"{base_url}/rules"  # 규칙 관리용
headers = {
   "Authorization": f"Bearer {bearer_token}",
   "Content-Type": "application/json"
}

1. 규칙 생성 (POST /rules)

스트림을 필터링하는 규칙을 추가합니다.
data = {
   "rules": [
       {
           "value": "(cat OR dog) lang:en -is:retweet",
           "tag": "pet-monitor"
       },
       # 필요에 따라 규칙 추가 (최대 100개)
   ]
}

response = requests.post(rules_url, headers=headers, json=data)
if response.status_code == 201:
   rules_added = response.json().get("data", {}).get("rules", [])
   print("Rules added:")
   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. 규칙 삭제 (POST /rules)

ID(권장) 또는 값으로 규칙을 삭제합니다.
data = {
   "rules": [
       {
           "value": "(cat OR dog) lang:en -is:retweet",
           "tag": "pet-monitor"
       },
       # 필요에 따라 규칙 추가 (최대 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}")
: 모든 규칙을 삭제하려면, 먼저 GET으로 규칙을 조회한 뒤 ID를 추출하여 일괄 삭제하세요.

3. 규칙 조회 (GET /rules)

모든 활성 규칙을 조회합니다.
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)

실시간 포스트를 위해 스트림에 연결합니다. 줄 단위로 읽으려면 stream=True를 사용하세요. 안정성을 높이기 위해 재연결 로직을 구현하세요.
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
                       )
                   )

로컬 데이터센터 지원

지연 시간 최적화를 위해 Powerstream은 연결이 설정된 로컬 데이터센터에서 생성되었거나 발신된 포스트만 가져오는 옵션을 제공합니다. 이렇게 하면 복제 지연(replication lag)을 피할 수 있어, 다른 데이터센터에서 오는 포스트보다 더 빠르게 전달됩니다. 이를 활성화하려면 스트림 엔드포인트에 쿼리 매개변수 ?localDcOnly=true를 추가합니다(예: /2/powerstream?localDcOnly=true). 연결된 데이터센터 정보는 스트림의 초기 데이터 페이로드와 응답의 HTTP 헤더 모두에 표시됩니다. 코드에서 사용하려면:
# 로컬 데이터센터 전용:
stream_url = "https://api.x.com/2/powerstream?localDcOnly=true"
localDcOnly 매개변수가 활성화된 경우, 스트림이 처음 연결될 때 사용 중인 로컬 데이터센터를 나타내는 다음과 같은 응답 헤더가 포함됩니다:
'x-powerstream-datacenter': 'atla',
'x-powerstream-localdconly': 'true'
이와 함께 데이터센터를 지정하는 초기 페이로드도 전송합니다.
{
    "type": "connection_metadata",
    "datacenter": "atla",
    "timestamp": 1762557264155
}
팁: 지연 시간을 최적화하려면 서로 다른 지리적 위치(예: 미국 동부 해안의 애틀랜타 근처 하나, 미국 서부 해안의 포틀랜드 근처 하나)에서 연결을 설정하고 각 연결에 대해 localDcOnly=true를 설정하세요. 이렇게 하면 각 데이터센터에서 나오는 게시물에 더 빠르게 접근할 수 있습니다. 여러분 쪽에서 여러 스트림을 집계해 데이터센터 간 데이터를 통합하세요.

연산자

필터링 규칙을 설정할 때 키워드와 연산자를 함께 사용할 수 있습니다. 아래에서 사용 가능한 연산자 목록을 확인하세요.

필드 기반 연산자

사용자 연산자

연산자요약예시
from:특정 사용자가 작성한 포스트from:xdevelopers 또는 from:123456
to:특정 사용자에게 보낸 포스트to:jvaleski
retweets_of:특정 사용자의 리포스트retweets_of:xdevelopers

콘텐츠 연산자

OperatorSummaryExample
contains:특정 텍스트/키워드를 포함하는 포스트와 일치합니다contains:hello or contains:-2345.432
url_contains:URL에 특정 텍스트가 포함된 포스트와 일치합니다url_contains:"com/willplayforfood"
lang:특정 언어의 포스트와 일치합니다lang:en

엔터티 연산자

OperatorSummaryExample
has:특정 엔터티를 포함하는 게시물을 검색합니다 (옵션: mentions, geo, links, media, lang, symbols, images, videos)has:images, has:geo, has:mentions
is:특정 유형이거나 특정 속성을 가진 게시물을 검색합니다 (옵션: retweet, reply)is:retweet, is:reply

위치 연산자

OperatorSummaryExample
place:특정 장소/위치에서 작성된 포스트와 일치합니다place:"Belmont Central", place:02763fa2a7611cf3
bounding_box:지정한 지리적 경계 상자 내에서 작성된 포스트와 일치합니다bounding_box:[-112.424083 42.355283 -112.409111 42.792311]
point_radius:기준 지점으로부터 지정한 반경 내에서 작성된 포스트와 일치합니다point_radius:[-111.464973 46.371179 25mi], point_radius:[-111.464973 46.371179 15km]

고급/콘텐츠 연산자

OperatorSummaryExample
bio:특정 프로필 소개(bio) 내용을 가진 사용자가 작성한 포스트와 일치합니다 (구문 일치 사용)N/A
bio_name:프로필 소개(bio)에 특정 이름이 있는 사용자가 작성한 포스트와 일치합니다 (구문 일치 사용)N/A

추가 연산자

OperatorSummaryExample
retweets_of_status_id:특정 포스트의 리포스트를 검색retweets_of_status_id:1234567890123456789
in_reply_to_status_id:특정 포스트에 대한 답글을 검색in_reply_to_status_id:1234567890123456789

비필드 연산자

특수 구문 연산자

연산자요약예시
@멘션 연산자@username
구문 일치 (Phrase matching)정확히 일치하는 구문 검색"exact phrase"

논리 연산자

연산자요약예시
OR표현식 사이의 논리 OR 연산x OR facebook
Space/AND표현식 사이의 논리 AND 연산x facebook (두 용어가 모두 포함되어야 함)
()복잡한 표현식의 그룹화(x OR facebook) iphone
-부정/제외x -facebook (x는 포함하지만 facebook은 제외)

응답

Powerstream API의 페이로드는 레거시 GNIP PowerTrack API와 동일한 형식을 사용합니다. JSON 응답 예시는 다음과 같습니다:
[
   {
       "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"
   }
]

한도 및 모범 사례

  • 요청 한도: 규칙 관리에는 24시간 기준 50회 요청; 스트림에는 한도가 없지만 연결 한도는 적용됩니다.
  • 재연결: 연결이 끊어질 경우 지수 백오프를 사용합니다.
  • 모니터링: Connection: keep-alive 헤더를 사용합니다.