Gehaltsdatenbanken, Jobbörsen und staatliche Arbeitsportale schützen Vergütungsdaten mit Cloudflare Turnstile und reCAPTCHA. CAPTCHAs werden ausgelöst, wenn Gehaltsspannen nach Rolle, Standort oder Branche abgefragt werden – insbesondere bei der Massendatenerfassung für viele Berufsbezeichnungen. Hier erfahren Sie, wie Sie damit umgehen.
CAPTCHA-Muster auf Gehaltsportalen
Quelltyp
CAPTCHA
Auslöser
Gehaltsvergleichsseiten
Cloudflare Turnstile
Wiederholte Suchanfragen
Gehaltsfilter der Jobbörse
reCAPTCHA v2
Mehrere Gehaltssuchen
Staatliche Arbeitsstatistik
Bild-CAPTCHA
Anfragen zum Herunterladen von Daten
Gehaltsseiten für Unternehmen
Cloudflare Challenge
Massenseitenaufrufe
HR-Umfrageplattformen
reCAPTCHA v3
Formulareinreichungen
Gehaltsdatensammler
import requests
import time
import re
from dataclasses import dataclass
@dataclass
class SalaryRecord:
title: str
location: str
min_salary: float
max_salary: float
median_salary: float
sample_size: int
source: str
class SalaryCollector:
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 collect_salary_data(self, portal_url, job_title, location):
"""Search for salary data, solving CAPTCHAs as needed."""
response = self.session.get(portal_url, params={
"title": job_title,
"location": location
})
if self._is_turnstile_challenge(response):
response = self._solve_turnstile_and_retry(response, portal_url)
return self._parse_salary_data(response.text, portal_url)
def collect_bulk(self, portal_url, job_titles, locations):
"""Collect salary data for multiple job title + location combos."""
results = []
for title in job_titles:
for location in locations:
try:
data = self.collect_salary_data(
portal_url, title, location
)
results.extend(data)
# Respectful delay between requests
time.sleep(2)
except Exception as e:
print(f"Failed for {title} in {location}: {e}")
return results
def _is_turnstile_challenge(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_salary_data(self, html, source):
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
records = []
def text_or_empty(node):
return node.text.strip() if node and node.text else ""
for row in soup.select(".salary-row, .compensation-entry, tr[data-salary]"):
try:
records.append(SalaryRecord(
title=text_or_empty(row.select_one(".job-title, .title")),
location=text_or_empty(row.select_one(".location")),
min_salary=self._parse_amount(
text_or_empty(row.select_one(".min-salary, .low"))
),
max_salary=self._parse_amount(
text_or_empty(row.select_one(".max-salary, .high"))
),
median_salary=self._parse_amount(
text_or_empty(row.select_one(".median, .mid"))
),
sample_size=int(
text_or_empty(row.select_one(".count, .sample")).replace(",", "") or 0
),
source=source
))
except (AttributeError, ValueError):
continue
return records
def _parse_amount(self, text):
if not text:
return 0.0
cleaned = re.sub(r'[^\d.]', '', text)
return float(cleaned) if cleaned else 0.0
# Usage
collector = SalaryCollector("YOUR_API_KEY")
data = collector.collect_bulk(
"https://salary.example.com/search",
job_titles=["Software Engineer", "Data Analyst", "Product Manager"],
locations=["San Francisco", "New York", "Austin"]
)
for record in data:
print(f"{record.title} in {record.location}: "
f"${record.min_salary:,.0f}–${record.max_salary:,.0f} "
f"(median: ${record.median_salary:,.0f})")
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.