返回博客

如何将网页抓取的封禁率降低到5%:12种有效的保护方法

我们分析了12种经过验证的降低爬虫封禁率的方法:从代理设置到模拟真实用户行为。提供实际案例和现成解决方案。

📅2026年2月10日
```html

如果您从事电商平台爬取、竞争对手价格监控或网站数据采集,那么您一定了解这个问题:网站会封禁IP地址、要求验证码或返回空白页面。封禁率(被封禁请求的百分比)可能达到70-90%,这使得爬取变得不可能。本文将介绍具体方法,帮助您将封禁率降低到5-10%并稳定地采集数据。

我们将探讨技术解决方案(代理轮换、HTTP头、指纹识别)以及行为模式(延迟、模拟用户操作)。所有方法都在爬取Wildberries、Ozon、Avito和国外平台时经过实践验证。

网站为何封禁爬虫:主要触发因素

在探讨防护方法之前,重要的是要理解网站如何识别自动化流量。现代反机器人系统(Cloudflare、Akamai、DataDome、Imperva)会分析每个请求的数十个参数。以下是主要的封禁触发因素:

网络层面的触发因素:

  • 来自单个IP地址的请求过多(例如,每分钟100+请求)
  • 来自已知数据中心IP段的IP(AWS、Google Cloud、Hetzner)
  • 地理位置不匹配:来自俄罗斯的IP请求英文版网站
  • IP地址缺少反向DNS记录

HTTP层面的触发因素:

  • 缺少或错误的HTTP头(User-Agent、Accept-Language、Referer)
  • 头部顺序与浏览器标准不同
  • TLS/SSL版本与声明的浏览器不匹配
  • 缺少cookie或使用不正确

浏览器层面的触发因素(JavaScript):

  • 未执行JavaScript(如果使用简单的HTTP客户端)
  • 浏览器指纹识别:Canvas、WebGL、AudioContext、已安装字体
  • 缺少鼠标移动、滚动、点击
  • 浏览器窗口大小(无头浏览器通常具有非标准尺寸)
  • 存在自动化特征:navigator.webdriver、window.chrome属性

行为触发因素:

  • 页面间导航过快(少于1秒)
  • 请求间隔相同(例如,恰好每2秒)
  • 顺序浏览页面(1、2、3、4...)无跳过
  • 缺少典型用户操作:搜索、筛选、查看图片

例如,在爬取Wildberries时,典型错误是从单个IP每0.5秒发送请求。Cloudflare反机器人系统会立即识别模式并将IP封禁24小时。真实用户会花5-15秒查看商品卡片、滚动页面、点击图片。

代理轮换:如何正确更换IP地址

使用代理是降低封禁率的基本方法。但重要的不仅是购买代理,还要正确配置轮换。以下是经过验证的策略:

选择爬取代理类型

代理类型 封禁率 速度 使用场景
数据中心代理 高(40-60%) 非常高 无防护的简单网站,大IP池的批量爬取
住宅代理 低(5-15%) 中等 电商平台(Wildberries、Ozon)、带Cloudflare的网站、社交网络
移动代理 非常低(2-8%) 具有激进防护的网站、移动应用程序

对于电商平台爬取(Wildberries、Ozon、Avito),推荐使用住宅代理——它们拥有真实家庭用户的IP,难以与普通流量区分。数据中心代理适用于防护较弱的网站或需要大数据量时的最高速度。

IP地址轮换策略

策略1:按时间轮换

每5-10分钟更换IP。这是最佳平衡:足够长以避免频繁更换引起怀疑,但足够频繁以避免在单个IP上累积请求历史。

示例: 爬取1000个商品的目录,请求间隔3秒,一个IP将活跃约100个请求,然后进行更换。

策略2:按请求数量轮换

每50-150个请求后更换IP。这有助于避免在单个地址上累积可疑活动。添加随机性:不是恰好100个请求,而是80到120个。

示例: 配置脚本,使其在随机数量的请求(80-120)后从池中轮换代理。

策略3:粘性会话(会话代理)

对于需要授权或使用购物车的网站,使用粘性会话——在会话期间(10-30分钟)固定IP。这允许保留cookie,并且不会在单个会话内更换IP时引起怀疑。

示例: 在Ozon上爬取个人账户时,使用一个IP进行登录和15分钟会话内的所有后续请求。

重要: 不要将同一IP用于不同任务。如果IP在爬取一个网站时被封禁,不要立即将其用于另一个网站——等待24-48小时。

代理池大小

最小池大小取决于爬取强度:

  • 低强度(每天最多10,000个请求):10-20个代理
  • 中等强度(每天10,000-100,000个请求):50-100个代理
  • 高强度(每天超过100,000个请求):200+个代理或带自动轮换的住宅代理

对于每个请求轮换的住宅代理(轮换代理),池大小可以更小,因为提供商会自动从其数百万地址池中替换新IP。

User-Agent和HTTP头:模拟真实浏览器

即使使用良好的代理,如果HTTP头看起来可疑,您也可能被封禁。网站不仅分析User-Agent,还分析头部顺序、它们的值以及彼此之间的对应关系。

正确的User-Agent

不要对所有请求使用相同的User-Agent。创建一个流行浏览器列表并随机选择:

user_agents = [
    # Windows上的Chrome
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    # macOS上的Chrome
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    # Windows上的Firefox
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
    # macOS上的Safari
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15",
    # Windows上的Edge
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0"
]

错误: 使用过时的浏览器版本(例如Chrome 80)——这会立即引起怀疑。每2-3个月更新一次User-Agent列表,在whatismybrowser.com上跟踪当前版本。

完整的HTTP头集合

现代浏览器发送15-20个头部。以下是模拟Chrome的最小必需集合:

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    "Accept-Language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
    "Accept-Encoding": "gzip, deflate, br",
    "DNT": "1",
    "Connection": "keep-alive",
    "Upgrade-Insecure-Requests": "1",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "none",
    "Sec-Fetch-User": "?1",
    "Cache-Control": "max-age=0",
    "sec-ch-ua": '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": '"Windows"'
}

注意Sec-Fetch-*sec-ch-ua-*头部——它们出现在新版Chrome中,缺少它们可能暴露自动化。

头部顺序很重要

浏览器以特定顺序发送头部。例如,Chrome总是将Host放在第一位,然后是ConnectionUser-Agent等。如果您使用Python的requests库,顺序可能是字母顺序,这会暴露自动化。

解决方案:使用正确格式化头部的库(Python的curl_cffi,Node.js的got)或无头浏览器(Puppeteer、Playwright、Selenium),它们像真实浏览器一样生成头部。

请求间延迟:最佳间隔

降低封禁率最简单但最有效的方法之一是请求间的正确延迟。真实用户无法每秒打开10个页面,因此过快的请求会立即导致封禁。

随机延迟而非固定延迟

不要使用固定延迟(例如,请求间恰好2秒)。反机器人系统很容易识别这种模式。使用随机间隔:

import random
import time

# 不要使用固定延迟
time.sleep(2)  # ❌ 不好

# 使用随机间隔
delay = random.uniform(2.5, 5.5)  # ✅ 好
time.sleep(delay)

不同网站的推荐间隔

网站类型 最小延迟 推荐延迟 示例
有防护的电商平台 3-5秒 5-10秒 Wildberries、Ozon、Lamoda
分类广告网站 2-4秒 4-8秒 Avito、Yula、CIAN
新闻网站 1-2秒 2-4秒 RBC、Kommersant、Vedomosti
无限制的API 0.5-1秒 1-2秒 开放API、RSS源

基于服务器响应的自适应延迟

高级方法——根据服务器响应动态更改延迟:

base_delay = 3.0  # 基础延迟
delay_multiplier = 1.0

response = requests.get(url, headers=headers, proxies=proxies)

# 如果收到验证码或429——增加延迟
if response.status_code == 429 or 'captcha' in response.text.lower():
    delay_multiplier *= 1.5
    print(f"检测到防护,增加延迟至{base_delay * delay_multiplier}秒")

# 如果一切正常——可以稍微加速
elif response.status_code == 200:
    delay_multiplier = max(1.0, delay_multiplier * 0.95)

time.sleep(random.uniform(base_delay * delay_multiplier, base_delay * delay_multiplier * 1.5))

这种方法允许在检测到防护时自动减速,在网站不显示攻击性时加速。

防指纹识别:Canvas、WebGL、字体

如果网站使用JavaScript进行检查,简单的HTTP头是不够的。现代反机器人系统基于数十个参数创建浏览器"指纹":Canvas、WebGL、已安装字体、时区、屏幕分辨率等。

指纹识别的主要参数

Canvas指纹识别

网站在Canvas中绘制不可见图像并读取它。不同的浏览器和操作系统以不同方式渲染图像,创建唯一指纹。无头浏览器通常生成相同的Canvas,这会暴露自动化。

WebGL指纹识别

类似于Canvas,但使用3D渲染。读取有关显卡、驱动程序、支持的扩展的信息。无头浏览器通常显示软件渲染(SwiftShader)而不是真实GPU。

已安装字体

JavaScript可以确定已安装字体列表。无头浏览器通常具有最小的系统字体集,这与安装了Microsoft Office、Adobe和其他程序的真实用户不同。

Navigator属性

navigator.webdriver、navigator.plugins、navigator.languages属性会暴露自动化。例如,在Selenium中navigator.webdriver === true,这会被反机器人系统立即检测到。

绕过指纹识别的工具

要绕过指纹识别,请使用专用工具:

  • Undetected ChromeDriver(Python)——隐藏自动化迹象的修改版Selenium
  • Puppeteer Stealth(Node.js)——替换指纹参数的Puppeteer插件
  • 带stealth的Playwright——类似于Puppeteer,但对不同浏览器有更好的支持
  • 反检测浏览器(Dolphin Anty、AdsPower、Multilogin)——对于不想编写代码的人,这些浏览器会自动替换指纹

在Python中使用undetected-chromedriver的示例:

import undetected_chromedriver as uc

# 创建具有防检测保护的浏览器
options = uc.ChromeOptions()
options.add_argument('--disable-blink-features=AutomationControlled')

driver = uc.Chrome(options=options)
driver.get('https://example.com')

# 检查navigator.webdriver === undefined
webdriver_status = driver.execute_script("return navigator.webdriver")
print(f"navigator.webdriver: {webdriver_status}")  # 应该是None/undefined

Cookie和会话管理

许多网站使用cookie来跟踪用户行为。正确管理cookie有助于避免封禁并看起来像真实用户。

保存和重用cookie

不要在每个请求上创建新会话,而是保存cookie并重复使用它们。这模拟了返回网站的真实用户的行为:

import requests
import pickle

session = requests.Session()

# 首次访问——获取cookie
response = session.get('https://example.com')

# 将cookie保存到文件
with open('cookies.pkl', 'wb') as f:
    pickle.dump(session.cookies, f)

# 稍后加载cookie
with open('cookies.pkl', 'rb') as f:
    session.cookies.update(pickle.load(f))

# 现在请求看起来像来自返回的用户
response = session.get('https://example.com/catalog')

爬取前预热会话

不要立即从目标页面开始爬取。模拟真实用户行为:

  1. 打开网站主页
  2. 等待2-5秒
  3. 打开类别或部分页面
  4. 等待3-7秒
  5. 只有在此之后才开始爬取目标页面

这在cookie中创建活动历史并降低封禁概率。

处理会话cookie和令牌

一些网站在首次访问时生成唯一令牌,并在后续请求中检查它们。例如,Wildberries在x-requested-with头中使用令牌。始终从第一个响应中保存此类令牌并在后续请求中发送它们。

JavaScript渲染:何时需要

许多现代网站通过JavaScript加载内容。如果您使用简单的HTTP客户端(Python中的requests,Node.js中的axios),您将获得空白页面或占位符。在这种情况下,需要JavaScript渲染。

何时需要JavaScript渲染

  • 网站使用React、Vue、Angular——内容在初始页面加载后加载
  • 数据通过AJAX/Fetch请求加载
  • 网站需要执行JavaScript来生成令牌或cookie
  • 存在需要执行JS代码的反机器人保护(例如Cloudflare Challenge)

JavaScript渲染工具

工具 语言 速度 绕过防护
Selenium Python、Java、C# 中等(使用undetected-chromedriver)
Puppeteer Node.js 中等 好(使用puppeteer-extra-plugin-stealth)
Playwright Python、Node.js、Java 优秀
Splash HTTP API 中等

对于大多数任务,推荐使用Playwright——它比Selenium更快,更好地绕过防护,并且具有更方便的API。

替代方案:拦截API请求

通常可以避免JavaScript渲染,如果找到网站用于加载数据的API请求。打开DevTools(F12)→ Network选项卡→ XHR/Fetch过滤器,查看网站发送的请求。然后通过HTTP客户端直接重复这些请求。

示例:Wildberries通过API https://catalog.wb.ru/catalog/...加载商品数据。不是渲染整个页面,而是可以直接请求此API,这快10-20倍。

绕过验证码:自动化解决方案

即使使用正确的代理和头部,您也可能遇到验证码。有几种解决方法:

验证码类型和解决方法

reCAPTCHA v2(复选框"我不是机器人")

通过识别服务解决:2Captcha、Anti-Captcha、CapMonster。成本:每1000次解决$1-3。解决时间:10-30秒。

reCAPTCHA v3(不可见,基于评分)

更复杂。分析用户行为并给出0到1的评分。绕过:使用具有正确指纹的无头浏览器+模拟用户操作(鼠标移动、点击)。

hCaptcha

reCAPTCHA的类似物,在许多网站上使用。通过相同的识别服务解决。成本:每1000次解决$0.5-2。

Cloudflare Challenge

检查浏览器的JavaScript挑战。绕过:使用专用库(Python的cloudscraper,Node.js的cloudflare-scraper)或服务(FlareSolverr)。

集成验证码识别服务

在Python中集成2Captcha的示例:

from twocaptcha import TwoCaptcha

solver = TwoCaptcha('YOUR_API_KEY')

try:
    # 解决reCAPTCHA v2
    result = solver.recaptcha(
        sitekey='6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-',
        url='https://example.com'
    )
    
    # 获取解决令牌
    captcha_token = result['code']
    
    # 使用令牌提交表单
    response = requests.post('https://example.com/submit', data={
        'g-recaptcha-response': captcha_token
    })
    
except Exception as e:
    print(f"验证码解决错误: {e}")

重要: 解决验证码会使爬取速度减慢10-30倍并增加成本。仅在其他方法不起作用时使用。首先尝试改进代理、指纹和延迟。

速率限制:如何不超过网站限制

许多网站对请求数量有明确或隐含的限制。超过这些限制会导致临时或永久封禁IP。

确定网站限制

注意服务器响应中的HTTP头:

  • X-RateLimit-Limit——期间内的最大请求数
  • X-RateLimit-Remaining——剩余请求数
  • X-RateLimit-Reset——限制何时重置(Unix时间戳)
  • Retry-After——多少秒后可以重试请求

如果您收到状态码429(请求过多),这意味着超过了限制。读取Retry-After头并在下一个请求之前等待指定时间。

实现速率限制器

创建请求速度控制机制:

import time
from collections import deque

class RateLimiter:
    def __init__(self, max_requests, time_window):
        self.max_requests = max_requests  # 时间窗口内的最大请求数
        self.time_window = time_window    # 时间窗口(秒)
        self.requests = deque()
    
    def wait_if_needed(self):
        now = time.time()
        
        # 删除时间窗口外的旧请求
        while self.requests and self.requests[0] < now - self.time_window:
            self.requests.popleft()
        
        # 如果达到限制——等待
        if len(self.requests) >= self.max_requests:
            sleep_time = self.time_window - (now - self.requests[0])
            if sleep_time > 0:
                print(f"达到速率限制,等待{sleep_time:.2f}秒")
                time.sleep(sleep_time)
                self.requests.popleft()
        
        # 记录新请求
        self.requests.append(time.time())

# 使用:每分钟最多60个请求
limiter = RateLimiter(max_requests=60, time_window=60)

for url in urls:
    limiter.wait_if_needed()
    response = requests.get(url)

监控指标:跟踪封禁率

要了解您的防护方法是否有效,需要监控关键指标。以下是应该跟踪的内容:

关键指标

封禁率(Ban Rate)

被封禁请求占总请求的百分比。计算方式:(被封禁请求数/总请求数)× 100%。目标:低于10%,理想情况下低于5%。

验证码率(Captcha Rate)

遇到验证码的请求百分比。高验证码率(>20%)表示需要改进指纹或代理质量。

成功率(Success Rate)

返回有效数据的请求百分比。应该高于90%。如果更低——检查页面结构是否改变或防护是否加强。

平均响应时间

帮助识别慢速代理或服务器过载。如果响应时间突然增加——可能是网站开始限制您的请求。

实现监控

简单的监控实现示例:

import time
from collections import defaultdict

class ScraperMetrics:
    def __init__(self):
        self.total_requests = 0
        self.successful_requests = 0
        self.blocked_requests = 0
        self.captcha_requests = 0
        self.response_times = []
        self.status_codes = defaultdict(int)
    
    def record_request(self, status_code, response_time, has_captcha=False, is_blocked=False):
        self.total_requests += 1
        self.status_codes[status_code] += 1
        self.response_times.append(response_time)
        
        if is_blocked:
            self.blocked_requests += 1
        elif has_captcha:
            self.captcha_requests += 1
        elif status_code == 200:
            self.successful_requests += 1
    
    def get_stats(self):
        if self.total_requests == 0:
            return "没有请求"
        
        ban_rate = (self.blocked_requests / self.total_requests) * 100
        captcha_rate = (self.captcha_requests / self.total_requests) * 100
        success_rate = (self.successful_requests / self.total_requests) * 100
        avg_response_time = sum(self.response_times) / len(self.response_times)
        
        return f"""
        总请求数: {self.total_requests}
        成功率: {success_rate:.2f}%
        封禁率: {ban_rate:.2f}%
        验证码率: {captcha_rate:.2f}%
        平均响应时间: {avg_response_time:.2f}秒
        状态码分布: {dict(self.status_codes)}
        """

# 使用
metrics = ScraperMetrics()

for url in urls:
    start_time = time.time()
    response = requests.get(url)
    response_time = time.time() - start_time
    
    is_blocked = response.status_code in [403, 429]
    has_captcha = 'captcha' in response.text.lower()
    
    metrics.record_request(response.status_code, response_time, has_captcha, is_blocked)

print(metrics.get_stats())

爬取工具比较

选择正确的工具可以显著影响封禁率。以下是流行解决方案的比较:

工具 复杂度 封禁率 速度 最佳用途
Requests + BeautifulSoup 高(40-70%) 非常快 简单静态网站,API
Scrapy 中等 中等(20-40%) 大规模爬取,需要结构化
Selenium + undetected-chromedriver 中等 低(10-20%) 需要JS的网站,复杂交互
Playwright 中等 非常低(5-15%) 中等 现代SPA,强防护
商业API(ScraperAPI、Bright Data) 非常低 非常低(2-10%) 预算充足,需要稳定性

推荐组合

对于大多数任务,最佳方法是组合使用:

  1. 第一阶段: 使用浏览器DevTools分析网站,查找API端点
  2. 第二阶段: 如果找到API——使用requests + 住宅代理直接请求
  3. 第三阶段: 如果需要JS——使用Playwright + 代理轮换
  4. 第四阶段: 如果遇到验证码——集成2Captcha或类似服务

结论

降低网页爬取中的封禁率需要综合方法。没有单一的"银弹"——您需要结合多种技术:

关键要点:

  • 使用高质量的住宅或移动代理,而不是数据中心代理
  • 正确配置HTTP头,包括新的Sec-Fetch-*和sec-ch-ua-*
  • 实现随机延迟(3-10秒),而不是固定间隔
  • 使用Playwright或undetected-chromedriver进行JS渲染
  • 在爬取前预热会话,模拟真实用户行为
  • 监控指标(封禁率、验证码率、成功率)并调整策略
  • 实现速率限制器以不超过网站限制
  • 仅在必要时使用验证码解决服务

从简单方法开始(良好的代理+正确的头部+延迟),并在需要时逐步添加复杂性。在大多数情况下,这足以将封禁率降低到5-10%并稳定地采集数据。

记住,网站不断改进其防护,因此定期更新您的方法并监控指标变化非常重要。今天有效的方法明天可能需要调整。

重要提示: 始终遵守网站的robots.txt和使用条款。网页爬取应该合乎道德并遵守法律。如果网站明确禁止自动化数据收集,请寻找替代方案或联系网站所有者获取官方API访问权限。

```