在使用Python开发网络爬虫时,模拟用户登录是获取需要权限数据的常见操作,但不少开发者会遇到登录请求返回406状态码的情况,请求直接被服务器拒绝,无法完成后续的数据采集工作。406状态码的全称是Not Acceptable,表示服务器无法根据客户端请求中的内容协商头信息,生成符合要求的响应内容。

406状态码在登录场景下的常见原因
登录请求返回406通常不是服务器故障,而是客户端发送的请求不符合服务器的校验规则,常见原因有以下几类:
- 请求头中Accept字段设置不合理:服务器要求客户端能够接收特定格式的响应,比如application/json,如果爬虫设置的Accept值不符合要求,就会触发406。
- 缺少必要的请求头字段:真实浏览器发送登录请求时会携带User-Agent、Referer、Origin等字段,爬虫如果缺失这些字段,服务器会判定请求为非正常浏览器请求,从而拒绝响应。
- 请求参数格式不符合要求:部分服务器对登录请求的参数编码格式、参数顺序有严格要求,参数格式错误也会返回406。
- Content-Type设置错误:如果是POST登录请求,Content-Type需要和参数格式匹配,比如表单提交一般是application/x-www-form-urlencoded,JSON提交是application/json,设置错误会导致服务器无法解析参数。
解决406状态码的具体方案
1. 完善请求头配置
首先模拟真实浏览器的请求头,补充必要的字段,尤其是Accept、User-Agent、Referer这几个字段。以下是常用的请求头配置示例:
import requests
# 模拟Chrome浏览器的请求头
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Accept": "application/json, text/plain, */*",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
"Referer": "https://ipipp.com/login", # 替换为实际登录页地址
"Origin": "https://ipipp.com", # 替换为实际域名
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
}
2. 校验请求参数格式
先通过浏览器开发者工具的Network面板抓取真实登录请求的参数,确保爬虫发送的参数和真实请求完全一致,包括参数名、参数值、编码格式。以下是POST表单登录的示例代码:
login_url = "https://ipipp.com/api/login" # 替换为实际登录接口地址
login_data = {
"username": "test_user",
"password": "test_password",
"remember": "true"
}
# 发送登录请求
response = requests.post(login_url, headers=headers, data=login_data)
print("响应状态码:", response.status_code)
print("响应内容:", response.text)
3. 处理JSON格式的登录请求
如果登录接口要求发送JSON格式的参数,需要调整Content-Type为application/json,同时将参数转换为JSON字符串发送:
import json
headers["Content-Type"] = "application/json; charset=UTF-8"
login_data = {
"username": "test_user",
"password": "test_password"
}
response = requests.post(login_url, headers=headers, data=json.dumps(login_data))
print("响应状态码:", response.status_code)
4. 携带Cookies维持会话
部分网站的登录流程需要先访问登录页获取Cookies,再携带这些Cookies发送登录请求,可以使用requests的Session对象自动管理Cookies:
session = requests.Session()
# 先访问登录页获取初始Cookies
session.get("https://ipipp.com/login", headers=headers)
# 使用同一个session发送登录请求
response = session.post(login_url, headers=headers, data=login_data)
print("登录后状态码:", response.status_code)
问题排查步骤
如果按照上述方案调整后仍然返回406,可以按照以下步骤排查:
- 对比爬虫请求和浏览器真实请求的所有请求头字段,确保没有遗漏或错误。
- 检查请求参数的编码格式,尝试使用urlencode对参数进行编码后再发送。
- 查看服务器返回的响应头,看是否有额外的校验要求提示。
- 尝试降低请求频率,避免被服务器判定为爬虫攻击。
注意事项
爬虫模拟登录需要遵守目标网站的robots协议和相关法律法规,不要对服务器造成过大访问压力,也不要采集受保护的非公开数据。如果遇到需要验证码的登录场景,还需要额外添加验证码识别的逻辑,否则即使修复了406问题也无法完成登录。