使用CookieJar提取cookie信息

该文章介绍了如何在Python中使用cookiejar库来管理cookie,特别是通过MozillaCookieJar类存储和加载cookie。它详细展示了如何在xmlrpc通信中添加和处理cookie,以及如何将cookie保存到文件中以便后续使用。文章强调了国外的做法相对于国内的复杂性和底层实现的差异。
摘要由CSDN通过智能技术生成

首先,推荐几个帖子,大伙可以先看看。国内通过cookiejar主要获取cookie的方法,大致都是如此的。

http.cookiejar库之CookieJar_pigYanYan的博客-CSDN博客

Python编程:cookiejar的使用_彭世瑜的博客-CSDN博客

再推荐一个资料帖,这个帖子主要涉及后面介绍的一种获取cookie的过程中所使用的一个方法。

cookielib_网络 | Internet_Python_参考手册_非常教程

本此,之所以写这个贴子主要是记录下,国外通过cookiejar是如何获取cookie的。总的来说,要比国内搞得复杂的多,但是也底层的多。

import gzip, os
from http import cookiejar
from urllib.request import Request
from xmlrpc.client import Transport

BUGZILLA_COOKIE_FILE = '/tmp/.bugzilla-cookies.txt'


class CookieTransport(Transport):
    """
    A subclass of xmlrpclib.Transport that supports cookies.
    """
    cookiejar = None

    def __init__(self, use_datetime=0, url=None):
        """
        Extend xmlrpclib.Transport's constructor to include url
        """
        self.url = url
        super(CookieTransport, self).__init__(use_datetime=use_datetime)

    def send_cookies(self, connection, cookie_request):
        """
        Send cookies to Bugzilla server
        """
        if self.cookiejar is None:
            # 实例化 MozillaCookieJar,这里国内外用法一致
            # BUGZILLA_COOKIE_FILE是用来存储具体的cookie信息的文件
            self.cookiejar = cookiejar.MozillaCookieJar(BUGZILLA_COOKIE_FILE)

            if os.path.exists(BUGZILLA_COOKIE_FILE):
                # 再次运行的时候,就可以直接读取cookie信息了
                self.cookiejar.load(BUGZILLA_COOKIE_FILE)
            else:
                # 初次运行,文件BUGZILLA_COOKIE_FILE是不存在的,所以save一把,用于创建文件
                self.cookiejar.save(BUGZILLA_COOKIE_FILE)

        # 将cookie信息从MozillaCookieJar对象中提取出来,添加到 cookie_request 对象的header里去
        # cookie_request对象就是 urllib.request.Request 对象,如果,有先看国内搞cookie的那几个
        # 帖子,就应该知道,用国内的方法,只需传入 urllib.request.Request 对象,去实际访问服务器的时候
        # 就可以直接获取到 cookie 信息了。而其具体实现的过程,就包括了下面的这个步骤,这里相当与将国内
        # 介绍的一体化操作,又分解了
        # 这里注意,初次运行代码到这里的时候,是不会添加啥东西出来的,因为这个时候,MozillaCookieJar
        # 对象此时还没有获取到cookie信息呢,只有再次运行到此处的时候,代码执行 self.cookiejar.load(BUGZILLA_COOKIE_FILE)
        # 动作的时候,self.cookiejar中才会存在具体的cookie信息,然后才能将其添加到cookie_request(即urllib.request.Request)
        # 对象的header中
        self.cookiejar.add_cookie_header(cookie_request)

        # 从 urllib.request.Request 对象中提取cookie信息
        cookielist = list()
        for header, headerdata in cookie_request.header_items():
            if header.startswith('Cookie'):
                cookielist.append([header, headerdata])
        # 将cookie添加到connection对象
        for header, headerdata in cookielist:
            connection.putheader(header, headerdata)
    
    def single_request_with_cookies(self, host, handler, request_body, verbose=False):
        # 首先一样是先造一个Request对象(其作用本身就是用于存储一些信息的,比如:url,header等)
        request_url = "https://%s%s" % (host, handler)
        cookie_request = Request(request_url)

        # 然后造一个发送请求的对象, 本来按照如下方法正常创造即可,但是,
        # 由于我们后续需要对header添加cookie,所以就不能如此使用了,python2.7版本可以这样用
        # 但是3.8版本是完全不行了,3.8版本对send_request方法做出了高度的集成改动,总体来说
        # 可以更加方便的创建可以发送请求的connect对象了,但是同样降低了其使用的灵活性,就比如
        # 给connect对象添加cookie,就会变得无法实现

        # h = self.send_request(host, handler, request_body, debug=verbose)

        # 这里我将python3.8版本里的 send_request 函数里的内容直接从xmlrpc库提取出来,直接用
        # 注意具体的使用会和send_request中略有不同,send_request方法的原始内容,我放到下面了
        h = self.make_connection(host)
        headers = self._headers + self._extra_headers
        if verbose:
            h.set_debuglevel(1)
        if self.accept_gzip_encoding and gzip:
            h.putrequest("POST", handler, skip_accept_encoding=True)
            headers.append(("Accept-Encoding", "gzip"))
        else:
            h.putrequest("POST", handler)
        headers.append(("Content-Type", "text/xml"))
        headers.append(("User-Agent", self.user_agent))
        self.send_headers(h, headers)

        # 注意,要修改header的内容,必须要在send_content动作之前
        # 这里就是添加cookie到header的地方, 也是实例化 MozillaCookieJar 对象的地方
        self.send_cookies(h, cookie_request)
        # 将request_body发送到服务器
        self.send_content(h, request_body)

        # 获取来自服务器的相应,而这个相应中,就蕴含着cookie信息
        response = h.getresponse()

        # 这个类是有必要造的,因为后续从response中提取cookie的时候,需要这样一种
        # 数据结构
        class CookieResponse:
            """
            parse headers and get cookies here
            fake a response object that we can fill with the headers above
            """

            def __init__(self, headers):
                self.headers = headers

            def info(self):
                return self.headers

        # 构建extract_cookies所需的参数
        cookie_response = CookieResponse(response.msg)
        # 从response中提取cookie信息
        # 正如上面send_cookies方法的注释中所提到的,这是将一体化动作拆分的过程。
        # cookie_request对象起一定的校验功能。另外就是,原本在一体化执行的过程,所有
        # 调用过程均存在于内部,外部仅需传入一个urllib.request.Request对象,所以
        # 此处在模仿内部调用的过程,就肯定也需要构造一个同样的对象,供其使用,因此在我
        # 看来,extract_cookies方法的重头戏就是从response提取cookie,传入cookie_request
        # 的目的更像是打个辅助罢了
        self.cookiejar.extract_cookies(cookie_response, cookie_request)

        # 将提取到的cookie信息,保存到文件中
        self.cookiejar.save(self.cookiejar.filename)

        if response.status == 200:
            self.verbose = verbose
            return self.parse_response(response)

    def send_request(self, host, handler, request_body, debug):
        """
        xmlrpc.client.Transport.send_request()的原始内容
        """
        connection = self.make_connection(host)
        headers = self._headers + self._extra_headers
        if debug:
            connection.set_debuglevel(1)
        if self.accept_gzip_encoding and gzip:
            connection.putrequest("POST", handler, skip_accept_encoding=True)
            headers.append(("Accept-Encoding", "gzip"))
        else:
            connection.putrequest("POST", handler)
        headers.append(("Content-Type", "text/xml"))
        headers.append(("User-Agent", self.user_agent))
        self.send_headers(connection, headers)
        self.send_content(connection, request_body)

注意,上述内容,为演示,说明内容,并不是说,照搬可以完整执行哈。

关于 def send_cookies(self, connection, cookie_request): 方法做一个演示:

在执行 self.cookiejar.add_cookie_header(cookie_request) 之前,cookie_request 对象长这样:

 执行之后,长这样:

 这不是果断加进header了。

另外,关于 self.cookiejar.save(self.cookiejar.filename) 保存cookie信息到文件,也介绍一个:

执行保存动作之前,.bugzilla-cookies.txt 文件长这样:

 之后:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值