Python脚本执行GET请求返回401,但命令行运行正常的问题求助
解决脚本运行时GET请求返回401但命令行正常的问题
看起来你遇到了一个挺让人困惑的会话保持问题——命令行直接跑代码时POST和GET都能正常返回200,但把代码作为脚本运行时,GET请求就莫名返回401了。我来帮你分析几个常见的原因和对应的解决办法:
1. 请求头差异导致服务器拒绝会话
很多网站会校验请求的User-Agent等请求头,命令行环境下requests的默认User-Agent和脚本在其他环境(比如定时任务、服务进程)运行时的可能存在差异,服务器会因此判定会话无效。
解决办法:手动设置模拟浏览器的请求头,让脚本的请求和浏览器/命令行环境保持一致:
import requests url = 'https://website.com' credentials = {'user': 'my_name', 'password' : 'my_password'} # 模拟浏览器的请求头 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' } with requests.Session() as sesh: # 给会话设置统一的请求头 sesh.headers.update(headers) init = sesh.post(url+'/login', data=credentials) print(init.status_code) # 可以打印会话的Cookie,对比命令行和脚本运行时的差异 print("Session cookies:", sesh.cookies) xml = sesh.get(url+'/different/path') if xml.status_code == 200: print(xml.content) else: print(xml.status_code)
2. 忽略了CSRF令牌验证
不少网站的登录接口需要CSRF令牌才能完成有效登录,你当前的代码直接POST用户名密码,命令行运行时可能刚好会话中保留了之前的CSRF令牌(比如你之前手动访问过登录页),但脚本运行时是全新会话,没有获取CSRF就直接登录,虽然返回200,但其实并没有真正建立有效会话。
解决办法:先请求登录页面获取CSRF令牌,再携带令牌进行登录:
import requests import re url = 'https://website.com' credentials = {'user': 'my_name', 'password' : 'my_password'} headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' } with requests.Session() as sesh: sesh.headers.update(headers) # 先获取登录页面,提取CSRF令牌 login_page = sesh.get(url+'/login') # 这里根据实际页面的CSRF字段名调整正则,比如name="csrfmiddlewaretoken" csrf_match = re.search(r'name="csrf_token" value="(.*?)"', login_page.text) if csrf_match: credentials['csrf_token'] = csrf_match.group(1) else: print("Failed to get CSRF token") init = sesh.post(url+'/login', data=credentials) print(init.status_code) xml = sesh.get(url+'/different/path') if xml.status_code == 200: print(xml.content) else: print(xml.status_code)
3. 环境差异导致会话状态异常
脚本运行的环境(比如不同用户身份、虚拟环境、网络代理)可能和命令行环境不一致,比如:
- 脚本运行用户没有访问目标网站的网络权限
- 虚拟环境中requests版本和命令行不同,导致会话处理逻辑有差异
- 脚本环境存在代理,而命令行没有,代理拦截了会话Cookie
排查思路:
- 对比脚本和命令行运行时的环境变量、Python版本、requests版本
- 在脚本中打印请求的完整信息(比如
print(xml.request.headers)),和命令行运行时的请求头对比,找出差异点
4. 登录后跳转未正确处理
有些网站登录后会自动跳转,虽然requests的Session默认开启了allow_redirects=True,但少数情况下跳转过程中可能丢失Cookie,或者需要额外处理跳转后的响应。
解决办法:可以手动处理跳转,或者检查登录响应的跳转目标,确保会话Cookie被正确保存:
init = sesh.post(url+'/login', data=credentials, allow_redirects=False) print("Login redirect status:", init.status_code) # 如果有跳转,手动跟进 if init.status_code in [301, 302]: sesh.get(init.headers['Location'])
内容的提问来源于stack exchange,提问作者t_wrecks_all
相关产品推荐
相关产品推荐

