Sie möchten CAPTCHAs lösen, ohne dafür rund um die Uhr einen Server bereitzuhalten? Azure Functions führt Ihren CaptchaAI-Solver genau dann aus, wenn eine Anfrage eintrifft – und rechnet nur diese Ausführungszeit ab. Dieser Leitfaden zeigt Schritt für Schritt, wie Sie einen Solver als serverlose Funktion aufsetzen: mit HTTP-Trigger für Einzelanfragen, dem API-Schlüssel sicher im Key Vault, Batch-Verarbeitung über Queue Storage und Monitoring per Application Insights.
Voraussetzungen
Bevor Sie loslegen, sollten Sie Folgendes bereithalten:
- ein Azure-Abo mit Rechten zum Anlegen von Function-Apps und Key Vaults
- die Azure CLI (
az) und die Azure Functions Core Tools (func), lokal installiert - Python 3.11 auf Ihrem Rechner – passend zur Laufzeit der Function-App
- einen CaptchaAI-API-Schlüssel von captchaai.com
Warum sich Azure Functions für CAPTCHA-Workloads eignet
CAPTCHA-Last ist selten gleichmäßig verteilt. Mal treffen zehn Formulare gleichzeitig ein, dann wieder eine Stunde lang keines. Eine dauerhaft laufende VM würde in diesen Leerlaufphasen Geld kosten, ohne etwas zu leisten. Eine serverlose Funktion skaliert dagegen mit der tatsächlichen Nachfrage – vom Nullpunkt bis zu Dutzenden parallelen Instanzen – und fällt danach wieder auf null zurück.
Serverlos lohnt sich vor allem, wenn:
- die Last stoßweise auftritt statt konstant über den Tag verteilt
- nächtliche oder ereignisgesteuerte Batches den Großteil der Arbeit ausmachen
- Sie keine VM rund um die Uhr für nur gelegentliche Lösungen bezahlen möchten
Das Preismodell von CaptchaAI passt gut dazu: Abgerechnet wird pro gleichzeitigem Thread, nicht pro gelöstem CAPTCHA. Ein BASIC-Tarif (15 $/Monat, 5 Threads) erlaubt fünf gleichzeitige Lösungen bei unbegrenzter Anzahl pro Thread im Abrechnungsmonat. Stimmen Sie die Nebenläufigkeit Ihrer Funktion auf Ihre Thread-Zuteilung ab – so vermeiden Sie, dass mehr parallele Aufrufe entstehen, als Ihr Tarif gleichzeitig bedienen kann.
Wenn Ihre Nutzer im DACH-Raum sitzen, bietet sich für das Deployment die Azure-Region Germany West Central (Frankfurt) an: kürzere Latenzen und lokale Datenhaltung. Bei Scraping-Szenarien gilt außerdem die übliche DSGVO-Sorgfalt – IP-Adressen zählen als personenbezogene Daten, prüfen Sie Ihre Datenflüsse und die Rechtsgrundlage eigenständig.
HTTP-Trigger: die Solver-Funktion
Der Einstiegspunkt ist eine HTTP-ausgelöste Funktion. Sie nimmt eine JSON-Anfrage mit method und params entgegen, übermittelt die Aufgabe an CaptchaAI und fragt anschließend das Ergebnis im Polling-Verfahren ab, bis das Token vorliegt:
# function_app.py
import json
import time
import os
import logging
import urllib.request
import urllib.parse
import azure.functions as func
app = func.FunctionApp()
@app.route(route="solve", methods=["POST"])
def solve_captcha(req: func.HttpRequest) -> func.HttpResponse:
"""HTTP trigger for CAPTCHA solving."""
try:
body = req.get_json()
except ValueError:
return func.HttpResponse(
json.dumps({"error": "JSON body required"}),
status_code=400,
mimetype="application/json",
)
method = body.get("method", "userrecaptcha")
params = body.get("params", {})
api_key = os.environ["CAPTCHAAI_KEY"]
try:
token = solve(api_key, method, params)
return func.HttpResponse(
json.dumps({"token": token}),
mimetype="application/json",
)
except Exception as e:
logging.error(f"Solve failed: {e}")
return func.HttpResponse(
json.dumps({"error": str(e)}),
status_code=500,
mimetype="application/json",
)
def solve(api_key, method, params, timeout=90):
"""Solve CAPTCHA via CaptchaAI API."""
submit_data = urllib.parse.urlencode({
"key": api_key,
"method": method,
"json": 1,
**params,
}).encode()
req = urllib.request.Request(
"https://ocr.captchaai.com/in.php",
data=submit_data,
)
with urllib.request.urlopen(req, timeout=30) as resp:
result = json.loads(resp.read())
if result.get("status") != 1:
raise RuntimeError(f"Submit error: {result.get('request')}")
task_id = result["request"]
start = time.time()
while time.time() - start < timeout:
time.sleep(5)
poll_url = (
f"https://ocr.captchaai.com/res.php"
f"?key={api_key}&action=get&id={task_id}&json=1"
)
with urllib.request.urlopen(poll_url, timeout=15) as resp:
data = json.loads(resp.read())
if data["request"] != "CAPCHA_NOT_READY":
if data.get("status") == 1:
return data["request"]
raise RuntimeError(f"Solve error: {data['request']}")
raise TimeoutError("Solve timeout")
Der method-Wert bestimmt den CAPTCHA-Typ. Im Beispiel steht userrecaptcha für reCAPTCHA – dieselbe Funktion bedient über den passenden Methodennamen aber auch Cloudflare Turnstile, GeeTest v3 sowie Bild- und Raster-CAPTCHAs.
API-Schlüssel im Key Vault ablegen
Legen Sie den API-Schlüssel niemals im Code oder in einer eingecheckten Konfigurationsdatei ab. Speichern Sie ihn stattdessen im Azure Key Vault und referenzieren Sie ihn zur Laufzeit:
# Create Key Vault
az keyvault create \
--name captchaai-vault \
--resource-group myResourceGroup
# Store secret
az keyvault secret set \
--vault-name captchaai-vault \
--name CaptchaAIKey \
--value "YOUR_API_KEY"
# Grant function access
az webapp identity assign \
--name my-captcha-function \
--resource-group myResourceGroup
az keyvault set-policy \
--name captchaai-vault \
--object-id <principal-id> \
--secret-permissions get
Anschließend binden Sie das Secret über eine Key-Vault-Referenz in den Anwendungseinstellungen ein. Die Funktion liest den Wert dann wie eine normale Umgebungsvariable – ohne dass der Schlüssel jemals im Klartext in der Konfiguration steht:
CAPTCHAAI_KEY=@Microsoft.KeyVault(SecretUri=https://captchaai-vault.vault.azure.net/secrets/CaptchaAIKey/)
Batch-Verarbeitung über Queue Storage
Für größere Mengen entkoppeln Sie Annahme und Verarbeitung. Ein Queue-Trigger liest CAPTCHA-Aufgaben aus Azure Queue Storage und arbeitet sie im Hintergrund ab – jede Nachricht wird zu einer eigenen Funktionsausführung, sodass Azure die Last automatisch auf mehrere Instanzen verteilt:
@app.queue_trigger(
arg_name="msg",
queue_name="captcha-tasks",
connection="AzureWebJobsStorage",
)
def process_queue_task(msg: func.QueueMessage):
"""Process CAPTCHA task from queue."""
task = json.loads(msg.get_body().decode())
api_key = os.environ["CAPTCHAAI_KEY"]
try:
token = solve(api_key, task["method"], task["params"])
logging.info(f"Task {task['id']} solved")
# Store result in Table Storage or return queue
_store_result(task["id"], "success", token)
except Exception as e:
logging.error(f"Task {task['id']} failed: {e}")
_store_result(task["id"], "error", str(e))
def _store_result(task_id, status, value):
"""Store result (simplified — use Table Storage in production)."""
logging.info(f"Result: {task_id} = {status}")
Persistieren Sie das Ergebnis in der Praxis in Table Storage oder schreiben Sie es in eine Ergebnis-Warteschlange zurück, statt es nur zu protokollieren.
Projektstruktur
Eine Azure-Functions-App im Python-Modell v2 kommt mit wenigen Dateien aus:
captcha-function/
├── function_app.py
├── requirements.txt
├── host.json
└── local.settings.json
Die vier Dateien im Überblick:
function_app.py– enthält HTTP- und Queue-Trigger sowie diesolve-Logikrequirements.txt– listet die Python-Abhängigkeitenhost.json– App-weite Einstellungen wie das Timeoutlocal.settings.json– nur für die lokale Entwicklung, nie ins Repository einchecken
requirements.txt:
azure-functions
In host.json heben Sie das Standard-Timeout an, damit langsamere Lösungen nicht abgeschnitten werden:
{
"version": "2.0",
"functionTimeout": "00:02:00",
"logging": {
"logLevel": {
"default": "Information"
}
}
}
local.settings.json gilt nur für die lokale Entwicklung – der Produktivschlüssel bleibt im Key Vault:
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "python",
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"CAPTCHAAI_KEY": "YOUR_API_KEY_FOR_LOCAL_DEV"
}
}
Funktion bereitstellen
Legen Sie die Function-App im Consumption-Plan an und veröffentlichen Sie Ihren Code. Der abschließende curl-Aufruf prüft, ob der Endpunkt wie erwartet antwortet:
# Create function app
az functionapp create \
--resource-group myResourceGroup \
--consumption-plan-location westus2 \
--runtime python \
--runtime-version 3.11 \
--functions-version 4 \
--name my-captcha-solver \
--storage-account mystorageaccount
# Deploy
func azure functionapp publish my-captcha-solver
# Test
curl -X POST https://my-captcha-solver.azurewebsites.net/api/solve \
-H "Content-Type: application/json" \
-d '{
"method": "userrecaptcha",
"params": {
"googlekey": "SITE_KEY",
"pageurl": "https://example.com"
}
}'
Für Nutzer im DACH-Raum ersetzen Sie westus2 durch germanywestcentral, um die Funktion in Frankfurt zu betreiben.
Aufgaben in die Warteschlange stellen
Um einen Batch zu starten, senden Sie die Aufgaben als JSON-Nachrichten an die Queue. Der oben definierte Queue-Trigger übernimmt die Verarbeitung dann automatisch:
from azure.storage.queue import QueueClient
import json
queue = QueueClient.from_connection_string(
conn_str="YOUR_STORAGE_CONNECTION_STRING",
queue_name="captcha-tasks",
)
# Submit batch
for i in range(10):
task = {
"id": f"task-{i}",
"method": "userrecaptcha",
"params": {
"googlekey": "SITE_KEY",
"pageurl": f"https://example.com/page{i}",
},
}
queue.send_message(json.dumps(task))
print(f"Queued task-{i}")
Praxisbeispiel: nächtlicher Batch-Lauf
Ein typisches Szenario aus der Praxis: Ein Team betreibt eine Monitoring-Pipeline, die jede Nacht mehrere hundert geschützte Seiten prüft. Der Ablauf sieht dann so aus:
- Ein Cron-Job stellt nachts alle Aufgaben gebündelt in die Queue.
- Der Queue-Trigger startet je Nachricht eine Funktionsausführung.
- Azure skaliert auf so viele Instanzen hoch, wie Nachrichten anfallen – begrenzt durch die Thread-Zuteilung des CaptchaAI-Tarifs.
- Tagsüber, ohne Batch, fällt die App auf null zurück und verursacht keine Kosten.
Mit einem STANDARD-Tarif (30 $/Monat, 15 Threads) laufen bis zu 15 Lösungen parallel; reicht das nicht, wechseln Sie in einen größeren Tarif, ohne den Code zu ändern. Der Vorteil gegenüber einem dauerhaft laufenden Worker: Es entstehen weder Rechen- noch Leerlaufkosten, wenn gerade kein Batch läuft.
Fehlerbehebung
| Problem | Ursache | Lösung |
|---|---|---|
| Die Funktion läuft nach 5 Minuten ab | Standard-Timeout | Legen Sie functionTimeout in host.json fest |
| Die Key Vault-Referenz gibt einen leeren Wert zurück | Fehlende Identität/policy | Weisen Sie verwaltete Identitäten und Key Vault-Richtlinien zu |
| Warteschlangennachrichten werden endlos wiederholt | Funktion löst Ausnahme aus | Behandeln Sie bekannte Fehler, protokollieren Sie sie und geben Sie sie zurück |
| Kaltstart > 10 Sekunden | Python-Laufzeitinitialisierung | Verwenden Sie den Premium-Plan oder legen Sie FUNCTIONS_WORKER_PROCESS_COUNT fest |
FAQ
Welche CAPTCHA-Typen kann ich mit CaptchaAI auf Azure lösen?
Über denselben solve-Handler unterstützt CaptchaAI reCAPTCHA v2 und v3, Cloudflare Turnstile und Challenge, GeeTest v3 sowie Bild-, OCR- und Raster-CAPTCHAs und BLS – jeweils über den passenden method-Wert. CaptchaFox, Friendly Captcha und Lemin befinden sich in der Beta. hCaptcha, FunCaptcha und GeeTest v4 werden derzeit nicht unterstützt.
Wie bewahre ich den CaptchaAI-API-Schlüssel sicher auf?
Im Azure Key Vault, referenziert über eine Key-Vault-Referenz in den Anwendungseinstellungen. Die Funktion greift per verwalteter Identität darauf zu; der Schlüssel taucht dadurch weder im Code noch im Klartext in der Konfiguration auf. Lokal nutzen Sie einen separaten Testschlüssel in local.settings.json.
Welche Azure-Region eignet sich für Nutzer im DACH-Raum?
Germany West Central (Frankfurt) bietet niedrige Latenzen und lokale Datenhaltung. Setzen Sie beim Anlegen der Function-App --consumption-plan-location germanywestcentral. Bei Scraping-Workloads sollten Sie zusätzlich Ihre DSGVO-Grundlage prüfen, da IP-Adressen als personenbezogene Daten gelten.
Consumption- oder Premium-Plan – was passt für CAPTCHA-Workloads?
Consumption eignet sich für geringe, unregelmäßige Mengen und rechnet nur die tatsächliche Ausführung ab. Premium hält Instanzen warm, beseitigt Kaltstarts und unterstützt VNET-Integration – sinnvoll bei konstanter Last oder wenn Kaltstarts von über 10 Sekunden Ihre Antwortzeiten stören.
Wie wirkt sich das Thread-basierte Preismodell auf serverlose Batches aus?
CaptchaAI rechnet pro gleichzeitigem Thread ab, nicht pro Lösung – bei unbegrenzten Lösungen je Thread. Die Nebenläufigkeit Ihrer Funktion sollte zur Thread-Zahl Ihres Tarifs passen: Mehr parallele Aufrufe als verfügbare Threads führen nur zu Wartezeiten, nicht zu mehr Durchsatz.
Verwandte Leitfäden
Serverlos auf Azure starten – holen Sie sich Ihren CaptchaAI-Schlüssel und lösen Sie Ihr erstes CAPTCHA noch heute.