Nach den drastischen Änderungen an der X/Twitter-API im Jahr 2023 stehen Entwicklungsteams vor einer schwierigen Entscheidung: die kostenpflichtigen API-Tiers bezahlen oder auf Web Scraping ausweichen. Für viele Anwendungsfälle – Social Listening, Sentiment-Analyse, Trend-Monitoring – ist Scraping die einzig praktikable Option geblieben. Dieser Leitfaden zeigt Ihnen, wie Sie öffentliche X-Daten mit Residential Proxys zuverlässig und ethisch korrekt extrahieren.
Die Post-API-Landschaft: Warum Scraping wieder relevant ist
Im Juli 2023 schaltete X die kostenlose API-Zugangsstufe ab. Die neuen Tier-Strukturen sehen wie folgt aus:
| Tier | Kosten/Monat | Post-Limit | Search-Access |
|---|---|---|---|
| Free | $0 | 1.500/Monat (nur Post) | Kein Zugriff |
| Basic | $100 | 3.000/Monat | 10.000/Monat |
| Pro | $5.000 | 50.000/Monat | 100.000/Monat |
| Enterprise | Individuell | Unbegrenzt | Vollzugriff |
Für Teams, die Tausende von Tweets pro Tag analysieren müssen, sind diese Limits prohibitiv. Eine Sentiment-Analyse über 50.000 Tweets würde allein $5.000/Monat kosten – für viele Startups und Agenturen nicht tragbar.
Wichtig: Web Scraping öffentlicher Daten verstößt nicht automatisch gegen Gesetze. Allerdings müssen Sie die Terms of Service jeder Plattform respektieren und sich der rechtlichen Grauzonen bewusst sein. Wir behandeln diese Aspekte ausführlich im Abschnitt Rechtliche Grundlagen.
Was ist ohne Login zugänglich – und was nicht
Die X-Web-Oberfläche unterscheidet strikt zwischen eingeloggten und nicht eingeloggten Sessions. Ohne Login sind folgende Daten öffentlich erreichbar:
Öffentlich zugänglich (kein Login erforderlich)
- Benutzerprofile: Name, Bio, Follower-Zahl, Verifizierungsstatus, Beitrittsdatum
- Einzelne Tweets: Textinhalt, Medien-Links, Engagement-Zahlen (Likes, Retweets, Replies)
- Tweet-Threads: Antworten und Konversationsverläufe
- Trending Topics: Aktuelle Trends nach Standort
- Suchergebnisse: Eingeschränkt – mit strengeren Rate Limits
Login-Walled (Authentifizierung erforderlich)
- Extended Search: Erweiterte Suchfilter (Datum, Engagement-Schwellenwerte)
- Complete Reply-Threads: Vollständige Konversationen mit allen Antworten
- Bookmarks und Lists: Benutzerdefinierte Sammlungen
- Private Accounts: Geschützte Tweets (ohne ausdrückliche Erlaubnis gar nicht zugänglich)
- Advanced Analytics: Detaillierte Engagement-Metriken
Für die meisten Monitoring-Anwendungsfälle – Markenüberwachung, Konkurrenzanalyse, Trend-Erkennung – reicht der öffentliche Zugriff aus. Das Problem: X erkennt und drosselt Scraping-Versuche aggressiv.
Warum Residential Proxys unverzichtbar sind
X/Twitter betreibt eines der anspruchsvollsten Anti-Bot-Systeme im Web. Drei Hauptgründe machen Residential Proxys zur Notwendigkeit:
1. Datacenter-IP-Blacklisting
X pflegt umfangreiche Blacklists für bekannte Datacenter-IP-Ranges. AWS, Google Cloud, DigitalOcean und andere große Provider werden systematisch gedrosselt oder komplett blockiert. Ein einfacher Test mit curl von einer Cloud-VM zeigt oft sofort einen 429-Status.
2. Striktere Limits für anonyme Sessions
Nicht eingeloggte Benutzer unterliegen deutlich strengeren Rate Limits. Während eingeloggte Nutzer Hunderte von Requests pro Minute ausführen können, werden anonyme Sessions nach etwa 50-100 Requests gedrosselt – und das bei weicher Erkennung.
3. Browser-Fingerprinting
X nutzt fortgeschrittenes Fingerprinting (Canvas, WebGL, Audio-Kontext, Font-Rendering). Kombiniert mit verdächtigen IP-Adressen löst selbst ein gut getarnter Browser oft Captcha-Challenges aus.
Residential Proxys lösen diese Probleme, indem sie Ihre Requests über echte Endverbraucher-IPs routen. X kann diese IPs nicht pauschal blockieren, ohne legitime Benutzer auszusperren.
Python + Playwright: Ein vollständiges Scraping-Setup
Die moderne X-Web-Oberfläche ist eine Single-Page-Application (SPA), die Daten über GraphQL-Endpoints lädt. Statische HTML-Parsing reicht nicht aus – Sie brauchen einen echten Browser oder tiefes Verständnis der internen API.
Methode 1: Playwright mit Residential Proxy
Dieser Ansatz rendert die Seite vollständig und extrahiert die JSON-Daten aus den Network-Responses:
import asyncio
from playwright.async_api import async_playwright
import json
class XScraper:
def __init__(self, proxy_url: str):
self.proxy_url = proxy_url
self.collected_data = []
async def scrape_profile(self, username: str):
async with async_playwright() as p:
# Browser mit Proxy starten
browser = await p.chromium.launch(
proxy={"server": self.proxy_url},
headless=True
)
context = await browser.new_context(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
)
page = await context.new_page()
# GraphQL-Responses abfangen
async def handle_response(response):
if "graphql" in response.url and "UserByScreenName" in response.url:
try:
data = await response.json()
self.collected_data.append(data)
except:
pass
page.on("response", handle_response)
# Profil aufrufen
await page.goto(f"https://x.com/{username}", wait_until="networkidle")
await asyncio.sleep(2) # Zusätzliche Wartezeit
await browser.close()
return self.collected_data
# ProxyHat Residential Proxy konfigurieren
proxy_url = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"
scraper = XScraper(proxy_url)
result = asyncio.run(scraper.scrape_profile("elonmusk"))
print(json.dumps(result, indent=2))
Methode 2: Direkte GraphQL-API-Nutzung
Für fortgeschrittene Entwickler ist der direkte Zugriff auf X's GraphQL-Endpoints effizienter – erfordert aber korrekte Headers und Authentifizierungs-Tokens:
import requests
import json
def scrape_tweets_graphql(query: str, proxy_url: str, cursor: str = None):
"""
Direkter Zugriff auf X's GraphQL Search-API.
Erfordert Guest-Token oder Bearer-Token.
"""
# Guest-Token anfordern (öffentlich verfügbar)
guest_token = get_guest_token(proxy_url)
headers = {
"authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LB81uq30A7Vg",
"x-guest-token": guest_token,
"x-twitter-active-user": "yes",
"content-type": "application/json",
}
# GraphQL-Variables
variables = {
"rawQuery": query,
"count": 20,
"querySource": "typed_query"
}
if cursor:
variables["cursor"] = cursor
params = {
"variables": json.dumps(variables),
"features": json.dumps({"rweb_tipjar_consumption_enabled": True})
}
proxies = {"http": proxy_url, "https": proxy_url}
response = requests.get(
"https://twitter.com/i/api/graphql/nK1dwP8XRVOAk4gS2qXjPA/SearchTimeline",
headers=headers,
params=params,
proxies=proxies
)
return response.json()
def get_guest_token(proxy_url: str) -> str:
"""Öffentlichen Guest-Token von X abrufen."""
proxies = {"http": proxy_url, "https": proxy_url}
response = requests.post(
"https://api.twitter.com/1.1/guest/activate.json",
headers={"authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LB81uq30A7Vg"},
proxies=proxies
)
return response.json()["guest_token"]
# Verwendung
proxy_url = "http://user-country-US:PASSWORD@gate.proxyhat.com:8080"
results = scrape_tweets_graphql("Python programming", proxy_url)
Node.js-Alternative mit Playwright
const { chromium } = require('playwright');
class XScraper {
constructor(proxyUrl) {
this.proxyUrl = proxyUrl;
this.tweets = [];
}
async scrapeTrending() {
const browser = await chromium.launch({
proxy: { server: this.proxyUrl },
headless: true
});
const context = await browser.newContext({
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
});
const page = await context.newPage();
// GraphQL-Responses abfangen
page.on('response', async (response) => {
if (response.url().includes('graphql') && response.url().includes('Trends')) {
try {
const data = await response.json();
this.tweets.push(data);
} catch (e) {}
}
});
await page.goto('https://x.com/explore', { waitUntil: 'networkidle' });
await page.waitForTimeout(3000);
await browser.close();
return this.tweets;
}
}
// ProxyHat Proxy mit Session-Stickiness
const proxyUrl = 'http://user-session-abc123:PASSWORD@gate.proxyhat.com:8080';
const scraper = new XScraper(proxyUrl);
scraper.scrapeTrending().then(console.log);
Rate Limits verstehen und überwinden
X verwendet ein mehrstufiges Rate-Limit-System, das verschiedene Dimensionen prüft:
Limit-Typen
| Limit-Typ | Scope | Typischer Threshold | Reset-Zeit |
|---|---|---|---|
| IP-Level | Pro IP-Adresse | ~100-500 Requests | 15-60 Minuten |
| Account-Level | Pro Benutzerkonto | ~300-2000 Requests | 15 Minuten |
| Endpoint-Level | Pro GraphQL-Query | Varriert | Sliding Window |
| Global | Plattformweit | Dynamisch | Unvorhersehbar |
Erkennung von Rate Limits
import time
import random
from collections import deque
class RateLimitHandler:
def __init__(self, requests_per_minute: int = 30):
self.rpm = requests_per_minute
self.request_times = deque(maxlen=100)
self.last_429_time = 0
def wait_if_needed(self):
"""Adaptives Warten basierend auf Request-History."""
now = time.time()
# Sliding Window prüfen
recent = [t for t in self.request_times if now - t < 60]
if len(recent) >= self.rpm:
sleep_time = 60 - (now - recent[0]) + random.uniform(1, 3)
time.sleep(sleep_time)
# Nach 429 länger warten
if self.last_429_time and now - self.last_429_time < 300:
time.sleep(random.uniform(30, 60))
self.request_times.append(now)
def handle_429(self, response):
"""429-Response behandeln und Backoff anwenden."""
if response.status_code == 429:
self.last_429_time = time.time()
reset_time = int(response.headers.get('x-rate-limit-reset', 900))
sleep_duration = min(reset_time, 300) + random.uniform(10, 30)
time.sleep(sleep_duration)
return True
return False
# Proxy-Rotation mit ProxyHat
class RotatingProxyScraper:
def __init__(self, base_username: str, password: str):
self.base_username = base_username
self.password = password
self.session_counter = 0
def get_proxy_url(self, country: str = "US") -> str:
"""Neue Session mit anderer IP generieren."""
self.session_counter += 1
session_id = f"sess{self.session_counter}"
username = f"{self.base_username}-country-{country}-session-{session_id}"
return f"http://{username}:{self.password}@gate.proxyhat.com:8080"
def rotate_on_429(self):
"""Bei 429 sofort IP wechseln."""
return self.get_proxy_url()
Best Practices für Rate-Limit-Management
- Exponential Backoff: Beginnen Sie mit 1 Sekunde Wartezeit und verdoppeln Sie bei jedem Fehler bis maximal 5 Minuten.
- Jitter hinzufügen: Zufällige Verzögerungen (±10-30%) verhindern, dass Ihre Requests vorhersehbar sind.
- Request-Batching: Sammeln Sie mehrere Datenanforderungen und führen Sie sie in kontrollierten Bursts aus.
- Proxy-Rotation: Wechseln Sie die IP-Adresse, bevor Limits greifen – nicht erst nach Fehlern.
- Response-Caching: Speichern Sie bereits abgerufene Daten, um redundante Requests zu vermeiden.
Rechtliche Grundlagen und ethische Erwägungen
Die rechtliche Lage von Social-Media-Scraping ist komplex und jurisdictionsabhängig. Hier ein Überblick über relevante Präzedenzfälle:
Wichtige Gerichtsentscheidungen
- hiQ Labs v. LinkedIn (USA, 2019/2022): Das 9th Circuit Court entschied, dass das Scrapen öffentlicher Daten nicht gegen den CFAA (Computer Fraud and Abuse Act) verstößt. Allerdings betonte das Gericht, dass Plattformen andere Rechtsmittel haben (Vertragsbruch, DMCA).
- X Corp. v. Bright Data (2024): X verklagte mehrere Scraping-Firmen. Die Fälle wurden teilweise zugunsten der Beklagten entschieden, da öffentliche Daten keinen Urheberschutz genießen.
- GDPR (EU): Personenbezogene Daten unterliegen DSGVO-Schutz. Scraping für kommermielle Zwecke ohne Einwilligung kann datenschutzrechtlich problematisch sein.
Terms of Service beachten
X's Terms of Service verbieten ausdrücklich:
- Automatisierten Zugriff ohne ausdrückliche Erlaubnis
- Das Sammeln von Daten für Wettbewerbszwecke
- Das Weiterverkaufen von Daten an Dritte
- Das Umgehen technischer Schutzmaßnahmen
Haftungsausschluss: Dieser Artikel dient ausschließlich Bildungszwecken. Die Autoren und ProxyHat befürworten keine illegalen Aktivitäten. Prüfen Sie vor jedem Scraping-Projekt die geltenden Gesetze und Terms of Service. Konsultieren Sie bei Unsicherheit einen Rechtsanwalt.
Wann die API die bessere Wahl ist
| Anwendungsfall | Scraping | API |
|---|---|---|
| Einmalige Datenextraktion | ✓ Geeignet | ✓ Geeignet |
| Kontinuierliches Monitoring | ⚠ Risiko | ✓ Empfohlen |
| Kommerzielle Datenweitergabe | ✗ Verboten | ✓ Mit Lizenz |
| Historische Analysen | ⚠ Begrenzt | ✓ Enterprise-API |
| Real-Time-Streaming | ✗ Unzuverlässig | ✓ Enterprise-API |
Best Practices für nachhaltiges Scraping
Robots.txt respektieren
Obwohl X's robots.txt Scraping nicht explizit verbietet, sollten Sie die angegebenen Rate-Limits beachten:
# Prüfen Sie robots.txt vor dem Scraping
import requests
from urllib.robotparser import RobotFileParser
rp = RobotFileParser()
rp.set_url("https://x.com/robots.txt")
rp.read()
# Prüfen, ob Ihr User-Agent erlaubt ist
can_scrape = rp.can_fetch("MyBot/1.0", "https://x.com/elonmusk")
Ethical Scraping Principles
- Minimierung: Sammeln Sie nur die Daten, die Sie tatsächlich benötigen.
- Anonymisierung: Entfernen Sie personenbezogene Daten, wo möglich.
- Transparenz: Identifizieren Sie Ihren Bot im User-Agent.
- Last-Balancing: Verteilen Sie Requests über verschiedene Tageszeiten.
- Offizielle APIs bevorzugen: Wenn verfügbar und erschwinglich.
Key Takeaways
- API-Einschränkungen machen Scraping relevant: Die kostenlosen Twitter-API-Tiers wurden abgeschafft – für viele Teams ist Web Scraping die einzige praktikable Alternative.
- Residential Proxys sind essenziell: X blockiert Datacenter-IPs aggressiv; Residential Proxys bieten die nötige Legitimität.
- GraphQL verstehen: Die X-SPA nutzt interne GraphQL-Endpoints – statisches HTML-Parsing reicht nicht aus.
- Rate-Limit-Management: Sliding-Window-Detection, Exponential Backoff und Proxy-Rotation verhindern 429-Blocks.
- Rechtliche Compliance: Öffentliche Daten zu scrapen ist in vielen Jurisdiktionen legal, aber Terms of Service können zivilrechtliche Konsequenzen haben.
- API wenn möglich: Für kommerzielle, kontinuierliche oder real-time-Anwendungen ist die offizielle API oft die sicherere Wahl.
Fazit und nächste Schritte
Das Scrapen öffentlicher Twitter/X-Daten bleibt technisch machbar, erfordert aber sorgfältige Planung und die richtige Infrastruktur. Residential Proxys wie die von ProxyHat bieten die notwendige IP-Diversität, um Anti-Bot-Systeme zu umgehen, während verantwortungsvolle Rate-Limit-Strategien langfristige Stabilität gewährleisten.
Für Ihre nächsten Schritte:
- Definieren Sie Ihren Datenbedarf: Welche Profile, Tweets oder Trends benötigen Sie tatsächlich?
- Wählen Sie die richtige Methode: Playwright für komplexe Seiten, GraphQL für Effizienz.
- Konfigurieren Sie Ihre Proxys: Nutzen Sie ProxyHat's Residential-Pools mit Geo-Targeting für optimale Ergebnisse.
- Implementieren Sie Rate-Limit-Handling: Exponential Backoff und Proxy-Rotation sind Pflicht.
- Dokumentieren Sie Ihre Compliance: Halten Sie Ihre Datenschutzerklärungen und ToS-Prüfungen aktuell.
Weitere Ressourcen finden Sie in unseren Leitfäden zu Web Scraping Best Practices und SERP-Tracking.






