经典情况:用于监控Wildberries或Ozon价格的脚本在家用笔记本电脑上运行良好,但在转移到VPS后开始收到403、验证码或即时IP禁止。开发者更改了请求头,增加了延迟——但结果没有改变。问题几乎从来不在于解析器的代码本身,而在于它发出请求的环境。我们分析了7个具体原因以及需要更改的内容,以确保解析器在服务器上稳定运行。
为什么本地一切正常,而在服务器上却被禁止
当您从家用计算机启动解析器时,网站会看到来自您提供商的普通住宅IP地址的请求,来自熟悉的区域,并且如果您使用Selenium或Playwright与真实配置文件,则具有真实的浏览器环境。一旦相同的脚本迁移到德国、荷兰或美国的VPS,情况就完全改变了:IP属于数据中心,TLS指纹可能因库版本不同而有所不同,服务器的时区与IP的地理位置不符,并且请求频率急剧增加,因为服务器24/7不间断运行。
Wildberries、Ozon、Avito和大多数大型市场的反机器人系统早已不再仅仅关注User-Agent。它们分析数十个信号的组合:IP类型、请求的速度和规律性、页面行为、请求头和TLS参数的匹配、cookies的存在和会话历史。当地机器在大多数方面偶然通过检查,而服务器几乎在所有方面都失败。下面是每个原因的详细分析。
原因1:数据中心的IP而非住宅IP
这是80%情况下的第一原因。VPS和云服务器(AWS、DigitalOcean、Hetzner、普通VDS托管)的IP地址位于数据中心的数据库中——这些提供商的ASN是公开的,并被反机器人系统用于即时过滤流量。市场主要使用这些列表,因为95%的自动化解析都是来自服务器IP。
解决方案是使用在视觉上与普通互联网用户无异的IP。对于Wildberries、Ozon和Avito的解析,最适合使用住宅代理:这些是真实的家庭提供商的IP地址,分配给普通用户。反机器人系统将这样的请求视为来自真实用户的流量,而不是来自数据中心的服务器,这立即消除了大部分阻止。
原因2:没有IP轮换和请求频率限制
在本地机器上,您在测试期间手动发出20-50个请求,而网站对此并没有注意。在服务器上,脚本每5分钟通过cron运行一次,并从一个IP连续处理数千个商品卡片。这样的模式是反机器人系统的直接信号:真实的人不可能在没有任何暂停的情况下在一个小时内打开3000个目录页面。
需要在代理池上实施IP轮换,并限制每个地址在单位时间内的请求数量。实际规则是:每分钟从一个IP发出的请求不超过30-60个,对于商品卡片,在每批请求后自动更换地址。以下是通过代理池在Python中设置轮换的示例:
import requests
proxies_pool = [
"http://user:[email protected]:9000",
"http://user:[email protected]:9001",
"http://user:[email protected]:9002",
]
def get_page(url, session_id):
proxy = proxies_pool[session_id % len(proxies_pool)]
resp = requests.get(
url,
proxies={"http": proxy, "https": proxy},
headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"},
timeout=10
)
return resp.text
在每天收集大量商品卡片时,最好使用按请求或定时自动轮换IP的代理——这消除了手动维护地址列表的必要性。
原因3:请求头和User-Agent与浏览器不相似
许多基于requests或aiohttp的解析器发送的请求只包含最小的请求头集,或者使用库的标准User-Agent,这立即暴露了脚本(例如python-requests/2.31.0)。在本地机器上,通过浏览器的请求头集是完整的:Accept、Accept-Language、Accept-Encoding、Sec-Ch-Ua、Referer等——它们的组合看起来是自然的。
需要复制真实浏览器的完整请求头集,包括发送顺序——一些反机器人系统甚至会检查这一点。此外,重要的是与TLS指纹版本同步轮换User-Agent(见下一个要点),否则浏览器头与真实TLS客户端之间的不匹配将成为新的机器人信号。
原因4:TLS/JA3指纹显示为脚本
这是一个不太为人所知但非常常见的原因,尤其是在服务器上被禁止。requests、urllib、aiohttp库使用其TLS握手的实现,这与Chrome或Firefox中的实现不同。反机器人系统计算JA3/JA4的TLS连接指纹——而python脚本的指纹与真实浏览器的指纹完全不同,即使请求头被完美复制。
解决方案是使用模拟浏览器TLS指纹的库(例如Python中的curl_cffi、tls-client,或基于Chromium的完整无头浏览器通过Playwright/Puppeteer)。第二种选择是通过受控浏览器引擎与反检测工具结合工作,其中TLS和请求头由真实的浏览器内核生成,而不是库的模拟。
原因5:时区、区域设置和DNS服务器
如果脚本通过Selenium或Playwright模拟浏览器,反机器人系统可能会检查系统时区、界面语言、DNS解析器甚至WebRTC泄露真实IP服务器。位于法兰克福数据中心的VPS,系统时区为UTC,并使用主机提供商的DNS,同时使用来自莫斯科的IP代理,造成地理数据明显不符——这是检测的最可靠信号之一。
所有环境参数——时区、浏览器语言、DNS、WebRTC的地理位置——必须与用于请求的IP地址的区域相匹配。为了解决这个问题,反检测浏览器应运而生:Dolphin Anty、AdsPower、Multilogin、Octo Browser和GoLogin允许为每个代理设置单独的“浏览器配置文件”,自动调整时区、区域设置、屏幕分辨率和WebRTC以匹配IP的地理位置。
原因6:请求模式过于“机器人化”
人类在浏览目录时会有不同的暂停,点击随机商品,有时会返回,滚动页面不均匀。服务器脚本通常以相等的间隔(例如严格每2秒一次)发出请求,并且仅访问所需的URL,没有“噪音”——没有加载图片、脚本,也没有在商品卡片之前访问主页。
需要更改的内容:添加随机延迟(不是固定的2秒,而是从1.5到6秒的随机值),定期访问中间页面(类别→卡片,而不是直接请求API),在通过无头浏览器工作时模拟滚动和鼠标移动。这会增加数据收集的时间,但会显著减少被禁止的数量。
原因7:会话和cookies在请求之间未保存
服务器上的解析器通常为每个请求创建一个新的requests会话——没有cookies,没有保存的授权令牌,没有访问历史。像Wildberries和Ozon这样的市场在第一次访问时会发出临时cookies和令牌,后续请求没有它们看起来很可疑,仿佛每个请求都是新的匿名访客。
正确的方案是:一个会话(requests.Session()或浏览器上下文)——对于来自代理池的一个IP,在整个请求系列中保持cookies。更换代理时,需要使用干净的cookies开始新的会话,模拟新用户,而不是继续使用旧的cookies与新IP——这也会造成不匹配并触发封锁。
检查清单:按顺序更改内容
如果解析器在服务器上稳定被禁止,但在本地工作,请按此顺序检查更改——这样您可以更快找到原因:
| 步骤 | 检查内容 | 更改内容 |
|---|---|---|
| 1 | 服务器IP类型 | 切换到住宅代理而不是直接的托管IP |
| 2 | 请求频率 | 引入IP轮换和请求限制 |
| 3 | 请求头 | 复制真实浏览器的完整请求头集 |
| 4 | TLS指纹 | 使用curl_cffi / 无头浏览器而不是纯requests |
| 5 | 时区和区域设置 | 在Dolphin Anty / AdsPower中设置IP区域配置文件 |
| 6 | 行为模式 | 随机化延迟,添加中间页面 |
| 7 | 会话和cookies | 将一个会话绑定到整个请求周期的一个IP |
对于高频率解析Wildberries和Ozon目录的情况,速度至关重要,通常会结合使用两种类型的代理:数据中心代理用于粗略的技术请求(检查可用性、状态码),而住宅代理则用于最终从商品卡片收集数据,在这里伪装成真实用户是重要的。对于市场和Avito的移动应用,有时使用移动代理更有效,因为它们更少被自动阻止列表中的ASN列入。
结论
解析器在服务器上被禁止,而本地版本正常工作,几乎总是与脚本的逻辑无关,而与环境有关:IP类型、TLS指纹、请求头、时区、请求模式和会话管理。通过按顺序检查这7个原因——从最常见的(数据中心IP)到最不明显的(时区与IP区域不匹配)——可以恢复解析器的稳定工作,而无需更改数据收集的主要业务逻辑。
如果您在Wildberries、Ozon或Avito上以工业规模收集价格和库存,请从更换IP开始:尝试使用住宅代理而不是标准的VPS地址——在大多数情况下,这可以在您开始设置请求头和TLS指纹之前消除高达70%的阻止。