在python爬虫中如何处理cookie和session

使用python开发爬虫的过程中,遇到需要登录鉴权的一些页面,必不可少的会接触到cookie和session的使用。本文结合自己最近一次爬虫爬坑的经历,介绍在python爬虫中如何使用Cookie和Session
在这里插入图片描述

Cookie和Session的介绍

Cookie

Cookie 是一种用于跟踪用户会话信息的小型文本文件。它由服务器发送到用户的浏览器,然后由浏览器存储在用户的计算机上。每当用户访问同一站点时,浏览器都会将相关的 Cookie 发送回服务器,以便服务器可以使用它来识别用户并维护用户的状态信息

Session

Session 是一种用于在服务器端存储用户状态信息的机制。与 Cookie 不同,Session 数据存储在服务器上,而不是存储在用户的浏览器中。每个会话都有一个唯一的会话标识符(Session ID),通常存储在用户的 Cookie 中,用于在用户和服务器之间唯一标识会话。

为什么要用到Cookie和Session

假如我们要去访问一些需要登录的页面,爬取需要的信息,我们有以下三中方式:

  1. 人工把浏览器页面的请求header里cookie复制下来,写到python脚本里,这个方法无法保证cookie的时效性
  2. 模拟登录请求,通过代码模拟用户登录的过程,使用requests 库来发送请求,一旦登录成功,保存cookie,后续请求携带上cookie。
  3. 同样模拟登录,但是这里不用保存cookie,使用request.Session发送请求,登录成功,后续都直接使用这个session,服务器会将你视为已登录用户,进行正常的会话。
    第2种方式比较灵活,第3种方式使用起来比较方便,就像使用浏览器登录一样,不需要再考虑cookie的管理和请求添加cookie等,直接使用session发起请求就可以,这里比较推荐第3种方式

使用session保持会话的好处

在requests中,如果直接利用get()或post()等方法的确可以做到模拟网页的请求,但是这实际上是相当于不同的会话,也就是说相当于你用了两个浏览器打开了不同的页面。

设想这样一个场景,第一个请求利用post() 方法登录了某个网站,第二次想获取成功登录后的自己的个人信息, 你又用了一次get()方法去请求个人信息页面。实际上,这相当于打开了两个浏览器,这是两个完全不相关的会话,能成功获取个人信息吗?那当然不能。有小伙伴可能说了,我在两次请求时设置一样的cookies不就行了?可以,但这样做起来显 得很烦琐,我们有更简单的解决方法。

其实解决这个问题的主要方法就是维持同一个会话,也就是相当于打开一个新的浏览器选项 卡而不是新开一个浏览器。但是我又不想每次设置cookies,那该怎么办呢?这时候就有了新的利器一Session对象。利用它,我们可以方便地维护一个会话,而且不用担心 cookies 的问题,它会帮我们自动处理好。requests模块中的Session类能够自动处理发送请求获取响应过程中产生的cookie,进而达到状态保持的目的。接下来我们就来学习它。

在python中如何使用Cookie

如果你已经有了个合法的cookie,可以直接这样使用:

requests.get(url=you_rurl, cookies=your_cookie)

后续每次请求都这样带着cookie就可以,比较繁琐,下面重点介绍如何使用Session

在python中如何使用Session

reqeust.Session()

# 新建一个会话
session = requests.Session()
# 使用这个会话发起一个请求,模拟登录
session.post(url=you_url, data={'你的参数'})
# 如果上一个请求成功,这个请求就可以直接获取到数据,因为session已经把上个请求返回的cookie自动带上了
session.get(url=you_url)

所以requests.session能自动处理 cookie , 下一次发起请求时会自动带上前一次的 cookie,不需要像使用cookie的方式一样每次都手动处理,极大的方便了请求的业务逻辑。

案例:使用session维持github会话

对这个案例进行分析有以下步骤:

  1. 对 github 登陆以及访问登陆后才能访问的页面的整个完成过程进行抓包分析,比如分析登录参数是什么
  2. 确定登陆请求的 url 地址、请求方法和所需的请求参数
  3. 部分请求参数在别的 url 对应的响应内容中,可以使用 re 模块获取
  4. 确定登陆后才能访问的页面的的 url 地址和请求方法
  5. 利用 requests.session 完成代码
import requests
import re
# 构造请求头字典
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (
KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36',}
# 实例化session对象
session = requests.session()
# 访问登陆页获取登陆请求所需参数
response = session.get(https://github.com/login, headers=headers)
authenticity_token = re.search('name="authenticity_token" value="(.*?)" />',
response.text).group(1) # 使用正则获取登陆请求所需参数
# 构造登陆请求参数字典
data = {
'commit': 'Sign in', # 固定值
'utf8': ' ', # 固定值
'authenticity_token': authenticity_token, # 该参数在登陆页的响应内容中
'login':
input('输入github账号:'),
'password':
input('输入github账号:')}
# 发送登陆请求(无需关注本次请求的响应)
session.post(https://github.com/session, headers=headers, data=data)
# 打印需要登陆后才能访问的页面
response = session.get(https://github.com/settings/profile, headers=headers)
print(response.text)

最佳实践参考

使用session需要每次打开程序都登录,但是有的时候,登录信息并没有过期,如何真正像浏览器一样,及时关闭了浏览器再重新打开,只要cookie不过期,也不需要重新登录。这里就需要把cookie做持久化,然后加载cookie到session中,这样就能通过持久化的cookie构造一个session,避免重复多次登录。

cookie持久化存储和加载

登录成功后,把session中的cookie取出做持久化存储,这里存储到文件中。保存cookie的对象是RequestsCookieJar,我们需要把他转成字典,不能直接使用__dict__方法,需要使用两个特殊函数requests.utils.dict_from_cookiejar将RequestsCookieJar转成字典,然后再使用requests.utils.cookiejar_from_dict(new_cookie_jar),可以将字典转成RequestsCookieJar,参考下面代码:

####### 持久化存储
# 转成字典
cookiejar = requests.utils.dict_from_cookiejar(request_session.cookies)
# 转成json存储到文件中
# 登录成功, session里的cookie是最全的
    cookiejar = requests.utils.dict_from_cookiejar(request_session.cookies)
    with open(cookie_path, "w") as f:
        json.dump(cookiejar, f, indent=True)
    logging.info('cookies saved to ./data/cookie.txt')


####### 取出cookie加载到session
session = reqeust.Session()
with open(cookie_path, "r") as f:
    load_cookie = json.load(f)
    whv_logger.info(f"load_cookie from file: {load_cookie}")
    exist_cookies =  requests.utils.cookiejar_from_dict(load_cookie)
    session.cookies.update(exist_cookies)

完整的cookie持久化方案参考

在这里顶一个模块专门处理cookie的持久和加载,定义个全局变量request_session用来管理全局的会话。登录完成之后,调用save_cookie方法更新全局session

import json
import traceback

import requests.utils

cookie_path = './data/cookie.txt'
request_session: requests.Session = None

def __load_cookie():
    '''
    加载本地cookie,如果存在加载,如果不存在就返回空
    :param session:
    :return:
    '''
    try:
        with open(cookie_path, "r") as f:
            load_cookie = json.load(f)
            logging.info(f"load_cookie from file: {load_cookie}")
            return requests.utils.cookiejar_from_dict(load_cookie)
    except Exception as e:
        traceback.print_exc()
        logging.error("failed load cookie, error:%s", e)
        return None

def get_session():
    global request_session
    if request_session is not None:
        return request_session
    else:
        request_session = requests.Session()
        exist_cookies = __load_cookie()
        if exist_cookies is not None:
            request_session.cookies.update(exist_cookies)

        return request_session

def save_cookie():
    # 登录成功, session里的cookie是最全的,response返回的cookie不全
    cookiejar = requests.utils.dict_from_cookiejar(request_session.cookies)
    with open(cookie_path, "w") as f:
        json.dump(cookiejar, f, indent=True)
    logging.info('cookies saved to ./data/cookie.txt')


def update_cookie():
    '''
    这个方法需要具体场景具体分析,并不一定都用到。
    为什么需要一个新的session
    # 走到这一步,说明session已经过期,重新获取session,需要重新处理下session
    :return:
    '''
    error_cookie_jar = requests.utils.dict_from_cookiejar(request_session.cookies)
    # 替换自己需要处理的cookie中的参数
    new_cookie_jar = {'__RequestVerificationToken': error_cookie_jar['__RequestVerificationToken']}
    new_cookie = requests.utils.cookiejar_from_dict(new_cookie_jar)

    # 清空旧的cookie
    request_session.cookies.clear_session_cookies()
    # 填充新的cookie
    request_session.cookies.update(new_cookie)

相关推荐

  1. DjangoCookieSession

    2024-04-12 19:16:06       19 阅读
  2. cookiesession

    2024-04-12 19:16:06       36 阅读
  3. PHP cookieSessions

    2024-04-12 19:16:06       42 阅读
  4. 聊聊SessionCookie

    2024-04-12 19:16:06       39 阅读
  5. cookie+sessiontoken

    2024-04-12 19:16:06       30 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-12 19:16:06       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-12 19:16:06       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-12 19:16:06       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-12 19:16:06       20 阅读

热门阅读

  1. 对用户上传图片进行压缩

    2024-04-12 19:16:06       14 阅读
  2. 请求的数据类型{ }{[ ]} 解析

    2024-04-12 19:16:06       20 阅读
  3. fastjson2 简单使用案例

    2024-04-12 19:16:06       15 阅读
  4. Qt安装 qt-unified-windows-x64-online.exe下载慢

    2024-04-12 19:16:06       11 阅读
  5. 苍穹外卖总结

    2024-04-12 19:16:06       16 阅读
  6. Yarn vs npm的大同小异&Yarn是什么?

    2024-04-12 19:16:06       13 阅读
  7. linux常用命令汇总

    2024-04-12 19:16:06       16 阅读
  8. leetcode热题HOT 200. 岛屿数量(深入理解DFS和BFS)

    2024-04-12 19:16:06       16 阅读