Sportstatistikportale schützen Spielerdatenbanken, Spielprotokolle und historische Aufzeichnungen mit Cloudflare Turnstile und reCAPTCHA. CAPTCHAs werden bei schnellen Abfragen über mehrere Spieler, Saisons oder Spiele hinweg ausgelöst – insbesondere auf Websites, die ihre Daten hinter Paywalls monetarisieren. So sammeln Sie Sportdaten zuverlässig.
CAPTCHA-Muster auf Sportportalen
Datentyp
Portaltyp
CAPTCHA
Auslöser
Spielerstatistiken
Referenzseiten
Cloudflare Turnstile
Schnelles Laden der Spielerseite
Spielbox-Ergebnisse
Punkteportale
Cloudflare Challenge
Massensuche nach Spielen
Saisonstand
Ligaseiten
reCAPTCHA v2
Automatisierte Navigation
Fantasieprojektionen
Fantasy-Plattformen
reCAPTCHA v3
Häufiger API-ähnlicher Zugriff
Wettquoten/lines
Quotenportale
Cloudflare Turnstile
Hochfrequenzaktualisierungen
Historische Aufzeichnungen
Archivseiten
Bild-CAPTCHA
Anfragen zum Datenexport
Sportdatensammler
import requests
import time
import re
from dataclasses import dataclass, field
@dataclass
class PlayerStats:
name: str
team: str
position: str
stats: dict = field(default_factory=dict)
season: str = ""
source: str = ""
class SportsDataCollector:
def __init__(self, api_key):
self.api_key = api_key
self.session = requests.Session()
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
})
def get_player_stats(self, portal_url, player_slug, season=None):
"""Fetch player statistics, solving CAPTCHAs as needed."""
url = f"{portal_url}/players/{player_slug}"
if season:
url += f"/{season}"
response = self.session.get(url)
if self._is_captcha_page(response):
response = self._solve_turnstile_and_retry(response, url)
return self._parse_player_stats(response.text)
def get_game_scores(self, portal_url, date):
"""Fetch all game scores for a specific date."""
url = f"{portal_url}/scores/{date}"
response = self.session.get(url)
if self._is_captcha_page(response):
response = self._solve_turnstile_and_retry(response, url)
return self._parse_scores(response.text)
def collect_team_roster(self, portal_url, team_slug, season):
"""Collect stats for all players on a team roster."""
roster_url = f"{portal_url}/teams/{team_slug}/{season}/roster"
response = self.session.get(roster_url)
if self._is_captcha_page(response):
response = self._solve_turnstile_and_retry(response, roster_url)
player_slugs = self._extract_player_links(response.text)
all_stats = []
for slug in player_slugs:
try:
stats = self.get_player_stats(portal_url, slug, season)
all_stats.append(stats)
time.sleep(2) # Respectful delay
except Exception as e:
print(f"Failed for {slug}: {e}")
return all_stats
def _is_captcha_page(self, response):
return (
response.status_code == 403 or
"cf-turnstile" in response.text or
"challenges.cloudflare.com" in response.text
)
def _solve_turnstile_and_retry(self, response, url):
match = re.search(r'data-sitekey="(0x[^"]+)"', response.text)
if not match:
raise ValueError("Turnstile sitekey not found")
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": self.api_key,
"method": "turnstile",
"sitekey": match.group(1),
"pageurl": url,
"json": 1
})
task_id = resp.json()["request"]
for _ in range(60):
time.sleep(3)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": self.api_key,
"action": "get",
"id": task_id,
"json": 1
})
data = result.json()
if data["status"] == 1:
return self.session.post(url, data={
"cf-turnstile-response": data["request"]
})
raise TimeoutError("Turnstile solve timed out")
def _parse_player_stats(self, html):
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
# Extract stat rows from tables
stats = {}
stat_table = soup.select_one("table.stats, #stats-table")
if stat_table:
headers = [th.text.strip() for th in stat_table.select("thead th")]
for row in stat_table.select("tbody tr"):
cells = [td.text.strip() for td in row.select("td")]
if len(cells) == len(headers):
for header, value in zip(headers, cells):
stats[header] = value
def text_or_empty(node):
return node.text.strip() if node and node.text else ""
return PlayerStats(
name=text_or_empty(soup.select_one("h1, .player-name")),
team=text_or_empty(soup.select_one(".team-name, .team")),
position=text_or_empty(soup.select_one(".position, .pos")),
stats=stats
)
def _parse_scores(self, html):
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
games = []
def text_or_none(node):
return node.text.strip() if node and node.text else None
for game in soup.select(".game-card, .scoreboard-item"):
games.append({
"away": text_or_none(game.select_one(".away-team")),
"home": text_or_none(game.select_one(".home-team")),
"away_score": text_or_none(game.select_one(".away-score")),
"home_score": text_or_none(game.select_one(".home-score")),
"status": text_or_none(game.select_one(".game-status"))
})
return games
def _extract_player_links(self, html):
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
links = []
for a in soup.select("a[href*='/players/']"):
slug = a["href"].rstrip("/").split("/")[-1]
if slug and slug not in links:
links.append(slug)
return links
# Usage
collector = SportsDataCollector("YOUR_API_KEY")
# Get player stats
stats = collector.get_player_stats(
"https://sports.example.com", "lebron-james", "2024"
)
print(f"{stats.name} ({stats.team}): {stats.stats}")
# Get all scores for a date
scores = collector.get_game_scores("https://sports.example.com", "2024-12-25")
for game in scores:
print(f"{game['away']} {game['away_score']} @ {game['home']} {game['home_score']}")
Saisondaten-Aggregator (JavaScript)
class SportsAggregator {
constructor(apiKey) {
this.apiKey = apiKey;
}
async collectSeasonData(portalUrl, sport, season, teams) {
const allData = {};
for (const team of teams) {
try {
const roster = await this.getTeamStats(portalUrl, team, season);
allData[team] = roster;
} catch (error) {
allData[team] = { error: error.message };
}
// Rate limit between teams
await new Promise(r => setTimeout(r, 3000));
}
return allData;
}
async getTeamStats(portalUrl, teamSlug, season) {
const url = `${portalUrl}/teams/${teamSlug}/${season}`;
const response = await fetch(url);
const html = await response.text();
if (html.includes('cf-turnstile') || response.status === 403) {
return this.solveAndFetch(url, html);
}
return this.parseTeamPage(html);
}
async solveAndFetch(url, html) {
const match = html.match(/data-sitekey="(0x[^"]+)"/);
if (!match) throw new Error('Turnstile sitekey not found');
const submitResp = await fetch('https://ocr.captchaai.com/in.php', {
method: 'POST',
body: new URLSearchParams({
key: this.apiKey,
method: 'turnstile',
sitekey: match[1],
pageurl: url,
json: '1'
})
});
const { request: taskId } = await submitResp.json();
for (let i = 0; i < 60; i++) {
await new Promise(r => setTimeout(r, 3000));
const result = await fetch(
`https://ocr.captchaai.com/res.php?key=${this.apiKey}&action=get&id=${taskId}&json=1`
);
const data = await result.json();
if (data.status === 1) {
const response = await fetch(url, {
method: 'POST',
body: new URLSearchParams({ 'cf-turnstile-response': data.request })
});
return this.parseTeamPage(await response.text());
}
}
throw new Error('Turnstile solve timed out');
}
parseTeamPage(html) {
const players = [];
const rowMatches = html.matchAll(/<tr[^>]*class="[^"]*player[^"]*"[^>]*>([\s\S]*?)<\/tr>/gi);
for (const row of rowMatches) {
const cells = [...row[1].matchAll(/<td[^>]*>([\s\S]*?)<\/td>/gi)]
.map(m => m[1].replace(/<[^>]+>/g, '').trim());
if (cells.length >= 3) {
players.push({
name: cells[0],
position: cells[1],
stats: cells.slice(2)
});
}
}
return { players, count: players.length };
}
}
// Usage
const aggregator = new SportsAggregator('YOUR_API_KEY');
const seasonData = await aggregator.collectSeasonData(
'https://sports.example.com', 'basketball', '2024',
['lakers', 'celtics', 'warriors']
);
Sammelstrategie nach Sport
Sport
Spitzendatenvolumen
CAPTCHA-Empfindlichkeit
Empfohlener Ansatz
Baseball
Tägliche Spielprotokolle
Mäßig
Nach Spielende einsammeln
Basketball
Spieleabende
Hoch während der Spiele
Nutzen Sie Zeiten außerhalb der Hauptverkehrszeiten
Fußball
Wöchentliche Spiele
Tief zwischen den Spielen
Wöchentliche Sammelabholung
Fußball
Täglich über Ligen hinweg
Mäßig
Sitzungen pro Liga
Hockey
Nächtlich
Mäßig
Sammlung nach dem Spiel
Fehlerbehebung
Problem
Ursache
Lösung
Zu viele CAPTCHAs in kurzer Zeit
Abrufrate oder Parallelität ist für die Quelle zu aggressiv
Drossele Intervalle, halte Sessions stabil und prüfe die Qualität deiner Proxys
Daten fehlen trotz gelöster CAPTCHA
Der Parser liest eine alte oder unvollständige Ansicht aus
Extrahiere Daten erst nach erfolgreicher Token-Anwendung in derselben Sitzung
Kosten steigen stärker als erwartet
Zu viele Wiederholungen oder unnötige Seitenaufrufe lösen zusätzliche Challenges aus
Löse nur kritische Schritte und protokolliere Wiederholungen pro Quelle
Sticky Sessions vs. Rotating Sessions: Beste Proxy-Strategie für CAPTCHA-Workflows mit Captcha AI.
Apr 20, 2026
Vergleiche
Wann sich Headless-Chrome und wann Headed-Chrome für CAPTCHA-Tests in eigenen CI- und QA-Pipelines eignet, und welche Auswirkungen die Wahl auf Stabilität und L...
Nachrichten- und Medienaggregation mit CAPTCHA-Verwaltung: Nachrichtenportale und Medienwebseiten mit Captcha...
Apr 26, 2026
Anwendungsfälle
CAPTCHA-geschützte Webformulare automatisch ausfüllen und abschicken – re CAPTCHA v 2, Cloudflare Turnstile und Bild-CAPTCHAs mit Selenium und Captcha AI.
Diskussionen (0)
Beteiligen Sie sich an der Unterhaltung
Melden Sie sich an, um Ihre Meinung zu teilen.
AnmeldenNoch keine Kommentare.