Python Requests实现模拟登录:解决CSRF与Session会话保持

山海之间
山海之间
发布时间:2026-10-13| 6人浏览过
原创

本文详解如何使用Python的Requests库实现网站模拟登录。通过抓取登录请求头与参数,解析CSRF Token机制,并重点解决HTTP无状态导致的身份识别问题。核心方案是利用requests.Session()维持会话状态,自动传递Session ID,从而成功通过服务器验证并获取登录后的页面内容。

此前在利用Python抓取网页数据时,主要采用GET请求方式获取页面,随后借助正则表达式进行内容过滤。

本次尝试模拟登录个人网站,发现操作流程相对简便。阅读并理解本文内容,要求读者具备HTTP协议及HTTP会话相关的基础知识。

特别说明:由于演示对象为作者的个人网站,下文代码中涉及的网站地址及账号密码信息已做脱敏处理。

网站分析

开展爬虫工作的首要步骤是深入分析目标网站。此处借助谷歌浏览器的开发者工具进行抓包分析。

通过执行登录操作并抓取网络请求,观察到如下请求结构。

请求部分包含请求头与请求体参数。从截图中可见,页面通过表单提交了三个关键参数,分别为_csrf、username和password。

其中_csrf参数旨在防御跨站请求伪造攻击。其原理较为直观:服务器在每次响应中生成一串加密字符串,并将其嵌入隐藏的input表单中。当用户发起后续请求时,需将该字符串一并提交,以此验证请求是否源自同一用户。

基于上述分析,代码逻辑应遵循以下步骤:首先请求登录页面,接着解析页面以提取_csrf字符串,最后将该字符串与账号密码组合发送至服务器以完成登录。

第一份代码

#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-

import requests
import re

# 头部信息
headers = {
 'Host':"localhost",
 'Accept-Language':"zh-CN,zh;q=0.8",
 'Accept-Encoding':"gzip, deflate",
 'Content-Type':"application/x-www-form-urlencoded",
 'Connection':"keep-alive",
 'Referer':"http://localhost/login",
 'User-Agent':"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36"
}

# 登陆方法
def login(url,csrf):
 data = {
 "_csrf" : csrf,
 "username": "xiedj",
 "password": "***"
 }

 response = requests.post(url, data=data, headers=headers)
 return response.content


# 第一次访问获取csrf值
def get_login_web(url):
 page = requests.get('http://localhost/login')
 reg = r'<meta name="csrf-token" content="(.+)">'
 csrf = re.findall(reg,page.content)[0]
 login_page = login(url,csrf)
 print login_page


if __name__ == "__main__":
 url = "http://localhost/login/checklogin"
 get_login_web(url)

代码逻辑看似无误,但执行时却报错。经核查,错误根源在于_csrf验证失败。

在反复确认获取的_csrf值与登录请求中的_csrf字符串均无误后,引发思考: 若读者尚未发现错误原因,此处可暂停思考一个问题:“服务器如何判定获取_csrf的第一次请求与执行POST登录的第二次请求来自同一用户?”

至此,问题已明晰:若要登录成功,必须解决如何让服务器信任两次请求来自同一用户的问题。这涉及到HTTP会话机制(若不了解可自行查阅,此处仅作简要介绍)。

HTTP协议本质上是一种无状态协议。为使无状态交互具备状态感知,引入了会话机制。简而言之,系统通过session来记录状态。当用户首次请求Web服务时,服务器生成一个session以保存用户信息,并在返回响应时将sessionID存入cookies。当用户再次发起请求时,浏览器会自动携带该cookies,从而使服务器能够识别多次请求是否属于同一用户。

因此,代码逻辑需调整为:在第一次请求时获取sessionID,并在第二次请求时将其一同发送。Requests库的强大之处在于,仅需一行简单的requests.Session()即可创建会话对象,自动处理这一过程。

第二份代码

#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-

import requests
import re

# 头部信息
headers = {
 'Host':"localhost",
 'Accept-Language':"zh-CN,zh;q=0.8",
 'Accept-Encoding':"gzip, deflate",
 'Content-Type':"application/x-www-form-urlencoded",
 'Connection':"keep-alive",
 'Referer':"http://localhost/login",
 'User-Agent':"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36"
}

# 登陆方法
def login(url,csrf,r_session):
 data = {
 "_csrf" : csrf,
 "username": "xiedj",
 "password": "***"
 }

 response = r_session.post(url, data=data, headers=headers)
 return response.content


# 第一次访问获取csrf值
def get_login_web(url):
 r_session = requests.Session()
 page = r_session.get('http://localhost/login')
 reg = r'<meta name="csrf-token" content="(.+)">'
 csrf = re.findall(reg,page.content)[0]


 login_page = login(url,csrf,r_session)
 print login_page


if __name__ == "__main__":
 url = "http://localhost/login/checklogin"
 get_login_web(url)

成功获取登录后的页面内容

从代码可见,使用requests.Session()启动会话对象后,后续的第二次请求会自动携带上一次的sessionID,无需手动传递。

以上即为本文的全部内容,希望对各位的学习有所帮助,也欢迎大家继续支持本站。

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。