http.cookiejar
— HTTP 客户端的 Cookie 处理¶
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-age
和 port
Cookie 属性。
备注
在 Set-Cookie 和 Set-Cookie2 头中找到的各种命名参数(例如 domain
和 expires
)通常被称为 attributes (属性)。为了与 Python 的属性 (attribute) 区分开来,本模块的文档使用术语 cookie-attribute (Cookie 属性)。
该模块定义了以下异常:
- exception http.cookiejar.LoadError¶
FileCookieJar
的实例在从文件加载 Cookie 失败时会引发此异常。LoadError
是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。默认情况下,https 和 wss (安全 WebSocket) 被视为安全协议。对于所有其他参数,请参阅CookiePolicy
和DefaultCookiePolicy
对象的文档。DefaultCookiePolicy
实现了针对 Netscape 和 RFC 2965 Cookie 的标准接受/拒绝规则。默认情况下,RFC 2109 Cookie(即在 Set-Cookie 头部中收到的,版本 Cookie 属性为 1 的 Cookie)会根据 RFC 2965 规则处理。然而,如果 RFC 2965 处理被关闭,或者rfc2109_as_netscape
为True
,CookieJar
实例会将 RFC 2109 Cookie“降级”为 Netscape Cookie,方法是将Cookie
实例的version
属性设置为 0。DefaultCookiePolicy
还提供了一些参数以允许对策略进行一些微调。
- class http.cookiejar.Cookie¶
这个类代表 Netscape、RFC 2109 和 RFC 2965 Cookie。不希望
http.cookiejar
的用户自己构造Cookie
实例。如有必要,应在CookieJar
实例上调用make_cookies()
。
参见
- 模块
urllib.request
使用自动 Cookie 处理打开 URL。
- 模块
http.cookies
HTTP Cookie 类,主要用于服务器端代码。
http.cookiejar
和http.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
具有以下方法:
- CookieJar.add_cookie_header(request)¶
向 request 添加正确的 Cookie 标头。
如果策略允许(即,
CookieJar
的CookiePolicy
实例的rfc2965
和hide_cookie2
属性分别为 true 和 false),则在适当时也会添加 Cookie2 标头。request 对象(通常是
urllib.request.Request
的实例)必须支持get_full_url()
,has_header()
,get_header()
,header_items()
,add_unredirected_header()
方法,以及host
,type
,unverifiable
和origin_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-Cookie 和 Set-Cookie2 标头,并根据情况存储 Cookie(需经CookiePolicy.set_ok()
方法批准)。response 对象(通常是调用
urllib.request.urlopen()
或类似函数的结果)应支持一个info()
方法,该方法返回一个email.message.Message
实例。request 对象(通常是
urllib.request.Request
的实例)必须支持get_full_url()
方法,以及host
、unverifiable
和origin_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
对象序列。关于 response 和 request 参数所需的接口,请参阅
extract_cookies()
的文档。
- CookieJar.clear([domain[, path[, name]]])¶
清除一些 Cookie。
如果不带参数调用,则清除所有 Cookie。如果给定一个参数,则只删除属于该 domain 的 Cookie。如果给定两个参数,则删除属于指定 domain 和 URL path 的 Cookie。如果给定三个参数,则删除具有指定 domain、path 和 name 的 Cookie。
如果不存在匹配的 Cookie,则引发
KeyError
。
- CookieJar.clear_session_cookies()¶
丢弃所有会话 Cookie。
丢弃所有
discard
属性为 true 的 Cookie(通常是因为它们没有max-age
或expires
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.filename
是None
,则引发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
,例如,如果文件不存在。
- FileCookieJar.revert(filename=None, ignore_discard=False, ignore_expires=False)¶
清除所有 Cookie 并从已保存的文件中重新加载 Cookie。
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
类的最有用方法是继承自 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.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_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.DomainLiberal¶
等同于 0(即,上述所有 Netscape 域严格性标志都关闭)。
- DefaultCookiePolicy.DomainStrict¶
等同于
DomainStrictNoDots|DomainStrictNonDomain
。
Cookie 对象¶
Cookie
实例的 Python 属性大致对应于各种 Cookie 标准中指定的标准 Cookie 属性。这种对应关系不是一对一的,因为存在复杂的默认值分配规则,max-age
和 expires
Cookie 属性包含等效信息,以及 RFC 2109 Cookie 可能被 http.cookiejar
从版本 1 “降级”为版本 0(Netscape)Cookie。
除了在 CookiePolicy
方法中的极少数情况下,不应需要对这些属性进行赋值。该类不强制内部一致性,所以如果你这样做,你应该知道你在做什么。
- Cookie.version¶
整数或
None
。Netscape cookie 的version
为 0。RFC 2965 和 RFC 2109 cookie 的version
cookie-attribute 为 1。但是请注意,http.cookiejar
可能会将 RFC 2109 cookie“降级”为 Netscape cookie,在这种情况下version
为 0。
- Cookie.name¶
Cookie 名称(字符串)。
- Cookie.domain¶
Cookie 域(字符串)。
- Cookie.path¶
Cookie 路径(字符串,例如
'/acme/rocket_launchers'
)。
- Cookie.secure¶
如果 cookie 只应通过安全连接返回,则为
True
。
- Cookie.expires¶
整数形式的过期日期,以 epoch 以来的秒数表示,或者为
None
。另请参阅is_expired()
方法。
- Cookie.discard¶
如果这是一个会话 cookie,则为
True
。
- Cookie.rfc2109¶
如果此 cookie 是作为 RFC 2109 cookie 接收的(即 cookie 是在 Set-Cookie 标头中到达的,并且该标头中 Version cookie-attribute 的值为 1),则为
True
。提供此属性是因为http.cookiejar
可能会将 RFC 2109 cookie“降级”为 Netscape cookie,在这种情况下version
为 0。
- Cookie.port_specified¶
如果服务器明确指定了一个或一组端口(在 Set-Cookie / Set-Cookie2 标头中),则为
True
。
- Cookie.domain_specified¶
如果服务器明确指定了域,则为
True
。
- Cookie.domain_initial_dot¶
如果服务器明确指定的域以点(
'.'
)开头,则为True
。
Cookie 可能具有其他非标准的 cookie-attribute。可以使用以下方法访问它们
- Cookie.has_nonstandard_attr(name)¶
如果 cookie 具有指定的 cookie-attribute,则返回
True
。
- Cookie.get_nonstandard_attr(name, default=None)¶
如果 cookie 具有指定的 cookie-attribute,则返回其值。否则,返回 default。
- Cookie.set_nonstandard_attr(name, value)¶
设置指定的 cookie-attribute 的值。
Cookie
类还定义了以下方法
- Cookie.is_expired(now=None)¶
如果 cookie 已超过服务器请求其应过期的时刻,则为
True
。如果给定了 now(以 epoch 以来的秒数),则返回 cookie 在指定时间是否已过期。
示例¶
第一个示例展示了 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/")