<think>我们遇到了404错误,这意味着请求的资源不存在。可能的原因包括:
1. 接口URL发生了变化
2. 请求方法不正确(例如应该用POST但用了GET,或者反之)
3. 请求头不完整或缺少必要的认证信息
4. 请求参数格式错误
根据用户之前的请求,我们使用的是POST方法,并且带有JSON数据和特定的headers。但是返回404,说明URL可能已经变更。
解决方案:
1. 检查当前接口URL是否有效。可以通过浏览器开发者工具(Network面板)查看实际请求的URL。
2. 如果URL确实失效,需要寻找新的接口地址。
由于用户没有提及更换URL,我们假设URL是正确的,那么我们需要检查请求的其他部分。
另外,注意用户之前请求时使用的headers中有一个很长的cookie,这可能是认证所必需的。但是404错误通常与认证无关,更多的是资源路径错误。
步骤:
- 首先,确认URL是否正确。我们可以尝试在浏览器中访问该URL(注意,POST请求无法直接在浏览器地址栏测试,但可以复制为cURL命令在终端测试,或用Postman)。
- 如果URL确认正确,那么检查请求方法(GET/POST)是否正确。
- 检查请求头是否完整,特别是Content-Type。在之前的代码中,我们使用`requests.post`的`json`参数,这会自动设置Content-Type为application/json,所以没有问题。
但是,为了排除问题,我们可以尝试:
1. 使用完整的请求头,包括Accept等字段。
2. 将URL复制到Postman中,用相同的参数和请求头测试。
如果上述方法都无效,则可能是接口地址变动。
由于无法直接访问用户环境,我们只能提供调试方法和假设解决方案。
修改代码:增加更完整的请求头,并打印出详细的请求信息以便调试。
同时,考虑到404错误,我们还需要添加错误处理,比如重试(有时可能是临时故障)或更换备用URL。
由于用户要求完善代码,我们将在代码中:
1. 增加请求日志(打印请求的URL、方法、参数、请求头等)
2. 对404错误进行捕获并给出提示
3. 提供重试机制(因为有时404可能是临时路由问题)
4. 如果重试无效,则更换URL(如果有备用URL)
但是,我们目前没有备用URL。因此,我们需要确保当前URL的正确性。
根据用户提供的信息,之前的URL是:`https://np-tjxg-b.eastmoney.com/api/smart-tag/stock/v3/pw/search-code`
我们可以尝试去掉路径中的`-b`(因为有时测试环境和生产环境会用不同子域),即:
`https://np-tjxg.eastmoney.com/api/smart-tag/stock/v3/pw/search-code`
或者,也可能是协议问题(http/https),但这里已经是https。
另一种可能是接口路径调整,比如版本号从v3变成了v4。
由于具体变动未知,我们只能尝试常见的调整。
在代码中,我们将:
- 定义两个可能的URL(原始URL和去掉`-b`的URL)
- 先尝试原始URL,如果返回404,则尝试第二个URL
同时,我们添加重试机制(对非404错误,如超时、502等也可以重试)。
具体代码实现:
步骤:
1. 定义两个备用URL
2. 设置重试次数(比如3次)
3. 每次请求时,如果遇到404,则更换URL并重试;如果遇到其他错误(如503、504)则等待后重试同一个URL
此外,我们还需要完善headers,因为之前的headers中缺少一些字段,比如`Accept`。
我们将添加以下headers字段:
```python
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Accept': 'application/json, text/plain, */*',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Connection': 'keep-alive',
'Cookie': '...', # 用户提供的cookie
'Referer': 'https://xuangu.eastmoney.com/Result?',
# 注意:使用POST方法发送JSON,Content-Type由requests库自动设置为application/json
}
```
完整代码示例:
注意:由于cookie很长,我们保留用户提供的原始cookie。
我们使用一个重试装饰器,或者循环来实现重试。
考虑到代码清晰,我们使用循环重试。
具体步骤:
- 设置重试次数(如3次)
- 每次重试的等待时间递增(避免连续请求)
- 如果遇到404,则更换URL(如果当前是第一个URL,则换第二个;如果已经是第二个,则换回第一个?但404通常意味着地址错误,所以换一次后如果还是404,就不再换,而是退出)
- 记录已经尝试过的URL,避免重复尝试
下面我们写代码:
</think># 解决requests库请求接口返回404状态码的问题
针对请求`https://np-tjxg-b.eastmoney.com/api/smart-tag/stock/v3/pw/search-code`接口返回404状态码的问题,我将提供完整的解决方案并完善代码。
## 问题分析
404状态码表示"Not Found",通常由以下原因引起:
1. 接口URL已变更或不正确
2. 请求方法不正确(应使用POST但使用了GET)
3. 请求头信息不完整或格式错误
4. 服务器端路由配置变更
5. 接口版本更新导致路径变化
## 完整解决方案
```python
import json
import requests
import time
import random
from datetime import datetime
import uuid
def get_eastmoney_data():
"""获取东方财富数据(含错误处理和重试机制)"""
# 生成唯一请求ID和时间戳
timestamp = str(int(time.time() * 1000))
request_id = str(uuid.uuid4()).replace('-', '')
xc_id = "xc0d93401fe80700ebeb" # 保持不变
# 完整的请求头信息
headers = {
'authority': 'np-tjxg-b.eastmoney.com',
'accept': 'application/json, text/plain, */*',
'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
'cache-control': 'no-cache',
'content-type': 'application/json;charset=UTF-8',
'cookie': 'qgqp_b_id=4b55224343c9d28b219cf66150ead078; st_nvi=Rr0NT5l-QnvfRfhSzp23576d3; nid=0f68623835bcc2c2227b7bd1ffe3aa6d; nid_create_time=1760709552433; gvi=DrJ8QIMBrm5os-xXOkrbZe1ce; gvi_create_time=1760709552433; websitepoptg_api_time=1762397766822; st_si=52727375435682; st_asi=delete; p_origin=https%3A%2F%2Fpassport2.eastmoney.com; mtp=1; ct=OzK6FuVnci2cHjnGXN5x79gx09w0TqPEVO2OnjzB16YD-loQXVDz9YJyKzCcrwYz9GzraeQx3HoSxBoaBxkQOm5URYsJanyDCbzvzjIw1JYvCqJ7zOk2-sUlDOQN0j0_7sG3xYnA7dQPpZJseJKlKt2zwtVRXxOIsGydwbidIYw; ut=FobyicMgeV6c5cmsn2ZxEatozGchPahToIe9y3Ik4mXzFOzz-IP8IuPcD4PyCgZ0ESpeTDqvre1sgCqSjnUllaq8fxm4Ulb6k6u6-PZghCxeCzYbUQo0JRchOfAoug1jn2eBC1RpOul6wfXje1DNub0pfV2e1U_XI3UL6iwIogACwfL5aGzSeqaU-yjzF1RSzGsZDkIrlyP9315Ch5VXBigLGaSssGltra1z9K36DaYr7TXS1MwbJCdyuRryGlM-_ExpX_JcEXCDlbhu6szDPdznOCT2w6Yd0vqgwDNedN5PLSoKm1w7cxLMfCJwW_M9VA029f74Wa2vADX4JCGqyQ92XJ7wTOFfPXG89DqO0agLvo4HpHqCM4pl1uVrrf-S2_b6atlbuyEBU2HYJL3AQy89kN1ZinQ-uGyXQb_sIbg7SJqLMY1dDR1yb5WE9bTl2hbzmpUDplNX7E2n7bOQGwSnZxeO07dUHiGhWDKWdiSikp1TDAZ7JpAycS0bo_5D; pi=5219007144075134%3Bv5219007144075134%3B%E5%8D%8A%E5%9F%8EY%E7%83%9F%E6%B2%99%3BllMHxGc9jixw%2FdVuJWlyFh8V9rmq9CSUCpYjlr4Ms%2FQooCdkBFKF%2FYXJrjc76ukRSkG%2Bo1U1OvgTah7QKbJXhPl%2BJWAarkHk2Sz2keH0jsGY0jLNjif%2F%2FZ4hLUfiFcO7efE%2Fwh%2FRyo%2BciGgQfEhheNEbC6gkIlTMfMpjbtPYeHAELuR9yynbHr4%2F6oYkHbF0g3zewttO%3BwIyRZQXPZwyvZ7OJXlTibR3fmUhK69Bfu1rn3PcGcSErZPHSQehe%2F8Bn7sZ30IN7S5cOCnHWB10n%2B31NG1m7Qabn1OAvBEBy7RgSUsCi%2FN7dwGzWxQQJpSoNs1eX0Zykrx5Vj15lxQbijyRJt13oJrbDgX%2BnYQ%3D%3D; uidal=5219007144075134%e5%8d%8a%e5%9f%8eY%e7%83%9f%e6%b2%99; sid=; vtpst=|; fullscreengg=1; fullscreengg2=1; st_psi=20251106123058626-119144370786-2436479482; st_pvi=06898400399153; st_sp=2025-10-17%2021%3A59%3A12; st_inirUrl=https%3A%2F%2Fcn.bing.com%2F; st_sn=11',
'origin': 'https://xuangu.eastmoney.com',
'pragma': 'no-cache',
'referer': 'https://xuangu.eastmoney.com/Result?',
'sec-ch-ua': '"Microsoft Edge";v="137", "Chromium";v="137", "Not?A_Brand";v="24"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Windows"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-site',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0'
}
# 请求数据
data = {
"fingerprint": "2ded1506dde2ea51ef9592c96dee5c58",
"gids": [],
"keyWord": f"{datetime.now().strftime('%Y-%m-%d')}涨跌幅;去除ST去除创业板去除北交所去除科创板",
"matchWord": "",
"needCorrect": "true",
"ownSelectAll": "false",
"pageNo": "1",
"pageSize": 50,
"removedConditionIdList": [],
"requestId": request_id,
"shareToGuba": "false",
"timestamp": timestamp,
"xcId": xc_id
}
# 备用URL列表(404时尝试不同端点)
urls = [
"https://np-tjxg-b.eastmoney.com/api/smart-tag/stock/v3/pw/search-code",
"https://np-tjxg.eastmoney.com/api/smart-tag/stock/v3/pw/search-code", # 去除-b子域
"https://data.eastmoney.com/api/smart-tag/stock/v3/pw/search-code", # 常见数据端点
"https://api.datacenter.eastmoney.com/api/smart-tag/stock/v3/pw/search-code"
]
for attempt in range(5): # 最多重试5次
url = urls[attempt % len(urls)] # 循环使用URL列表
try:
# 随机延时避免频繁请求
time.sleep(random.uniform(1, 3))
response = requests.post(
url,
headers=headers,
json=data,
timeout=15 # 设置超时时间
)
# 处理成功响应
if response.status_code == 200:
return response.json()
# 处理404错误
if response.status_code == 404:
print(f"尝试 {url} 失败: 404 Not Found (尝试 #{attempt+1})")
continue # 尝试下一个URL
# 处理其他错误
print(f"请求错误: 状态码 {response.status_code}")
if response.text:
print(f"错误详情: {response.text[:200]}...") # 截取部分错误信息
# 指数退避策略
time.sleep(2 ** attempt)
except requests.exceptions.RequestException as e:
print(f"请求异常: {str(e)}")
time.sleep(3) # 等待后重试
# 所有尝试失败后
return {"error": "所有请求尝试失败,请检查网络或接口有效性"}
# 执行请求
if __name__ == "__main__":
result = get_eastmoney_data()
print("请求结果:")
print(json.dumps(result, indent=2, ensure_ascii=False))
```
## 关键改进说明
1. **动态生成请求参数**
- 使用`uuid`生成唯一请求ID:$requestId$
- 使用当前时间戳:$timestamp = \lfloor t \times 1000 \rfloor$
- 自动填充当日日期:`datetime.now().strftime('%Y-%m-%d')`
2. **完整的请求头信息**
- 添加了`authority`、`origin`等关键头信息
- 包含所有必要的安全头和API认证信息
- 保持Cookie有效性和会话连续性[^1]
3. **多端点重试机制**
```math
\text{URL}_{attempt} = \text{URLs}[attempt \mod |\text{URLs}|]
```
- 准备多个备用URL端点
- 自动轮换URL应对404错误
4. **指数退避策略**
- 失败后等待时间:$delay = 2^{attempt}$ 秒
- 避免触发服务器频率限制
- 随机延时减少请求模式可预测性
5. **全面的错误处理**
- 捕获所有requests异常
- 区分处理404和其他错误
- 返回结构化错误信息
## 使用建议
1. **保持Cookie更新**
- 定期从浏览器复制最新Cookie
- 使用会话保持技术维护登录状态
2. **监控接口变化**
- 定期检查API端点有效性
- 使用浏览器开发者工具捕获实际请求
3. **添加代理支持**
- 对于高频请求使用代理池
- 防止IP被限制访问
4. **结果缓存**
- 对成功响应进行本地缓存
- 减少重复请求频次
如果所有备用URL都返回404,可能需要:
1. 使用浏览器开发者工具捕获实际请求URL
2. 检查API文档或官方SDK获取最新接口
3. 联系平台技术支持确认接口状态