快速回答
爬虫应如何处理 403、429 和 CAPTCHA 响应?
将它们视为信号,而非障碍。在 429 时,等待 Retry-After 并降低该主机上的请求频率。遇到 403,暂停后重试一次,若仍失败则停止并检查网站规则。遇到 CAPTCHA,停止访问该主机,不要自动破解。 CrawlRelay 住宅代理,来自 US$0.50/GB,分散负载并设定位置;它们不是绕过网站限制的方法。无需 KYC。支持加密货币支付。
三种信号一览
| 429 请求过多 | 您爬取太快。遵守 Retry-After,退避,降低每主机并发请求数 |
|---|---|
| 403 禁止访问 | 请求被拒绝。暂停后重试一次,然后停止并检查 |
| CAPTCHA 或挑战页面 | 网站想确认您是否为真人。停止访问该主机并放慢速度 |
| 爬取规则规范 | robots.txt,RFC 9309;Crawl-delay 是常用扩展 |
| 我们不支持的内容 | CAPTCHA 破解,隐身插件,指纹伪装 |
每个信号对我的爬虫意味着什么?
- 429 是最礼貌的信号:内容可用,但速度过快。RFC 6585 定义了它,通常带有指明何时重试的
Retry-After头。 - 403 是请求被拒绝。可能是可修复的(地区错误,缺少 header,请求过快)或最终拒绝(网站不允许自动访问该内容)。
- CAPTCHA 或挑战页面,通常伴随 403 或 503 状态码,表示网站的反爬机制怀疑您的流量。这是比忽略的 429 更严厉的升级措施。
这三者都是递增的信号。忽略 429 后,网站会升级到 403 和挑战,最终对整个 IP 段进行长时间封禁,影响该段所有用户。
每个信号爬虫该如何应对?
| 信号 | 首次响应 | 若持续出现 | 停止条件 |
|---|---|---|---|
| 429 | 等待 Retry-After 或带随机性的指数退避 | 该主机请求数减半 | 若 Retry-After 越来越长,或 429 持续单请求返回 |
| 403 | 暂停后重试一次,同国家 | 对比同国家浏览器访问,检查 robots.txt 和条款 | 同一 URL 模式第二次出现 403 |
| CAPTCHA / 挑战 | 暂停该主机数分钟 | 以更低速率恢复 | 低速下仍出现挑战,代表网站不允许自动访问 |
| 503 携带 Retry-After | 按要求等待 | 暂停该主机 | 多数请求失败超过几分钟 |
如何构建正确响应的爬虫?
将规则放在抓取器里,而非每个爬虫。该抓取器每主机一次只发一个请求,遵守 robots.txt 及其 Crawl-delay,等待 Retry-After,连续三次拒绝后停止访问。它将 4xx robots.txt 视为允许,5xx 视为完全禁止,符合 RFC 9309 规范。
import time
import urllib.robotparser
from urllib.parse import urlsplit
import requests
PROXY = "http://USERNAME-country-us:[email protected]:7777"
USER_AGENT = "ExampleCrawler/1.0 (+https://example.com/crawler-info)"
class PoliteFetcher:
"""One request at a time per host; robots.txt, Crawl-delay and Retry-After honoured."""
def __init__(self, min_interval=1.0, max_refusals=3):
self.min_interval, self.max_refusals = min_interval, max_refusals
self.http = requests.Session()
self.http.proxies = {"http": PROXY, "https": PROXY}
self.http.headers["User-Agent"] = USER_AGENT
self.robots, self.next_time, self.refusals = {}, {}, {}
def _robots(self, root):
if root not in self.robots:
rp = urllib.robotparser.RobotFileParser(root + "/robots.txt")
try:
r = self.http.get(root + "/robots.txt", timeout=(10, 30))
if r.status_code >= 500:
rp.parse(["User-agent: *", "Disallow: /"]) # unreachable: assume disallow
else:
rp.parse(r.text.splitlines() if r.status_code == 200 else []) # 4xx: allowed
except requests.RequestException:
rp.parse(["User-agent: *", "Disallow: /"])
self.robots[root] = rp
return self.robots[root]
def get(self, url):
scheme, host = urlsplit(url)[:2]
if self.refusals.get(host, 0) >= self.max_refusals:
return None # this host said no: stop asking
rp = self._robots("%s://%s" % (scheme, host))
if not rp.can_fetch(USER_AGENT, url):
return None
delay = max(self.min_interval, rp.crawl_delay(USER_AGENT) or 0)
wait = self.next_time.get(host, 0) - time.monotonic()
if wait > 0:
time.sleep(wait)
r = self.http.get(url, timeout=(10, 30))
pause = delay
if r.status_code in (429, 503):
retry_after = r.headers.get("Retry-After", "")
pause = max(delay, int(retry_after) if retry_after.isdigit() else 60)
refused = r.status_code in (403, 429) or "captcha" in r.text[:5000].lower()
self.refusals[host] = self.refusals.get(host, 0) + 1 if refused else 0
self.next_time[host] = time.monotonic() + pause
return r
fetcher = PoliteFetcher()
resp = fetcher.get("https://example.com/")
print(resp.status_code if resp is not None else "skipped")如何合法修复 403?
部分 403 原因在您这边,修正它们是合理的:
- 地区错误。 许多网站仅对特定区域提供服务。使用
-country-<code>针对目标国家。 - 缺失 Header。 发送
Accept,Accept-Language和带联系 URL 的真实用户代理。仅 HTTP 客户端使用类浏览器 User Agent 不一致,常被拒绝。 - 请求速度过快。 N 次请求后出现 403 是速度问题,应放慢。
不能算修复的是:频繁切换 User Agent 装作不同用户、伪造浏览器指纹、或者更换 IP 以绕过网站故意设置的封禁。如果网站过滤托管 IP 段以屏蔽自动流量,使用住宅代理 IP 并不能让访问合法。
为什么不直接解决 CAPTCHA?
因为 CAPTCHA 是网站提出一个问题,而你可能会误答。自动解决会把一个礼貌的爬虫变成一个专门绕过访问控制的工具,这会增加你的法律风险:2026 年美国关于搜索抓取案件,如 Google 诉 SerpApi 和 Reddit 诉 SerpApi 等,涉及被告绕过反自动化系统违反 DMCA 的反规避条款。法院对此尚无定论,但风险是真实存在的。
CrawlRelay 不支持 CAPTCHA 解决或反机器人检测,且其可接受使用政策] 已禁止通过网关使用这些功能。如果你需要访问受挑战保护的数据,请向网站申请访问权限,使用其 API,或许可数据。
我什么时候应该联系网站?
当你需要超过网站默认允许的访问时。许多网站提供 API、数据源、合作伙伴计划,或者对能够自报身份并说明用途的爬虫提高限制。在你的用户代理里放入联系 URL,保持公开一页介绍你的爬虫和退出方式,及时响应滥用报告。能被联系的爬虫在被封锁前会收到警告。
403,429 和 CAPTCHA:常见问题
住宅代理能阻止 CAPTCHA 吗?
别指望它。住宅出口 IP 会改变网站看到的 IP,而不是你的爬虫行为:因请求频率或行为而触发的 CAPTCHA 依然存在,这是网站的本意。如果低频请求仍被挑战,说明网站不欢迎自动访问该内容。
如果 429 状态码没有 Retry-After,我该等多久?
从几秒开始,遇到每个新的429时将等待时间翻倍,同时加一点随机延迟,最多等约一分钟。当请求恢复成功,按触发 429 前的较低频率恢复爬取,随后在错误率稳定时慢慢提高速率。
轮换 IP 来规避速率限制允许吗?
轮换有助于分散负载并选择不同地区,是正常做法。但用轮换来维持低于单 IP 限制的请求频率,同时保持网站拒绝的速率,是规避手段。大多数使用条款禁止此行为,我们的可接受使用政策也禁止。
我的爬虫应该发送什么用户代理?
用你自己的:包含名字、版本和可说明爬虫及联系方式的 URL,例如 ExampleCrawler/1.0 (+https://example.com/crawler-info)。不要用其他爬虫的名字,比如 Googlebot 或 GPTBot。
来源 (4)
- RFC 9309:机器人排除协议 — IETF (2022-09)
- RFC 6585:新增 HTTP 状态码(429) — IETF (2012-04)
- Reddit 诉 SerpApi LLC 案件 — Loeb & Loeb (2026-08)
- Google 诉 SerpApi 案件:法院同意我们的撤诉请求 — SerpApi (2026-07-21)
礼貌爬虫的住宅代理
US$1.50,1 GB起,US$0.50/GB从50 GB起。