为什么CAPTCHAs 是史克威尔最大的障碍
CAPTCHA存在以区分人类和bots,它们对此越来越有效. 当您的刮刮器遇到CAPTCHA时,这意味着目标站点已经检测到自动化行为——您的请求频率太高,IP信任度低,或者您的浏览器指纹看起来可疑. 最佳的CAPTCHA战略是预防而不是解决.
本指南涵盖了您将遇到的CAPTCHA类型,为什么预防比解决更有效、更便宜,以及代理如何在完全避免CAPTCHA方面发挥关键作用。
这篇文章是我们 完整网页搜索代理指南 丛书。 关于了解探测系统,见 反毒系统如何检测代理。 。 。
2026年CAPTCHA类型
| 类型 | 如何运作 | 绕行困难 |
|---|---|---|
| reCAPTCHA v2(复选框) | 点击“ 我不是机器人” + 可选图像挑战 | 中型 |
| reCAPTCHA v3(隐形) | 没有用户互动的分数行为 0.0-1.0 | 难 |
| h Captcha (美国) | 图像选择挑战( 类似于 reCAPTCHA v2) | 中型 |
| 云浮转弯 | 浏览器挑战, 通常是隐形的 | 难 |
| 自定义图像 CAPTCHAs | 特定地点的挑战(扭曲文本、谜题) | 变量 |
| 工作证明 | 浏览器必须计算散列( Cloudflare Under attack) | 中型 |
隐形CAPTCHA 真正的威胁
最危险的CAPTCHA是那些你从未见过的。 (原始内容存档于2019-03-03). reCAPTCHA v3 和 云浮转弯 在背景中运行,分析鼠标运动,滚动行为,打字模式,以及浏览器环境. 它们在不显示任何挑战的情况下分配一个信任分数——如果分数过低,则请求会静默地被阻断或重定向.
预防与解决:为什么预防胜利
| 方针 | 每笔费用 | 速度 | 可靠性 | 可缩放性 |
|---|---|---|---|---|
| 预防(没有触发CAPTCHA) | 0美元 (单位:美元) | 即时 | 最高 | 不错 |
| CAPTCHA 解决服务 | 每1 000美元-3美元 | 10-60秒 | 85-95% (单位:千美元) | 中调 |
| 基于AI的自动解析 | 每1 000美元2-5美元 | 5-30秒 | 70%-90% | 有限 |
在规模上,预防既节省金钱又节省时间。 每天解决10万个CAPTCHA需要100-500美元,并增加休息时间。 防止它们除了适当的代理和请求管理之外,别无其他代价。
预防战略1:使用高质量的住宅代用品
一项最有效的CAPTCHA预防措施是使用信任率高的住宅代管。 住宅IP是由ISP分配给真实家庭的,因此网站无法轻易区分您的请求与真实用户流量.
import requests
# Residential proxy — high trust score, fewer CAPTCHAs
PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
def scrape_with_residential(url: str) -> str:
"""Use residential proxies to avoid triggering CAPTCHAs."""
session = requests.Session()
session.proxies = {"http": PROXY, "https": PROXY}
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
})
resp = session.get(url, timeout=30)
return resp.textProxyHat的住宅池提供来自真实的ISP的IP. 190多个国家,给予每个请求最高的信任分。 见 住宅对数据中心 详细比较一下
预防战略2:实事求是的要求模式
CAPTCHA经常由机器人行为模式引发,而不仅仅是IP的声誉. 让你的刮刀看起来像人:
Python 执行
import requests
import random
import time
PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
USER_AGENTS = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Safari/605.1.15",
]
REFERRERS = [
"https://www.google.com/",
"https://www.bing.com/",
"https://duckduckgo.com/",
None, # Direct visit
]
def human_like_scrape(urls: list[str]) -> list[str]:
"""Scrape with realistic human behavior patterns."""
results = []
session = requests.Session()
session.proxies = {"http": PROXY, "https": PROXY}
for url in urls:
# Randomize headers per request
headers = {
"User-Agent": random.choice(USER_AGENTS),
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1",
}
referrer = random.choice(REFERRERS)
if referrer:
headers["Referer"] = referrer
try:
resp = session.get(url, headers=headers, timeout=30)
results.append(resp.text)
except requests.RequestException:
results.append(None)
# Human-like delays: 1-5 seconds with occasional longer pauses
if random.random() < 0.1:
time.sleep(random.uniform(5, 15)) # 10% chance of long pause
else:
time.sleep(random.uniform(1, 4))
return results节点.js 执行
const HttpsProxyAgent = require('https-proxy-agent');
const fetch = require('node-fetch');
const agent = new HttpsProxyAgent('http://USERNAME:PASSWORD@gate.proxyhat.com:8080');
const USER_AGENTS = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0',
];
function randomDelay() {
const isLongPause = Math.random() < 0.1;
const ms = isLongPause
? 5000 + Math.random() * 10000
: 1000 + Math.random() * 3000;
return new Promise(r => setTimeout(r, ms));
}
async function humanLikeScrape(urls) {
const results = [];
for (const url of urls) {
const headers = {
'User-Agent': USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)],
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
};
try {
const res = await fetch(url, { agent, headers, timeout: 30000 });
results.push(await res.text());
} catch {
results.push(null);
}
await randomDelay();
}
return results;
}预防战略3:聪明的知识产权轮换
您旋转IP的方式直接影响 CAPTCHA 费率 。 主动旋转(每个请求新IP)实际上可以增加一些站点的CAPTCHA,因为访问同一会话路径的不同IP的一系列请求看起来很可疑.
import requests
import uuid
def create_session_for_site(site_id: str):
"""Create a sticky session that maintains the same IP per site.
This avoids the suspicious pattern of different IPs accessing the same flow."""
session_id = uuid.uuid5(uuid.NAMESPACE_URL, site_id).hex[:8]
proxy = f"http://USERNAME-session-{session_id}:PASSWORD@gate.proxyhat.com:8080"
session = requests.Session()
session.proxies = {"http": proxy, "https": proxy}
return session
# Same IP for all requests to a specific product section
session = create_session_for_site("example.com-electronics")
page1 = session.get("https://example.com/electronics?page=1")
page2 = session.get("https://example.com/electronics?page=2")
page3 = session.get("https://example.com/electronics?page=3")
# Different IP for a different section
session2 = create_session_for_site("example.com-clothing")
clothes1 = session2.get("https://example.com/clothing?page=1")关于更多的旋转模式,见 大型碎屑代用旋转策略。 。 。
预防战略4:尊重率限制
CAPTCHA往往是利率限制之后的升级. 如果正确处理速率限制信号,则很少看到CAPTCHAs:
import requests
import time
PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
CAPTCHA_INDICATORS = [
"captcha",
"recaptcha",
"hcaptcha",
"challenge",
"verify you are human",
"please complete the security check",
]
def is_captcha_page(html: str) -> bool:
"""Detect if the response is a CAPTCHA challenge page."""
html_lower = html.lower()
return any(indicator in html_lower for indicator in CAPTCHA_INDICATORS)
def scrape_with_captcha_detection(urls: list[str]) -> list[dict]:
results = []
session = requests.Session()
session.proxies = {"http": PROXY, "https": PROXY}
captcha_count = 0
backoff = 2.0
for url in urls:
try:
resp = session.get(url, timeout=30)
if resp.status_code == 200 and not is_captcha_page(resp.text):
results.append({"url": url, "status": "success", "body": resp.text})
captcha_count = 0
backoff = max(backoff * 0.9, 1.0) # Reduce backoff on success
elif is_captcha_page(resp.text) or resp.status_code == 403:
captcha_count += 1
results.append({"url": url, "status": "captcha"})
if captcha_count >= 3:
# Too many CAPTCHAs — increase backoff significantly
backoff = min(backoff * 3, 60)
print(f"CAPTCHA streak: {captcha_count}. Backing off to {backoff:.0f}s")
else:
backoff = min(backoff * 1.5, 30)
except requests.RequestException as e:
results.append({"url": url, "status": "error", "error": str(e)})
time.sleep(backoff)
return results综合税率限制战略见 速率限制解释。 。 。
当您必须处理 CAPTCHA : 检测和运行
即使有完美的预防,一些CAPTCHA也是不可避免的. 在您的管道中建立检测功能, 这样您就可以通过 CAPTCHA 页面进行特殊处理 :
import requests
from enum import Enum
PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
class ResponseType(Enum):
SUCCESS = "success"
CAPTCHA = "captcha"
BLOCKED = "blocked"
ERROR = "error"
def classify_response(resp: requests.Response) -> ResponseType:
"""Classify a response to determine next action."""
if resp.status_code == 403:
return ResponseType.BLOCKED
if resp.status_code == 429:
return ResponseType.BLOCKED
if resp.status_code == 200:
html = resp.text.lower()
captcha_signals = ["captcha", "recaptcha", "hcaptcha", "cf-challenge"]
if any(s in html for s in captcha_signals):
return ResponseType.CAPTCHA
return ResponseType.SUCCESS
return ResponseType.ERROR
def scrape_with_routing(urls: list[str]) -> dict:
"""Scrape URLs and route based on response classification."""
session = requests.Session()
session.proxies = {"http": PROXY, "https": PROXY}
results = {"success": [], "captcha": [], "blocked": [], "error": []}
for url in urls:
try:
resp = session.get(url, timeout=30)
response_type = classify_response(resp)
results[response_type.value].append(url)
if response_type == ResponseType.CAPTCHA:
# Route to CAPTCHA queue for manual or service-based solving
print(f"CAPTCHA detected: {url}")
elif response_type == ResponseType.BLOCKED:
# Rotate IP and retry
print(f"Blocked: {url}")
except requests.RequestException:
results["error"].append(url)
print(f"Success: {len(results['success'])}, "
f"CAPTCHAs: {len(results['captcha'])}, "
f"Blocked: {len(results['blocked'])}")
return resultsCAPTCHA 预防清单
- 使用住宅代理. 他们的信用分数最高 引发的CAPTCHA最少. 代理哈特住宅代理 提供数百万个干净的IP.
- 设定现实的页眉 。 总是发送用户代理,接受,接受-语言,以及其他标准浏览器头.
- 加上人类般的延迟. 请求之间随机1-5秒的延迟,偶尔会有较长的暂停.
- 正确维持会话 通过粘度会话对相关请求使用 cookie 和一致的IP.
- 敬重机器人. txt. (中文(简体) ). 检测机器人.txt违规的站点升级为CAPTCHA更快.
- 监测CAPTCHA的费率。 如果你的CAPTCHA率超过5%, 你的方法中的东西需要修复。
- 避免在高峰时段刮刮。 反机器人系统在高流量期间更具攻击性.
- 正确旋转用户代理 。 使用最近现实的浏览器字符串 。 在同一会话上不要混合移动和桌面 UA 。
关于您首选语言的代理设置,请参见 在 Python 中使用代理, (中文). 使用节点中的代理,或 使用 Go 中的代理探索 网页搜索的代理用户名 开始吧
经常被问到的问题
代理可以帮助避免CAPTCHAs吗?
是的,相当重要。 优质住宅代理拥有干净的IP声誉,很少触发CAPTCHA. Datacenter IP更常被标记,因为它们是已知的自动化源. 住宅代用品与适当要求模式相结合,几乎消除了大多数目标的CAPTCHA。
什么是最便宜的方法 处理CAPTCHA的规模?
预防。 投资住宅代用品和适当报废模式的成本远低于CAPTCHA规模的解决服务. 如果您必须解决CAPTCHA,第三方服务费用为每1000美元1-3美元,但每个请求增加10-60秒的延迟.
无头浏览器是否帮助 CAPTCHA ?
它们通过JavaScript执行提供真实的浏览器环境来帮助隐形CAPTCHAs(reCAPTCHA v3,Turnstile). 然而,它们的速度较慢,而且资源更密集。 仅用于特定需要浏览器级验证的目标.
我怎么知道我是否有CAPTCHA的页面?
请检查access-date=中的日期值 (帮助) CAPTCHA指标的响应HTML:"captcha","captcha","hcaptcha","挑战",或"验证你是人类". 同时注意403个出乎意料的反应,并重新定向以挑战URL. 将自动探测器安装到您的刮刮管道中。
为什么我仍然得到 CAPTCHA 与住宅代理?
通常是因为请求模式,而不是IP质量. 常见原因:每分钟请求过多,浏览器头缺失,饼干处理问题,或刮刮模式过于系统化. 慢下来, 添加焦躁, 并且对相关请求使用粘度会话 。






