You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Cloudflare拦截Python requests请求却放行Postman请求的原因及解决方法

Cloudflare拦截Python requests请求却放行Postman请求的原因及解决方法

我完全懂你这种挫败感——明明Postman能轻松拿到200响应和目标数据,把Postman生成的代码直接搬到Python里用requests跑,就立刻被Cloudflare扔403。哪怕你把headers都逐字复制过去也没用,甚至Chrome和Firefox导出的curl在Postman里表现都不一样。咱们先把背后的原因说透,再给你落地的解决办法。

为什么会出现这种差异?

1. Cloudflare的会话Cookie是“一次性绑定”的

你从Postman里复制的__cf_bm__cflb这类Cookie,是Cloudflare为当前会话生成的临时验证凭证。它们不仅有时效性(几分钟就会过期),还和生成它们的请求环境(比如浏览器的指纹、IP、会话上下文)深度绑定。直接把这些Cookie复制到Python的requests里,请求环境变了,Cloudflare就会判定这是“异常请求”,直接拦截。

2. 请求指纹的细微差异触发了拦截

Cloudflare的反爬系统(Bot Management)会检测全维度的请求指纹,不只是你能看到的User-Agent和Cookie:

  • TLS握手参数:requests默认的TLS配置和Firefox/Postman不一样,Cloudflare会通过TLS的加密套件、版本、扩展字段来识别是不是“真实浏览器”
  • HTTP头的顺序/细节:你提到Chrome里把user-agent改成User-Agent才有用,虽然HTTP标准里头是不区分大小写的,但Cloudflare会把这种细节作为指纹的一部分;还有一些你没注意到的隐式头,比如Postman可能自动添加了X-Requested-With这类头,而requests默认不会加
  • 会话连贯性:Postman会自动维护会话状态,而你用requests.request每次都是独立请求,更像“机器人”的行为

你说Firefox导出的curl在Postman里直接能用,Chrome的却要删一堆头才行,本质就是Firefox的请求指纹更符合Cloudflare的“可信浏览器”模板,而Chrome的一些默认头被判定为“可疑”。

3. Postman的底层请求逻辑更贴近浏览器

Postman本身是基于Chromium内核的,它的请求发送逻辑和浏览器更接近,而requests是基于urllib3的纯HTTP库,底层的请求特征和浏览器有本质区别,哪怕你手动加了所有可见的头,隐藏的差异还是会被Cloudflare抓到。

解决办法,从临时到长期

方法1:临时测试——实时更新有效Cookie

这是最快的临时解决方案,适合单次测试:

  1. 打开Firefox,访问目标页面(或者直接打开你要请求的API URL)
  2. 打开开发者工具(F12)→ 网络面板,找到对应请求,复制最新的__cf_bm__cflb Cookie值
  3. 把这些Cookie替换到Python代码里,立刻运行,这时候大概率能拿到200响应

⚠️ 注意:这个方法只能用几分钟,Cookie过期后就会再次403,不适合长期爬取。

方法2:优化请求指纹,模拟真实浏览器

如果要长期用requests,得把请求的每一个细节都对齐Firefox的请求:

  1. 补全所有浏览器级别的HTTP头
    不要只留User-Agent和Cookie,把Firefox请求里的所有头都复制过来,比如AcceptAccept-LanguageAccept-EncodingRefererConnectionSec-Fetch-*系列头
  2. 用requests.Session维护会话
    Session会自动维护Cookie和会话状态,比每次用requests.request更像浏览器的连贯请求
  3. 调整TLS配置,匹配Firefox
    requests默认的TLS加密套件和Firefox不一样,可以通过适配器修改:

优化后的代码示例:

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.ssl_ import create_urllib3_context

# 模拟Firefox的TLS加密套件
FIREFOX_CIPHERS = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:RSA-AES128-GCM-SHA256:RSA-AES256-GCM-SHA384:RSA-AES128-SHA:RSA-AES256-SHA"

class FirefoxTLSAdapter(HTTPAdapter):
    def init_poolmanager(self, *args, **kwargs):
        context = create_urllib3_context(ciphers=FIREFOX_CIPHERS)
        kwargs['ssl_context'] = context
        return super().init_poolmanager(*args, **kwargs)

url = "https://io.dexscreener.com/dex/pair-details/v3/solana/HKj2acbuMto92TvjtBfpPyG2im28og5b647gh1K62CAm"

# 完全复制Firefox的请求头
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0',
    'Accept': 'application/json, text/plain, */*',
    'Accept-Language': 'en-US,en;q=0.5',
    'Accept-Encoding': 'gzip, deflate, br, zstd',
    'Referer': 'https://dexscreener.com/',
    'Connection': 'keep-alive',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-site',
    # 替换成你刚从Firefox复制的最新Cookie
    'Cookie': '__cf_bm=Pa25nvnzsUCW1AnI5oCV6ZDLXV8HY.VjsZM1squ8D30-1735078602-1.0.1.1-7WIFetntuMUCOgKEH0XlF8uKq8e4t5sS403X8XEwzkrACUTs1woAlaXzzmN65nZksyujfMGKiD_HqyD9MRED6mASCQxtAbySJGLSyGVVvII; __cflb=04dTof7UnGZLJbSktrXU5s6TEcm2ZGkWquifmfRNx5'
}

# 创建会话并挂载自定义TLS适配器
session = requests.Session()
session.mount('https://', FirefoxTLSAdapter())

response = session.get(url, headers=headers)
print(response.text)

方法3:用专门的库绕过Cloudflare验证

如果上面的方法还是被拦,就用专门针对Cloudflare的工具,这些库会自动处理JS验证、Cookie生成和指纹模拟:

用cloudscraper(推荐,轻量)

cloudscraper是requests的封装,会自动处理Cloudflare的Turnstile和JS验证,用法和requests几乎一样:

import cloudscraper

# 创建模拟浏览器的scraper
scraper = cloudscraper.create_scraper(browser={'browser': 'firefox', 'platform': 'windows', 'mobile': False})

url = "https://io.dexscreener.com/dex/pair-details/v3/solana/HKj2acbuMto92TvjtBfpPyG2im28og5b647gh1K62CAm"
response = scraper.get(url)

# 直接获取JSON数据
print(response.json())

用undetected-chromedriver(适合更严格的验证)

如果Cloudflare的验证级别很高,用修改过的ChromeDriver来模拟真实浏览器,它会隐藏所有自动化痕迹,比普通Selenium更难被检测:

from undetected_chromedriver import Chrome, ChromeOptions
import json

options = ChromeOptions()
options.add_argument('--headless=new')  # 无头模式,不弹出浏览器
options.add_argument('--disable-gpu')
options.add_argument('--no-sandbox')

# 启动浏览器
driver = Chrome(options=options)
driver.get("https://io.dexscreener.com/dex/pair-details/v3/solana/HKj2acbuMto92TvjtBfpPyG2im28og5b647gh1K62CAm")

# 获取页面的JSON内容(因为API返回的是纯JSON,直接取页面源码)
data = json.loads(driver.page_source)
print(data)

driver.quit()

最后补充

你提到用Selenium/无头Selenium能成功,本质就是因为它们模拟了真实浏览器的所有特征,而requests是纯HTTP库,缺少这些“浏览器指纹”。上面的方法就是在requests里补全这些指纹,或者直接用工具帮你做这件事。

备注:内容来源于stack exchange,提问作者nilesh jodhani

火山引擎 最新活动