http.cookiejar — HTTP 客户端的 Cookie 处理

源代码: Lib/http/cookiejar.py


http.cookiejar 模块定义了用于自动处理 HTTP Cookie 的类。它对于访问那些需要Web服务器通过HTTP响应在客户端机器上设置一小段数据——即 Cookie,然后在后续的HTTP请求中将其返回给服务器的网站非常有用。

该模块同时处理常规的 Netscape Cookie 协议和 RFC 2965 定义的协议。默认情况下,RFC 2965 的处理是关闭的。RFC 2109 Cookie 会被解析为 Netscape Cookie,然后根据生效的“策略”被当作 Netscape 或 RFC 2965 Cookie 处理。请注意,互联网上绝大多数 Cookie 都是 Netscape Cookie。http.cookiejar 模块试图遵循事实上的 Netscape Cookie 协议(这与最初 Netscape 规范中规定的有很大不同),包括注意 RFC 2965 引入的 max-ageport Cookie 属性。

备注

Set-CookieSet-Cookie2 头中找到的各种命名参数(例如 domainexpires)通常被称为 attributes (属性)。为了与 Python 的属性 (attribute) 区分开来,本模块的文档使用术语 cookie-attribute (Cookie 属性)。

该模块定义了以下异常:

exception http.cookiejar.LoadError

FileCookieJar 的实例在从文件加载 Cookie 失败时会引发此异常。LoadErrorOSError 的子类。

在 3.3 版本发生变更: LoadError 过去是 IOError 的子类型,现在 IOError 已成为 OSError 的别名。

提供了以下类:

class http.cookiejar.CookieJar(policy=None)

policy 是一个实现了 CookiePolicy 接口的对象。

CookieJar 类存储 HTTP Cookie。它从 HTTP 请求中提取 Cookie,并在 HTTP 响应中返回它们。CookieJar 实例会在必要时自动使包含的 Cookie 过期。其子类还负责从文件或数据库中存储和检索 Cookie。

class http.cookiejar.FileCookieJar(filename=None, delayload=None, policy=None)

policy 是一个实现了 CookiePolicy 接口的对象。对于其他参数,请参阅相应属性的文档。

一个 CookieJar,可以从磁盘上的文件中加载 Cookie,也可能将 Cookie 保存到文件中。除非调用 load()revert() 方法,否则 Cookie 不会从指定的文件中加载。这个类的子类在 FileCookieJar 的子类以及与 Web 浏览器的协作 一节中有文档说明。

不应直接初始化此类——应使用其下方的子类。

在 3.8 版本发生变更: filename 形参支持 path-like object

class http.cookiejar.CookiePolicy

这个类负责决定每个 Cookie 是否应该被服务器接受或返回给服务器。

class http.cookiejar.DefaultCookiePolicy(blocked_domains=None, allowed_domains=None, netscape=True, rfc2965=False, rfc2109_as_netscape=None, hide_cookie2=False, strict_domain=False, strict_rfc2965_unverifiable=True, strict_ns_unverifiable=False, strict_ns_domain=DefaultCookiePolicy.DomainLiberal, strict_ns_set_initial_dollar=False, strict_ns_set_path=False, secure_protocols=('https', 'wss'))

构造函数参数应仅作为关键字参数传递。blocked_domains 是一个域名序列,我们永远不会接受来自这些域名的 Cookie,也不会向它们返回 Cookie。如果 allowed_domains 不为 None,则它是一个我们只接受和返回 Cookie 的域名序列。secure_protocols 是一个协议序列,可以为这些协议添加安全 Cookie。默认情况下,httpswss (安全 WebSocket) 被视为安全协议。对于所有其他参数,请参阅 CookiePolicyDefaultCookiePolicy 对象的文档。

DefaultCookiePolicy 实现了针对 Netscape 和 RFC 2965 Cookie 的标准接受/拒绝规则。默认情况下,RFC 2109 Cookie(即在 Set-Cookie 头部中收到的,版本 Cookie 属性为 1 的 Cookie)会根据 RFC 2965 规则处理。然而,如果 RFC 2965 处理被关闭,或者 rfc2109_as_netscapeTrueCookieJar 实例会将 RFC 2109 Cookie“降级”为 Netscape Cookie,方法是将 Cookie 实例的 version 属性设置为 0。DefaultCookiePolicy 还提供了一些参数以允许对策略进行一些微调。

class http.cookiejar.Cookie

这个类代表 Netscape、RFC 2109RFC 2965 Cookie。不希望 http.cookiejar 的用户自己构造 Cookie 实例。如有必要,应在 CookieJar 实例上调用 make_cookies()

参见

模块 urllib.request

使用自动 Cookie 处理打开 URL。

模块 http.cookies

HTTP Cookie 类,主要用于服务器端代码。http.cookiejarhttp.cookies 模块互不依赖。

https://curl.se/rfc/cookie_spec.html

最初的 Netscape Cookie 协议规范。尽管这仍然是主流协议,但所有主流浏览器(以及 http.cookiejar)实现的“Netscape Cookie 协议”与 cookie_spec.html 中描述的协议仅有微弱的相似之处。

RFC 2109 - HTTP 状态管理机制

已被 RFC 2965 废弃。使用带有 version=1 的 Set-Cookie

RFC 2965 - HTTP 状态管理机制

修复了 Netscape 协议错误的协议。使用 Set-Cookie2 替代 Set-Cookie。未被广泛使用。

https://kristol.org/cookie/errata.html

RFC 2965 的未完成勘误表。

RFC 2964 - HTTP 状态管理的使用

CookieJar 和 FileCookieJar 对象

CookieJar 对象支持迭代器协议,用于遍历其中包含的 Cookie 对象。

CookieJar 具有以下方法:

request 添加正确的 Cookie 标头。

如果策略允许(即,CookieJarCookiePolicy 实例的 rfc2965hide_cookie2 属性分别为 true 和 false),则在适当时也会添加 Cookie2 标头。

request 对象(通常是 urllib.request.Request 的实例)必须支持 get_full_url(), has_header(), get_header(), header_items(), add_unredirected_header() 方法,以及 host, type, unverifiableorigin_req_host 属性,具体如 urllib.request 所述。

在 3.3 版本发生变更: request 对象需要 origin_req_host 属性。已移除对已弃用方法 get_origin_req_host() 的依赖。

CookieJar.extract_cookies(response, request)

从 HTTP response 中提取 Cookie,并在策略允许的情况下将它们存储在 CookieJar 中。

CookieJar 会在 response 参数中查找允许的 Set-CookieSet-Cookie2 标头,并根据情况存储 Cookie(需经 CookiePolicy.set_ok() 方法批准)。

response 对象(通常是调用 urllib.request.urlopen() 或类似函数的结果)应支持一个 info() 方法,该方法返回一个 email.message.Message 实例。

request 对象(通常是 urllib.request.Request 的实例)必须支持 get_full_url() 方法,以及 hostunverifiableorigin_req_host 属性,具体如 urllib.request 所述。该请求用于为 Cookie 属性设置默认值,以及检查是否允许设置该 Cookie。

在 3.3 版本发生变更: request 对象需要 origin_req_host 属性。已移除对已弃用方法 get_origin_req_host() 的依赖。

CookieJar.set_policy(policy)

设置要使用的 CookiePolicy 实例。

CookieJar.make_cookies(response, request)

返回从 response 对象中提取的 Cookie 对象序列。

关于 responserequest 参数所需的接口,请参阅 extract_cookies() 的文档。

如果策略允许,则设置一个 Cookie

设置一个 Cookie,不检查策略是否允许设置。

CookieJar.clear([domain[, path[, name]]])

清除一些 Cookie。

如果不带参数调用,则清除所有 Cookie。如果给定一个参数,则只删除属于该 domain 的 Cookie。如果给定两个参数,则删除属于指定 domain 和 URL path 的 Cookie。如果给定三个参数,则删除具有指定 domainpathname 的 Cookie。

如果不存在匹配的 Cookie,则引发 KeyError

CookieJar.clear_session_cookies()

丢弃所有会话 Cookie。

丢弃所有 discard 属性为 true 的 Cookie(通常是因为它们没有 max-ageexpires Cookie 属性,或者有明确的 discard Cookie 属性)。对于交互式浏览器,会话结束通常对应于关闭浏览器窗口。

注意,save() 方法不会保存会话 Cookie,除非你通过传递一个 true 的 ignore_discard 参数来请求保存。

FileCookieJar 实现了以下附加方法:

FileCookieJar.save(filename=None, ignore_discard=False, ignore_expires=False)

将 Cookie 保存到文件。

此基类会引发 NotImplementedError。子类可以不实现此方法。

filename 是保存 Cookie 的文件名。如果未指定 filename,则使用 self.filename(其默认值是传递给构造函数的值,如果有的话);如果 self.filenameNone,则引发 ValueError

ignore_discard:即使是被设置为丢弃的 Cookie 也保存。ignore_expires:即使是已过期的 Cookie 也保存。

如果文件已存在,则会覆盖它,从而清除其中包含的所有 Cookie。保存的 Cookie 之后可以使用 load()revert() 方法恢复。

FileCookieJar.load(filename=None, ignore_discard=False, ignore_expires=False)

从文件中加载 Cookie。

旧的 Cookie 会被保留,除非被新加载的 Cookie 覆盖。

参数与 save() 的参数相同。

指定的文件必须是该类所理解的格式,否则将引发 LoadError。此外,也可能引发 OSError,例如,如果文件不存在。

在 3.3 版本发生变更: 过去会引发 IOError,现在它是 OSError 的别名。

FileCookieJar.revert(filename=None, ignore_discard=False, ignore_expires=False)

清除所有 Cookie 并从已保存的文件中重新加载 Cookie。

revert() 可能引发与 load() 相同的异常。如果发生故障,对象的状态将不会被改变。

FileCookieJar 实例具有以下公共属性:

FileCookieJar.filename

用于保存 Cookie 的默认文件的文件名。该属性可以被赋值。

FileCookieJar.delayload

如果为真,则从磁盘延迟加载 Cookie。不应给该属性赋值。这只是一个提示,因为它只影响性能,不影响行为(除非磁盘上的 Cookie 正在改变)。CookieJar 对象可能会忽略它。标准库中包含的 FileCookieJar 类都不会延迟加载 Cookie。

FileCookieJar 的子类以及与 Web 浏览器的协作

提供了以下 CookieJar 子类用于读写操作。

class http.cookiejar.MozillaCookieJar(filename=None, delayload=None, policy=None)

一个 FileCookieJar,可以以 Mozilla 的 cookies.txt 文件格式(curl、Lynx 和 Netscape 浏览器也使用此格式)从磁盘加载和保存 Cookie。

备注

这会丢失关于 RFC 2965 Cookie 的信息,以及较新的或非标准的 Cookie 属性,如 port

警告

如果你的 Cookie 丢失或损坏会带来不便,请在保存前备份你的 Cookie(存在一些微妙之处,可能导致文件在加载/保存往返过程中发生轻微变化)。

另请注意,在 Mozilla 运行时保存的 Cookie 会被 Mozilla 覆盖。

class http.cookiejar.LWPCookieJar(filename=None, delayload=None, policy=None)

一个 FileCookieJar,可以以与 libwww-perl 库的 Set-Cookie3 文件格式兼容的格式从磁盘加载和保存 Cookie。如果你想将 Cookie 存储在人类可读的文件中,这将非常方便。

在 3.8 版本发生变更: filename 形参支持 path-like object

CookiePolicy 对象

实现了 CookiePolicy 接口的对象具有以下方法:

CookiePolicy.set_ok(cookie, request)

返回一个布尔值,指示是否应接受来自服务器的 Cookie。

cookie 是一个 Cookie 实例。request 是一个实现了 CookieJar.extract_cookies() 文档中定义接口的对象。

CookiePolicy.return_ok(cookie, request)

返回一个布尔值,指示是否应将 Cookie 返回给服务器。

cookie 是一个 Cookie 实例。request 是一个实现了 CookieJar.add_cookie_header() 文档中定义接口的对象。

CookiePolicy.domain_return_ok(domain, request)

如果给定 Cookie 域不应返回 Cookie,则返回 False

这个方法是一种优化。它避免了检查每个具有特定域的 Cookie(这可能涉及读取许多文件)。从 domain_return_ok()path_return_ok() 返回 true 会将所有工作留给 return_ok()

如果 domain_return_ok() 对 Cookie 域返回 true,则会为 Cookie 路径调用 path_return_ok()。否则,对于该 Cookie 域,永远不会调用 path_return_ok()return_ok()。如果 path_return_ok() 返回 true,则会使用 Cookie 对象本身调用 return_ok() 进行全面检查。否则,对于该 Cookie 路径,永远不会调用 return_ok()

请注意,domain_return_ok() 是为每个 cookie 域调用的,而不仅仅是为 request 域。例如,如果请求域是 "www.example.com",该函数可能会同时被 ".example.com""www.example.com" 调用。同样的情况也适用于 path_return_ok()

request 参数的文档与 return_ok() 一致。

CookiePolicy.path_return_ok(path, request)

如果给定 Cookie 路径不应返回 Cookie,则返回 False

请参阅 domain_return_ok() 的文档。

除了实现上述方法外,CookiePolicy 接口的实现还必须提供以下属性,指示应使用哪些协议以及如何使用。所有这些属性都可以被赋值。

CookiePolicy.netscape

实现 Netscape 协议。

CookiePolicy.rfc2965

实现 RFC 2965 协议。

CookiePolicy.hide_cookie2

不要向请求添加 Cookie2 标头(此标头的存在向服务器表明我们理解 RFC 2965 Cookie)。

定义 CookiePolicy 类的最有用方法是继承自 DefaultCookiePolicy 并重写上述部分或全部方法。CookiePolicy 本身可以用作“空策略”,以允许设置和接收任何和所有 Cookie(这可能不太有用)。

DefaultCookiePolicy 对象

实现了接受和返回 Cookie 的标准规则。

RFC 2965 和 Netscape Cookie 都被涵盖。默认情况下,RFC 2965 的处理是关闭的。

提供您自己的策略的最简单方法是重写此类,并在您重写的实现中调用其方法,然后再添加您自己的额外检查。

import http.cookiejar
class MyCookiePolicy(http.cookiejar.DefaultCookiePolicy):
    def set_ok(self, cookie, request):
        if not http.cookiejar.DefaultCookiePolicy.set_ok(self, cookie, request):
            return False
        if i_dont_want_to_store_this_cookie(cookie):
            return False
        return True

除了实现 CookiePolicy 接口所需的功能外,此类还允许您阻止和允许域设置和接收 Cookie。还有一些严格性开关,可以让您稍微收紧相当宽松的 Netscape 协议规则(代价是阻止一些良性的 Cookie)。

提供了一个域黑名单和白名单(默认都关闭)。只有不在黑名单中且存在于白名单中(如果白名单是激活的)的域才会参与 Cookie 的设置和返回。使用 blocked_domains 构造函数参数,以及 blocked_domains()set_blocked_domains() 方法(以及对应的 allowed_domains 参数和方法)。如果您设置了白名单,您可以通过将其设置为 None 来再次关闭它。

黑名单或白名单中不以点开头的域必须与 Cookie 域完全相等才能匹配。例如,"example.com" 匹配黑名单条目 "example.com",但 "www.example.com" 不匹配。以点开头的域也匹配更具体的域。例如,"www.example.com""www.coyote.example.com" 都匹配 ".example.com"(但 "example.com" 本身不匹配)。IP 地址是例外,必须精确匹配。例如,如果 blocked_domains 包含 "192.168.1.2"".168.1.2",则 192.168.1.2 被阻止,但 193.168.1.2 不被阻止。

DefaultCookiePolicy 实现了以下附加方法:

DefaultCookiePolicy.blocked_domains()

返回被阻止的域名序列(以元组形式)。

DefaultCookiePolicy.set_blocked_domains(blocked_domains)

设置被阻止的域名序列。

DefaultCookiePolicy.is_blocked(domain)

如果 domain 在设置或接收 Cookie 的黑名单上,则返回 True

DefaultCookiePolicy.allowed_domains()

返回 None,或允许的域名序列(以元组形式)。

DefaultCookiePolicy.set_allowed_domains(allowed_domains)

设置允许的域名序列,或 None

DefaultCookiePolicy.is_not_allowed(domain)

如果 domain 不在设置或接收 Cookie 的白名单上,则返回 True

DefaultCookiePolicy 实例具有以下属性,这些属性都从同名的构造函数参数初始化,并且都可以被赋值。

DefaultCookiePolicy.rfc2109_as_netscape

如果为 true,则请求 CookieJar 实例将 RFC 2109 Cookie(即在 Set-Cookie 标头中收到的,版本 Cookie 属性为 1 的 Cookie)降级为 Netscape Cookie,方法是将 Cookie 实例的版本属性设置为 0。默认值为 None,在这种情况下,当且仅当 RFC 2965 处理被关闭时,RFC 2109 Cookie 才会被降级。因此,默认情况下 RFC 2109 Cookie 会被降级。

通用严格性开关

DefaultCookiePolicy.strict_domain

不允许网站设置具有国家代码顶级域名(如 .co.uk.gov.uk.co.nz 等)的双部分域名。这远非完美,并不能保证一定有效!

RFC 2965 协议严格性开关

DefaultCookiePolicy.strict_rfc2965_unverifiable

遵循 RFC 2965 关于不可验证事务的规则(通常,不可验证事务是由重定向或对托管在其他站点上的图像的请求产生的)。如果此值为 false,则 Cookie 永远不会因可验证性而被阻止。

Netscape 协议严格性开关

DefaultCookiePolicy.strict_ns_unverifiable

即使对于 Netscape Cookie,也应用 RFC 2965 关于不可验证事务的规则。

DefaultCookiePolicy.strict_ns_domain

指示对 Netscape Cookie 的域匹配规则的严格程度的标志。可接受的值见下文。

DefaultCookiePolicy.strict_ns_set_initial_dollar

忽略 Set-Cookie: 标头中名称以 '$' 开头的 Cookie。

DefaultCookiePolicy.strict_ns_set_path

不允许设置其路径与请求 URI 不匹配的 Cookie。

strict_ns_domain 是一个标志集合。它的值通过或运算构造(例如,DomainStrictNoDots|DomainStrictNonDomain 意味着两个标志都已设置)。

DefaultCookiePolicy.DomainStrictNoDots

设置 Cookie 时,“主机前缀”不能包含点(例如,www.foo.bar.com 不能为 .bar.com 设置 Cookie,因为 www.foo 包含一个点)。

DefaultCookiePolicy.DomainStrictNonDomain

未明确指定 domain Cookie 属性的 Cookie 只能返回给与设置该 Cookie 的域相等的域(例如,spam.example.com 不会收到来自 example.com 且没有 domain Cookie 属性的 Cookie)。

DefaultCookiePolicy.DomainRFC2965Match

设置 Cookie 时,需要完全的 RFC 2965 域匹配。

以下属性为方便起见而提供,是上述标志的最有用组合:

DefaultCookiePolicy.DomainLiberal

等同于 0(即,上述所有 Netscape 域严格性标志都关闭)。

DefaultCookiePolicy.DomainStrict

等同于 DomainStrictNoDots|DomainStrictNonDomain

示例

第一个示例展示了 http.cookiejar 的最常见用法

import http.cookiejar, urllib.request
cj = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
r = opener.open("http://example.com/")

此示例说明了如何使用你的 Netscape、Mozilla 或 Lynx cookie 打开 URL(假设 cookie 文件的位置遵循 Unix/Netscape 约定)

import os, http.cookiejar, urllib.request
cj = http.cookiejar.MozillaCookieJar()
cj.load(os.path.join(os.path.expanduser("~"), ".netscape", "cookies.txt"))
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
r = opener.open("http://example.com/")

下一个示例说明了 DefaultCookiePolicy 的使用。启用 RFC 2965 cookie,在设置和返回 Netscape cookie 时对域进行更严格的检查,并阻止某些域设置或返回 cookie

import urllib.request
from http.cookiejar import CookieJar, DefaultCookiePolicy
policy = DefaultCookiePolicy(
    rfc2965=True, strict_ns_domain=Policy.DomainStrict,
    blocked_domains=["ads.net", ".ads.net"])
cj = CookieJar(policy)
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
r = opener.open("http://example.com/")