使用Python Requests登录UPS MyChoice遇403错误求排查
我尝试用Python Requests登录UPS MyChoice账户,UPS采用两步登录流程:先输入用户名发起请求,再用上一步的CSRFToken输入密码完成登录,但卡在输入用户名的步骤,持续收到403 Forbidden错误。代码如下:
import requests from bs4 import BeautifulSoup s = requests.Session() jar = requests.cookies.RequestsCookieJar() # Create cookie jar # Go to home page to get init cookies response = s.get("https://www.ups.com/us/en/Home.page", headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'}) jar.update(response.cookies) # Go to login page, update cookie jar, get CSRFToken response = s.get("https://www.ups.com/lasso/login?loc=en_US&returnto=https%3A%2F%2Fwww.ups.com%2Fus%2Fen%2FHome.page", headers=headers_main, cookies=jar) jar.update(response.cookies) soup = BeautifulSoup(response.content, 'html.parser') csrftoken = soup.find(id='CSRFToken')['value'] url = "https://www.ups.com/lasso/login" payload = f'CSRFToken={csrftoken}&loc=en_US&returnto=https%253A%252F%252Fwww.ups.com%252Fus%252Fen%252FHome.page&forgotusername=YZ&connectWithSocial=YZ&userID=MYUSERNAME&getTokenWithPassword1=&ioBlackBox=&ioElapsedTime=' headers = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 'Accept-Language': 'en-US,en;q=0.9', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Content-Type': 'application/x-www-form-urlencoded', 'Origin': 'https://www.ups.com', 'Pragma': 'no-cache', 'Referer': 'https://www.ups.com/us/en/Home.page', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36', } response = s.post(url, headers=headers, data=payload, cookies=jar) # Returns 403
问题根源与修复方案
放弃手动管理CookieJar,依赖Session自动维护
Session本身会自动保存、更新和发送请求过程中的所有Cookie,手动创建jar并重复更新的操作会导致Cookie状态混乱,这是触发403的核心原因之一。直接移除所有手动CookieJar相关代码即可。修复未定义的
headers_main变量
代码中请求登录页时使用了未定义的headers_main,会直接抛出异常,即使忽略异常,缺失规范请求头也会被反爬拦截。统一使用预定义的标准请求头即可。用字典格式传递Payload,避免手动编码错误
手动拼接字符串容易出现URL编码错误(比如returnto的重复编码),改用字典传递data参数,Requests会自动处理application/x-www-form-urlencoded格式的编码逻辑。修正Referer为实际跳转前的登录页URL
提交用户名的请求,Referer应该是登录页地址而非首页,不符合浏览器行为的请求头会被反爬识别。
修正后的完整代码
import requests from bs4 import BeautifulSoup # 用Session自动管理Cookie,无需手动维护CookieJar s = requests.Session() base_headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36' } # 访问首页初始化Session状态 s.get("https://www.ups.com/us/en/Home.page", headers=base_headers) # 访问登录页获取CSRFToken login_page_url = "https://www.ups.com/lasso/login?loc=en_US&returnto=https%3A%2F%2Fwww.ups.com%2Fus%2Fen%2FHome.page" response = s.get(login_page_url, headers=base_headers) soup = BeautifulSoup(response.content, 'html.parser') csrftoken = soup.find(id='CSRFToken')['value'] # 用字典构造请求参数,避免编码错误 payload = { 'CSRFToken': csrftoken, 'loc': 'en_US', 'returnto': 'https://www.ups.com/us/en/Home.page', 'forgotusername': 'YZ', 'connectWithSocial': 'YZ', 'userID': 'MYUSERNAME', 'getTokenWithPassword1': '', 'ioBlackBox': '', 'ioElapsedTime': '' } # 构造POST请求头,修正Referer为登录页地址 post_headers = base_headers.copy() post_headers.update({ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', 'Accept-Language': 'en-US,en;q=0.9', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Content-Type': 'application/x-www-form-urlencoded', 'Origin': 'https://www.ups.com', 'Pragma': 'no-cache', 'Referer': login_page_url, 'Upgrade-Insecure-Requests': '1' }) # 发送POST请求,Session自动处理Cookie response = s.post("https://www.ups.com/lasso/login", headers=post_headers, data=payload) print(response.status_code) print(response.text)
额外说明
如果修正后仍出现403,需要注意UPS的ioBlackBox和ioElapsedTime参数——这两个是前端生成的防爬校验值,需要通过开发者工具查看浏览器实际发送的参数内容,模拟前端生成逻辑或直接从登录页的JS代码中提取对应值。
内容的提问来源于stack exchange,提问作者Bijan

