首先,推荐几个帖子,大伙可以先看看。国内通过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 文件长这样:
之后: