
Emma Foster
Machine Learning Engineer

AntiCloudflareTask yang telah didokumentasikan dengan URL target yang tepat dan proxy statis atau sticky; pertahankan agen Chrome yang didukung konsisten.cf_clearance, cookie, token, kredensial proxy, dan HTML mentah sebagai rahasia berumur pendek yang tidak boleh masuk ke log atau analitik.Diagnosis Tantangan Cloudflare sebaiknya dimulai dengan klasifikasi status dan identitas sesi, bukan pembuatan tugas berulang. Halaman yang dilindungi dapat menampilkan halaman interstitial tantangan, widget Turnstile, respons HTTP 429, blok keras, layar otentikasi, kesalahan asal, atau halaman aplikasi biasa. Setiap status membutuhkan tindakan yang berbeda. Untuk halaman Tantangan yang didukung, CapSolver mendokumentasikan AntiCloudflareTask dengan URL target yang tepat, proxy statis atau sticky, dan agen Chrome yang konsisten; beberapa situs juga membutuhkan HTML tantangan segar dari sesi yang sama. Data clearance yang dikembalikan kemudian harus diterapkan pada identitas permintaan yang sama dan diverifikasi terhadap halaman target yang diharapkan. Panduan ini menyajikan implementasi umum tanpa mengikat desain ke industri, kasus penggunaan, atau kerangka agen tertentu.
Cloudflare menggambarkan Tantangan sebagai mekanisme keamanan yang mengevaluasi sinyal browser dan klien, serta mungkin meminta interaksi pengguna minimal. Kategori luas ini tidak boleh disalahartikan sebagai setiap respons yang ditolak atau tidak lengkap.
Alur diagnostik harus menjawab empat pertanyaan secara berurutan:
Blog CapSolver Cloudflare mengandung materi produk dan implementasi terkait, sementara FAQ Penyelesaian CAPTCHA CapSolver menjelaskan siklus tugas umum.
| Status | Bukti Umum | Tindakan Berikutnya yang Benar |
|---|---|---|
| Halaman yang Diharapkan | Judul yang diketahui, rute, selektor semantik, atau skema respons | Parsing atau lanjutkan |
| Halaman Tantangan Cloudflare | "Tunggu sebentar...", skrip tantangan, penanda Cloudflare | Validasi lingkup dan pertimbangkan AntiCloudflareTask |
| Widget Turnstile | Skrip Turnstile, kunci situs, kontainer widget | Gunakan jalur tugas Turnstile yang telah didokumentasikan |
| Pembatasan kecepatan | Respons HTTP 429, Retry-After, respons kuota |
Tunggu dan kurangi laju permintaan |
| Otentikasi diperlukan | Form login, 401, status sesi kadaluarsa | Otentikasi melalui alur yang disetujui |
| Blok keras | 403 yang terus-menerus tanpa bukti tantangan yang didukung | Berhenti dan tinjau kebijakan akses atau identitas jaringan |
| Kesalahan asal atau jaringan | 5xx, DNS, TLS, timeout | Perbaiki infrastruktur; jangan buat tugas tantangan |
| Halaman tidak dikenal | Tata letak atau semantik tidak sesuai dengan status yang diketahui | Simpan diagnostik yang telah direvisi dan minta tinjauan |
Layanan tantangan seharusnya tidak pernah digunakan sebagai respons universal untuk setiap 403 atau halaman kosong.
from dataclasses import dataclass
@dataclass(frozen=True)
class HttpObservation:
url: str
status_code: int
title: str
html: str
headers: dict[str, str]
def classify_observation(obs: HttpObservation) -> str:
title = obs.title.lower()
html = obs.html.lower()
if obs.status_code == 429:
return "RATE_LIMIT"
if obs.status_code >= 500:
return "ORIGIN_OR_NETWORK_ERROR"
if "challenges.cloudflare.com/turnstile" in html:
return "TURNSTILE_WIDGET"
challenge_markers = (
"just a moment" in title
or "challenge-platform" in html
or "cf-chl-" in html
)
if challenge_markers:
return "CLOUDFLARE_CHALLENGE"
if 'type="password"' in html or obs.status_code == 401:
return "AUTH_REQUIRED"
if obs.status_code == 200 and 'data-page="expected"' in html:
return "EXPECTED_PAGE"
if obs.status_code == 403:
return "HARD_BLOCK"
return "UNKNOWN_PAGE"
Gunakan penanda keberhasilan yang spesifik untuk target. HTTP 200 umum tidak cukup karena halaman tantangan, kesalahan, dan persetujuan juga dapat mengembalikan 200.
FAQ kesalahan CapSolver berguna untuk memisahkan kesalahan penyedia dari kesalahan status halaman.
Clearance Cloudflare terkait dengan konteks pengunjung dan perangkat. Dokumentasi clearance Cloudflare menyatakan bahwa cf_clearance terkait dengan pengunjung dan perangkat tertentu dan dapat dievaluasi ulang seiring perubahan perilaku sesi.
Wakili identitas permintaan secara eksplisit:
from dataclasses import dataclass
@dataclass(frozen=True)
class SessionIdentity:
session_id: str
proxy_profile: str
chrome_user_agent: str
tls_profile: str
cookie_jar_id: str
target_host: str
Tupel tersebut harus tetap stabil dari pengamatan awal hingga eksekusi tugas dan verifikasi halaman target.
from dataclasses import dataclass
from urllib.parse import urlparse
@dataclass(frozen=True)
class TargetPolicy:
target_id: str
hostname: str
allowed_path_prefixes: tuple[str, ...]
purpose: str
proxy_profile: str
max_attempts: int = 1
TARGETS = {
"docs_demo": TargetPolicy(
target_id="docs_demo",
hostname="approved.example.com",
allowed_path_prefixes=("/public/", "/test/"),
purpose="validasi integrasi yang diizinkan",
proxy_profile="approved_static_us",
)
}
def resolve_target(target_id: str, url: str) -> TargetPolicy:
policy = TARGETS.get(target_id)
if policy is None:
raise PermissionError("Target tidak dikenal")
parsed = urlparse(url)
if parsed.scheme != "https":
raise PermissionError("HTTPS diperlukan")
if parsed.hostname != policy.hostname:
raise PermissionError("Host di luar lingkup yang disetujui")
if not any(parsed.path.startswith(p) for p in policy.allowed_path_prefixes):
raise PermissionError("Path di luar lingkup yang disetujui")
return policy
Jangan biarkan pemanggil yang tidak tepercaya menyediakan URL, proxy, atau tujuan yang arbitrer.
AntiCloudflareTaskDokumentasi Tantangan Cloudflare CapSolver mendefinisikan AntiCloudflareTask.
| Kolom | Diperlukan | Aturan Diagnostik |
|---|---|---|
type |
Ya | Harus AntiCloudflareTask |
websiteURL |
Ya | Halaman target yang tepat |
proxy |
Ya | Proxy statis atau sticky yang digunakan untuk sesi |
userAgent |
Bersyarat | Agen Chrome yang didukung yang digunakan oleh klien |
html |
Bersyarat | HTML tantangan segar dari sesi yang sama |
Dokumentasi juga memanggil perpustakaan permintaan yang mendukung TLS dan merekomendasikan mempertahankan sesi proxy selama setidaknya tiga menit.
Halaman produk CapSolver membantu membedakan kategori tugas Cloudflare dan Turnstile yang didukung.
import os
import capsolver
capsolver.api_key = os.environ["CAPSOLVER_API_KEY"]
PROXY_VAULT = {
"approved_static_us": os.environ["APPROVED_STATIC_PROXY"],
}
def build_task(
policy: TargetPolicy,
identity: SessionIdentity,
target_url: str,
fresh_html: str | None,
) -> dict:
if identity.proxy_profile != policy.proxy_profile:
raise ValueError("Proxy sesi tidak sesuai dengan kebijakan target")
if identity.target_host != policy.hostname:
raise ValueError("Host sesi tidak sesuai dengan kebijakan target")
task = {
"type": "AntiCloudflareTask",
"websiteURL": target_url,
"proxy": PROXY_VAULT[identity.proxy_profile],
"userAgent": identity.chrome_user_agent,
}
if fresh_html:
task["html"] = fresh_html
return task
Pembangun tugas membaca kredensial jaringan dari brankas yang dilindungi. Ia tidak mengembalikan mereka ke pemanggil atau menulisnya ke jejak.
Ketika HTML diperlukan, tangkap langsung setelah klasifikator mengidentifikasi tantangan.
from datetime import datetime, timezone
@dataclass(frozen=True)
class ChallengeDocument:
session_id: str
target_url: str
body: str
status_code: int
captured_at: str
async def capture_challenge_document(client, identity, target_url):
response = await client.get(
target_url,
session_id=identity.session_id,
proxy_profile=identity.proxy_profile,
user_agent=identity.chrome_user_agent,
tls_profile=identity.tls_profile,
cookie_jar_id=identity.cookie_jar_id,
)
observation = HttpObservation(
url=str(response.url),
status_code=response.status_code,
title=extract_title(response.text),
html=response.text,
headers=dict(response.headers),
)
if classify_observation(observation) != "CLOUDFLARE_CHALLENGE":
raise ValueError("Respons bukan halaman Tantangan yang dikenal")
return ChallengeDocument(
session_id=identity.session_id,
target_url=target_url,
body=response.text,
status_code=response.status_code,
captured_at=datetime.now(timezone.utc).isoformat(),
)
Jangan gunakan HTML yang ditangkap oleh proxy, agen pengguna, sesi, atau URL target lain.
def solve_approved_challenge(
target_id: str,
target_url: str,
identity: SessionIdentity,
document: ChallengeDocument,
) -> dict:
policy = resolve_target(target_id, target_url)
if document.session_id != identity.session_id:
raise ValueError("Dokumen dan sesi tidak sesuai")
if document.target_url != target_url:
raise ValueError("Dokumen dan URL target tidak sesuai")
task = build_task(
policy=policy,
identity=identity,
target_url=target_url,
fresh_html=document.body,
)
solution = capsolver.solve(task)
cookies = solution.get("cookies") or {}
clearance = cookies.get("cf_clearance") or solution.get("token")
returned_user_agent = solution.get("userAgent") or identity.chrome_user_agent
if not clearance:
raise RuntimeError("Hasil tugas tidak mengandung data clearance")
return {
"cookies": cookies,
"user_agent": returned_user_agent,
}
Jangan cetak solution. Ekstrak hanya bidang runtime yang diperlukan untuk permintaan berikutnya.
async def apply_clearance(client, identity: SessionIdentity, result: dict):
for name, value in result["cookies"].items():
await client.set_cookie(
cookie_jar_id=identity.cookie_jar_id,
domain=identity.target_host,
name=name,
value=value,
secure=True,
)
await client.set_user_agent(
session_id=identity.session_id,
user_agent=result["user_agent"],
)
Gunakan host dan ruang cookie yang tepat yang diperlukan oleh target yang disetujui. Jangan menyalin cookie ke domain yang tidak terkait atau mesin lain.
@dataclass(frozen=True)
class VerificationRule:
expected_status: int
required_selectors: tuple[str, ...]
forbidden_markers: tuple[str, ...]
expected_path_prefix: str
async def verify_target_page(
client,
identity: SessionIdentity,
target_url: str,
rule: VerificationRule,
) -> dict:
response = await client.get(
target_url,
session_id=identity.session_id,
proxy_profile=identity.proxy_profile,
user_agent=identity.chrome_user_agent,
tls_profile=identity.tls_profile,
cookie_jar_id=identity.cookie_jar_id,
)
parsed = urlparse(str(response.url))
body = response.text.lower()
status_ok = response.status_code == rule.expected_status
path_ok = parsed.path.startswith(rule.expected_path_prefix)
markers_ok = not any(marker.lower() in body for marker in rule.forbidden_markers)
selectors_ok = all(selector_in_html(response.text, selector) for selector in rule.required_selectors)
return {
"verified": status_ok and path_ok and markers_ok and selectors_ok,
"status_ok": status_ok,
"path_ok": path_ok,
"markers_ok": markers_ok,
"selectors_ok": selectors_ok,
}
Hasil tugas CapSolver tidak cukup. Aplikasi harus terus berjalan hanya setelah verifikasi ini mengembalikan verified=True.
from enum import Enum
class FlowState(str, Enum):
OBSERVED = "OBSERVED"
CLASSIFIED = "CLASSIFIED"
TASK_CREATED = "TASK_CREATED"
RESULT_READY = "RESULT_READY"
PAGE_VERIFIED = "PAGE_VERIFIED"
STOPPED = "STOPPED"
ALLOWED = {
FlowState.OBSERVED: {FlowState.CLASSIFIED, FlowState.STOPPED},
FlowState.CLASSIFIED: {FlowState.TASK_CREATED, FlowState.STOPPED},
FlowState.TASK_CREATED: {FlowState.RESULT_READY, FlowState.STOPPED},
FlowState.RESULT_READY: {FlowState.PAGE_VERIFIED, FlowState.STOPPED},
FlowState.PAGE_VERIFIED: {FlowState.STOPPED},
}
def transition(current: FlowState, next_state: FlowState) -> FlowState:
if next_state not in ALLOWED[current]:
raise ValueError(f"Transisi tidak valid: {current} -> {next_state}")
return next_state
Izinkan satu percobaan tugas per status halaman yang diamati. Jika verifikasi gagal, berhenti dan minta tinjauan daripada mengulang.
Dokumentasi kode kesalahan CapSolver membedakan kesalahan input, batas, timeout, proxy, akun, dukungan, dan layanan sementara.
| Kelas Kesalahan | Contoh | Tindakan |
|---|---|---|
| Input tidak valid | ERROR_INVALID_TASK_DATA |
Perbaiki pembuatan tugas yang tepercaya |
| Batas kecepatan | ERROR_RATE_LIMIT |
Tunggu sesuai kebijakan |
| Timeout | ERROR_TASK_TIMEOUT |
Catat waktu dan berhenti atau tinjau |
| Tugas tidak didukung | ERROR_TASK_NOT_SUPPORTED |
Klasifikasikan ulang jenis tantangan |
| Tidak dapat diselesaikan | ERROR_CAPTCHA_UNSOLVABLE |
Berhenti dan tinjau status halaman |
| Proxy Diblokir | ERROR_PROXY_BANNED |
Ulas identitas jaringan yang disetujui |
| Akun/kunci | ERROR_KEY_DENIED_ACCESS, ERROR_ZERO_BALANCE |
Perbaiki konfigurasi akun |
| Layanan sementara | ERROR_SERVICE_UNAVALIABLE |
Tunda dan periksa status penyedia |
Jangan menerapkan aturan ulang yang sama untuk setiap kesalahan.
ERROR_ACTIONS = {
"ERROR_INVALID_TASK_DATA": "PERBAIKI_INPUT",
"ERROR_RATE_LIMIT": "TUNDA",
"ERROR_TASK_TIMEOUT": "ULAS",
"ERROR_TASK_NOT_SUPPORTED": "KELAS_ULANG",
"ERROR_CAPTCHA_UNSOLVABLE": "ULAS",
"ERROR_PROXY_BANNED": "ULAS_JARINGAN",
"ERROR_KEY_DENIED_ACCESS": "PERBAIKI_AKUN",
"ERROR_ZERO_BALANCE": "PERBAIKI_AKUN",
"ERROR_SERVICE_UNAVALIABLE": "TUNDA",
}
def normalize_error(error_code: str | None) -> dict:
code = error_code or "UNKNOWN_ERROR"
return {
"category": code,
"action": ERROR_ACTIONS.get(code, "ULAS_OPERATOR"),
"retry_allowed": ERROR_ACTIONS.get(code) in {"TUNDA", "TUNDA"},
}
Pengulangan hanya boleh diizinkan oleh kebijakan yang tepercaya dan hanya setelah kondisi yang memicu berubah atau periode menunggu berlalu.
Anggap hal berikut sebagai rahasia:
cf_clearance dan cookie lainnya;SAFE_EVENT_FIELDS = {
"event",
"target_id",
"state",
"error_category",
"attempt_count",
"duration_ms",
"verified",
"observed_at",
}
def redact_event(event: dict) -> dict:
return {
key: event[key]
for key in SAFE_EVENT_FIELDS
if key in event
}
Simpan hash atau referensi internal ke bukti sensitif daripada menyimpan bukti itu sendiri di log umum.
FAQ CapSolver memberikan panduan operasional tambahan, dan halaman status CapSolver membantu membedakan kegagalan aplikasi dari ketersediaan penyedia.
from datetime import datetime, timezone
from time import monotonic
def diagnostic_event(
target_id: str,
state: str,
attempt_count: int,
verified: bool,
started_at: float,
error_category: str | None = None,
) -> dict:
return redact_event({
"event": "diagnostik_tantangan_cloudflare",
"target_id": target_id,
"state": state,
"attempt_count": attempt_count,
"duration_ms": int((monotonic() - started_at) * 1000),
"verified": verified,
"error_category": error_category,
"observed_at": datetime.now(timezone.utc).isoformat(),
})
Lacak tingkat tantangan, tingkat tugas yang berhasil, tingkat halaman yang diverifikasi, distribusi kesalahan, waktu hingga siap, dan volume ulasan operator. Jangan lacak rahasia.
import pytest
@pytest.mark.parametrize(
"status,title,html,expected",
[
(429, "Dibatasi laju", "", "BATAS_LAJU"),
(403, "Tunggu sebentar...", "cf-chl-test", "TANTANGAN_CLOUDFLARE"),
(200, "Masuk", '<input type="password">', "KEPERLUAN_AUTENTIKASI"),
(500, "Kesalahan server", "", "KESALAHAN_ASAL_ATAU_JARINGAN"),
],
)
def test_classifier(status, title, html, expected):
observation = HttpObservation(
url="https://approved.example.com/test/",
status_code=status,
title=title,
html=html,
headers={},
)
assert classify_observation(observation) == expected
Uji juga ketidaksesuaian identitas:
def test_task_menolak_ketidaksesuaian_profil_proxy():
policy = TARGETS["docs_demo"]
identity = SessionIdentity(
session_id="session-1",
proxy_profile="profil_salah",
chrome_user_agent="Mozilla/5.0 ... Chrome/141.0.0.0 ...",
tls_profile="chrome141",
cookie_jar_id="jar-1",
target_host="approved.example.com",
)
with pytest.raises(ValueError):
build_task(
policy=policy,
identity=identity,
target_url="https://approved.example.com/test/",
fresh_html="<html>Tunggu sebentar...</html>",
)
Akhirnya, uji bahwa redaksi mengecualikan cookie, HTML, kunci, dan nilai proxy.
Kode Bonus: Gunakan kode WEBS di Dasbor CapSolver untuk mendapatkan bonus tambahan 5% pada setiap recharge.
| Pola | Konsistensi Identitas | Keterjelasan Diagnostik | Rekomendasi |
|---|---|---|---|
| Ulangi setiap 403 | Rendah | Rendah | Hindari |
| Buat tugas dari bidang yang disediakan pengguna | Variabel | Rendah | Hindari |
| Kelasifikasikan, bangun dari identitas yang tepercaya, lalu verifikasi | Tinggi | Tinggi | Disarankan |
| Berhenti dan minta ulasan manual | Tinggi | Tinggi | Wajib untuk keadaan yang tidak dikenal atau sensitif |
Pola yang disarankan membuat setiap keputusan jelas dan dapat diuji.
AntiCloudflareTask hanya untuk halaman Tantangan yang didukung secara terkenal.Halaman produk CapSolver https://www.capsolver.com/products dapat membantu memverifikasi kategori tantangan yang didukung sebelum implementasi.
Gunakan penanganan Tantangan Cloudflare hanya di situs yang Anda miliki, uji, atau memiliki izin eksplisit untuk mengakses. Hormati ketentuan, batas laju, batas otentikasi, kewajiban privasi, dan kebijakan sumber. Kemampuan pemrosesan tantangan tidak memberikan hak akses. Berhenti ketika target tidak dikenal, halaman sensitif, identitas tidak konsisten, atau verifikasi gagal. Pertahankan tindakan konsekuensial di balik kebijakan dan langkah persetujuan manusia.
Diagnostics Tantangan Cloudflare harus menjadi pipa yang ketat: otorisasi target, klasifikasikan halaman yang diamati, bangun AntiCloudflareTask dari identitas sesi yang tepercaya, pertahankan proxy dan user agent Chrome yang didukung konsisten, terapkan materi clearance berumur pendek ke cookie jar yang sama, dan verifikasi halaman target yang diinginkan. Kesalahan harus dikategorikan daripada diulang secara buta, dan rahasia tidak pernah masuk ke log atau konteks model.
Mulai implementasi yang disetujui dengan CapSolver, validasi di halaman uji terkontrol, dan tambahkan uji state, identitas, verifikasi, dan redaksi sebelum penggunaan produksi.
Gunakan AntiCloudflareTask yang telah didokumentasikan ketika halaman yang diamati cocok dengan Tantangan Cloudflare yang didukung dan target disetujui.
Ya. CapSolver mendokumentasikan proxy statis atau tetap untuk tugas ini. Pertahankan identitas jaringan yang konsisten melalui verifikasi.
html harus dimasukkan?Sertakan HTML tantangan segar ketika diperlukan oleh target. Tangkap HTML dengan proxy tetap yang sama, user agent Chrome yang didukung, cookie jar, dan URL target.
Tidak. Terapkan materi sesi yang dikembalikan ke identitas permintaan yang sama dan verifikasi bahwa halaman target yang diharapkan dimuat tanpa penanda tantangan.
Berhenti, simpan diagnostik yang direkam, dan minta ulasan operator. Jangan buat loop ulang yang tidak terbatas.
Bangun pemantauan harga properti yang andal dengan dataset resmi, observasi yang dapat dibandingkan, Penyelesaian Tantangan Cloudflare, bukti, dan peringatan yang dikendalikan.

Bangun pemantauan inventaris e-commerce yang andal dengan sumber API, pemulihan tantangan Cloudflare, konsistensi sesi, bukti persediaan, dan notifikasi aman.
