You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python requests.session()登录纽约时报网站失效问题求助

问题核心原因

你的代码跑不通本质上是对现在主流网站的登录逻辑有误解:纽约时报根本没有用传统的静态表单提交做登录,整个流程是前端JS控制的多步交互,还带动态参数校验、反爬识别,你对着静态页面源码找form action、猜参数名,肯定登不进去。
至于错密码也返回200太正常了,现在几乎没有网站会用HTTP状态码标识登录失败,都是返回200状态,把错误信息放在响应体里靠前端弹窗提示,靠状态码判断登录成功从一开始就不对。

你踩的几个明确的坑:

  • 找<form action>的方法只适用于老旧网站,现在NYT登录页根本没有静态form标签,所有提交请求都是JS动态生成接口地址发出去的,提交目标根本不是登录页本身的URL,你POST到login_page相当于把数据发给了一个根本不处理登录逻辑的地址。
  • 密码框name从hiddenPassword变password,本身就是两步登录的前端表现:第一步只提交邮箱,后端校验邮箱存在、没有风控拦截,才会返回密码输入框的渲染逻辑,你一次性把邮箱密码全POST过去,流程根本没走到密码校验那一步,传什么参数名都没用。
  • 所有登录请求都需要带动态生成的校验参数,最常见的就是CSRF令牌、会话流水、风控埋点参数,这些参数每次打开登录页都会变,你不带这些参数,后端直接把请求当非法流量拦截,根本不会校验你的账号密码对不对。
具体解决步骤

别盯着页面源码猜了,按下面的流程走就能通:

  1. 先抓真实的登录请求。打开浏览器的开发者工具(F12),切到「网络」面板,勾选「保留日志(Preserve log)」,手动完整走一遍登录流程:输入邮箱点下一步,输入密码点登录。这时候你能在网络面板里看到两个核心的POST请求,一个是提交邮箱做第一步校验的,一个是提交密码做最终登录的,这俩请求的URL才是你真正要请求的接口,不是浏览器地址栏里的登录页地址。
  2. 第一次用Session访问登录页的时候,不要急着POST账号密码,先从返回的页面源码里把所有动态参数解析出来:最常见的是放在meta标签里的CSRF token,或者写在页面script标签里的全局配置参数,这些值每次刷新页面都会变,必须实时拿,不能写死。
  3. 严格按照抓包看到的顺序复现请求,别跳步:
    • 第一步:把解析到的动态参数和你的邮箱拼到请求体里,POST到你抓包拿到的邮箱校验接口。注意请求头必须带正常的浏览器User-Agent,requests默认带的python-requests/版本号UA会被NYT的反爬直接拦,直接复制你浏览器里的UA就行,另外把Referer头设成登录页地址,更不容易被拦。
    • 第一步请求成功后,从响应的Cookie或者返回的JSON数据里,拿到第二步需要的新校验参数,再把密码拼进去,POST到密码校验接口。这里密码字段的名字、请求体格式(是form表单还是JSON)完全照着抓包看到的写,不要自己猜是password还是hiddenPassword,抓包里是什么就写什么。
  4. 两步请求都发完之后,先检查Session里的Cookie有没有带上登录态标识(一般字段名会带auth、sid、login这类关键词),确认有登录Cookie之后,再去请求收藏文章的页面,这时候拿到的才是登录后的内容。

参考代码框架

注意:代码里的接口地址、参数解析逻辑需要替换成你自己抓包拿到的真实值,不能直接硬抄运行

import requests
from bs4 import BeautifulSoup

# 以下两个接口地址替换成你自己抓包拿到的真实地址
EMAIL_CHECK_API = "抓包获取的邮箱校验接口URL"
PASSWORD_LOGIN_API = "抓包获取的密码提交接口URL"
LOGIN_PAGE_URL = "https://myaccount.nytimes.com/auth/login"
SAVED_ARTICLES_URL = "https://www.nytimes.com/saved"

# 请求头直接复制你浏览器里的内容,重点是User-Agent不能用默认值
REQUEST_HEADERS = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
    "Referer": LOGIN_PAGE_URL
}

if __name__ == "__main__":
    with requests.Session() as session:
        session.headers.update(REQUEST_HEADERS)
        # 第一步:访问登录页,拿动态参数
        login_page_resp = session.get(LOGIN_PAGE_URL)
        login_page_resp.raise_for_status()
        soup = BeautifulSoup(login_page_resp.text, "html.parser")
        
        # 这里根据你实际在页面里找到的CSRF参数位置调整,比如如果是meta标签存的就这么写
        csrf_token = soup.select_one('meta[name="csrf-token"]')["content"]
        # 其他抓包里看到的必填隐藏参数,都按这个方式从页面里解析出来

        # 第二步:提交邮箱做第一步校验
        email_payload = {
            "email": "你的注册邮箱",
            "csrf_token": csrf_token,
            # 把其他抓包里看到的必填参数都补上
        }
        # 注意看抓包里的请求是form格式(传参用data=)还是json格式(传参用json=),别写错
        email_resp = session.post(EMAIL_CHECK_API, json=email_payload)
        email_resp.raise_for_status()
        # 从邮箱校验的返回里拿第二步需要的参数,根据实际返回格式调整解析逻辑
        step2_auth_data = email_resp.json()

        # 第三步:提交密码完成登录
        login_payload = {
            "password": "你的账号密码",
            "csrf_token": csrf_token,
            # 把第二步拿到的校验参数都补上,字段名和抓包完全一致
        }
        login_resp = session.post(PASSWORD_LOGIN_API, json=login_payload)
        login_resp.raise_for_status()

        # 登录完成后访问收藏页
        saved_articles_resp = session.get(SAVED_ARTICLES_URL)
        # 这里打印内容验证是否登录成功
        print(saved_articles_resp.text)

实操提醒

  • 所有接口地址、参数名、请求格式,一律以你自己抓包看到的内容为准,不要硬抄网上的旧代码,NYT前端经常迭代,字段和接口随时会变。
  • 如果抓包看到密码是加密后传输的,说明前端JS对密码做了加密处理,你需要找到对应的加密逻辑,把密码按同样规则加密之后再传,传明文肯定过不了校验。
  • 如果账号开了二次验证,就在密码登录成功之后,多一步二次验证的请求,逻辑完全一样,照着抓包的请求顺序复现参数就行。
  • 调试的时候一步一步来,先把邮箱校验接口调通,确认返回成功了再调密码登录接口,哪步返回不对,就把你发的请求和浏览器的请求挨个对比:请求头差什么、参数差什么、Cookie差什么,补上就能过。

内容的提问来源于stack exchange,提问作者itsallkosher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 16:27:49