Python Requests本地运行正常,Django本地服务请求触发验证码求助
咱们先捋清楚核心矛盾:同一个请求代码,在Sublime里直接跑能正常拿页面,放到Django本地服务里就触发验证码——这大概率是两种环境下的请求特征差异被目标网站的反爬机制盯上了。下面一步步排查解决:
1. 对比请求头,补全关键字段
Sublime里的请求可能自带了更贴近真实浏览器的请求头,而Django环境下的默认请求头可能太简陋。先把两种环境的请求头打出来对比:
在Sublime的代码里加一行:
print("Sublime请求头:", headers)
在Django的请求代码里也加一行:
print("Django请求头:", headers)
重点检查这几个容易踩坑的字段,缺了就补上:
User-Agent:别用requests默认的,直接抄浏览器或者Sublime里的正常值Accept、Accept-Language、Accept-Encoding:这些字段能让请求更像真人操作Cookie:如果Sublime里之前访问过目标站,session里可能存了已验证的Cookie,而Django里是全新session,不妨把Sublime的Cookie复制过来测试
比如补全后的headers可以是这样:
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', 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 'Accept-Encoding': 'gzip, deflate, br', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1', }
2. 确认代理在Django环境下真的生效了
有时候Django运行的环境会偷偷读取系统代理,哪怕你设置了proxies参数。可以在请求后打印实际代理使用情况:
print("实际代理信息:", response.request.url, response.request.headers.get('Proxy-Authorization'))
或者检查环境里的代理是否干扰了你的设置:
import requests.utils print("环境默认代理:", requests.utils.get_environ_proxies(url))
如果发现环境代理在搞事,除了设置session.trust_env = False,还可以在Django启动时临时清空代理环境变量:
import os os.environ.pop('HTTP_PROXY', None) os.environ.pop('HTTPS_PROXY', None)
3. 复用Sublime里的已验证Session
既然Sublime里能正常访问,说明那个session已经通过了目标站的验证。你可以把Sublime里的Session Cookie导出来,在Django里复用:
在Sublime的代码里加:
print("Sublime Session Cookies:", s.cookies.get_dict())
然后把这些Cookie复制到Django的Session里:
s = requests.Session() # 替换成你从Sublime里拿到的Cookie键值对 for key, value in {'auth_token': 'xxx', 'session_id': 'yyy'}.items(): s.cookies.set(key, value) # 再发起请求 response = s.get(url, headers=headers, proxies=proxies)
4. 检查请求频率和并发问题
如果Django里是高频发起请求,目标站可能会因为请求太频繁触发验证码。可以加个小延迟试试:
import time time.sleep(2) # 请求前延迟2秒,模拟真人操作间隔 response = s.get(url, headers=headers, proxies=proxies)
5. 确认网络出口IP是否一致
有时候Django运行的环境(比如虚拟机、Docker)和Sublime所在的本地网络出口不一样,导致目标站识别为陌生IP。可以在两种环境下打印出口IP验证:
# 请求一个能返回自身IP的网站 ip_response = s.get('http://httpbin.org/ip', proxies=proxies) print("当前出口IP:", ip_response.json())
如果IP不一样,说明代理在Django里没生效,或者网络环境有差异,得调整代理配置。
内容的提问来源于stack exchange,提问作者jayimshan

