为何node-fetch与cURL请求返回200,Python requests却返回403?
问题分析与解决方法
原因
返回403 Forbidden的核心原因是Investing.com的反爬机制检测到Python requests的请求不符合浏览器请求特征,具体可能包括以下几点:
- 关键请求头缺失或不匹配:比如
User-Agent、Cookie、Referer、Accept系列头部,Python requests默认的请求头和浏览器差异较大,被服务器识别为非浏览器请求。 - Cookie未正确携带:浏览器中存在会话Cookie(包括可能的认证或反爬标识),cURL和Postman复制时保留了这些Cookie,但转为Python代码时可能遗漏或未正确处理。
- 请求参数或编码差异:部分参数的格式、编码方式在Python requests中处理不当,导致服务器拒绝请求。
修复步骤
1. 完整复制并保留所有请求头
从cURL中提取所有请求头,包括Cookie、User-Agent、Accept、Accept-Language、Referer、X-Requested-With等,确保Python请求完全模拟浏览器的请求头。
2. 处理Cookie(可选但关键)
如果Cookie包含会话信息,可先请求主页获取最新Cookie,再发起目标请求;或者直接使用cURL中复制的Cookie(注意Cookie的有效期,过期后需要重新获取)。
3. 模拟浏览器的请求结构
确保请求方式(GET/POST)、参数(包括查询参数或表单数据)与cURL完全一致,注意参数的编码和顺序。
示例代码
假设复制的cURL对应的请求是GET请求,以下是模拟代码:
import requests # 从cURL中复制的完整请求头 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8', 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 'Referer': 'https://www.investing.com/economic-calendar/', 'Cookie': '这里替换成你从cURL中复制的Cookie内容', 'X-Requested-With': 'XMLHttpRequest', # 其他从cURL中提取的头部 } # 目标请求的URL和参数(从cURL中复制) url = 'https://www.investing.com/economic-calendar/Service/getCalendarFilteredData' params = { 'country[]': ['25', '32', '37', '72', '22', '17', '39', '10', '11', '43', '56', '12', '14', '4', '35', '26', '15', '29', '5'], 'dateFrom': '2024-05-20', 'dateTo': '2024-05-26', 'timeZone': '8', 'timeFilter': 'time_zone', 'currentTab': 'nextWeek', 'limit_from': '0' } # 使用会话保持Cookie session = requests.Session() # 先访问主页获取有效会话 session.get('https://www.investing.com/economic-calendar/', headers={'User-Agent': headers['User-Agent']}) # 发起目标请求 response = session.get(url, headers=headers, params=params) print(response.status_code) print(response.text)
额外注意事项
- Cookie可能会过期,建议每次请求前先访问主页获取最新会话Cookie,避免因Cookie失效导致403。
- 避免频繁请求,否则可能触发IP封禁,可添加适当的延迟(比如
time.sleep(1))。 - 如果请求是POST类型,确保表单数据的格式(如
application/x-www-form-urlencoded)与cURL一致,使用requests.post并传入data参数。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

