http.cookiejar —— HTTP 客戶端的 Cookie 處理?

源代碼: Lib/http/cookiejar.py


http.cookiejar 模塊定義了用于自動處理 HTTP cookie 的類。這對訪問需要小段數據 —— cookies 的網站很有用,這些數據由 Web 服務器的 HTTP 響應在客戶端計算機上設置,然后在以后的 HTTP 請求中返回給服務器。

常規的 Netscape Cookie 協議和 RFC 2965 定義的協議都可以處理。RFC 2965 處理默認情況下處于關閉狀態。 RFC 2109 cookie 被解析為 Netscape cookie,隨后根據有效的 'policy' 被視為 Netscape 或 RFC 2965 cookie。 請注意,Internet 上的大多數 cookie 是 Netscape cookie。 http.cookiejar 嘗試遵循事實上的 Netscape cookie 協議(與原始 Netscape 規范中所設定的協議大不相同),包括注意 max-ageport RFC 2965 引入的 cookie 屬性。

注解

Set-CookieSet-Cookie2 頭中找到的各種命名參數通常指 attributes。為了不與 Python 屬性相混淆,模塊文檔使用 cookie-attribute 代替。

此模塊定義了以下異常:

exception http.cookiejar.LoadError?

FileCookieJar 實例在從文件加載 cookies 出錯時拋出這個異常。 LoadErrorOSError 的一個子類。

在 3.3 版更改: LoadError 成為 OSError 的子類而不是 IOError

提供了以下類:

class http.cookiejar.CookieJar(policy=None)?

policy 是實現了 CookiePolicy 接口的一個對象。

CookieJar 類儲存 HTTP cookies。它從 HTTP 請求提取 cookies,并在 HTTP 響應中返回它們。 CookieJar 實例在必要時自動處理包含 cookie 的到期情況。子類還負責儲存和從文件或數據庫中查找 cookies。

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

policy 是實現了 CookiePolicy 接口的一個對象。對于其他參數,參考相應屬性的文檔。

一個可以從磁盤文件中加載或保存 cookie 的 CookieJar。 cookie 不會 從指定的文件中加載,直到調用 load()revert() 方法。 該類的子類文檔請參閱 FileCookieJar 的子類及其與 Web 瀏覽器的協同。

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)?

構造器的參數應當只作為關鍵字參數傳入。 blocked_domains 是一個域名序列,程序將絕不接受其 cookie 也絕不向其返回 cookie。 allowed_domains 如果不為 None,則也應是一個域名序列,程序將只對其中的域名接受和返回 cookie。 對于所有其他參數,請參閱 CookiePolicyDefaultCookiePolicy 對象的文檔。

DefaultCookiePolicy 實現了 Netscape 和 RFC 2965 cookies 的標準接受 / 拒絕規則。 默認情況下,RFC 2109 cookies(即在 Set-Cookie 頭中收到的 cookie-attribute 版本為 1 的 cookies )將按照 RFC 2965 規則處理。 然而,如果 RFC 2965 的處理被關閉,或者 rfc2109_as_netscapeTrue,Cookie 實例的 version 屬性設置將被為 0, RFC 2109 cookies CookieJar 實例將 "降級" 為 Netscape cookies。 DefaultCookiePolicy 也提供一些參數以允許一些策略微調。

class http.cookiejar.Cookie?

這個類代表 Netscape、RFC 2109RFC 2965 的 cookie 。 我們不希望 http.cookiejar 的用戶構建他們自己的 Cookie 實例。 相反,如果有必要,請在一個 CookieJar 實例上調用 make_cookies() 。

參見

模塊 urllib.request

URL 打開帶有自動的 cookie 處理。

模塊 http.cookies

HTTP cookie類,主要是對服務端代碼有用。 http.cookiejarhttp.cookies 模塊不相互依賴。

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

原始 Netscape cookie 協議的規范。 雖然這仍然是主流協議,但所有主要瀏覽器(以及 http.cookiejar )實現的 "Netscape cookie協議" 與``cookie_spec.html``中描述的協議僅有幾分相似之處。

RFC 2109 - HTTP狀態管理機制

RFC 2965 所取代。使用 Set-Cookie version=1 。

RFC 2965 - HTTP狀態管理機制

修正了錯誤的 Netscape 協議。 使用 Set-Cookie2 來代替 Set-Cookie 。 沒有廣泛被使用。

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

未完成的:rfc:2965 勘誤表。

HTTP狀態管理使用方法

CookieJar 和 FileCookieJar 對象?

CookieJar 對象支持 iterator 協議,用于迭代包含的 Cookie 對象。

CookieJar 有以下方法:

request 中添加正確的 Cookie 頭。

如果策略允許(即 rfc2965hide_cookie2 屬性在 CookieJarCookiePolicy 實例中分別為 True 和 False ), Cookie2 標頭也會在適當時候添加。

urllib.request 所記載的, request 對象(通常是一個 urllib.request.Request 實例)必須支持 get_full_url() , get_host(), get_type(), unverifiable(), has_header(), get_header(), header_items(), add_unredirected_header()origin_req_host 屬性。

在 3.3 版更改: request 對象需要 origin_req_host 屬性。對已廢棄的方法 get_origin_req_host() 的依賴已被移除。

CookieJar.extract_cookies(response, request)?

從HTTP response 中提取 cookie,并在政策允許的情況下,將它們存儲在 CookieJar 中。

CookieJar 將 在*response* 參數中尋找允許的 Set-CookieSet-Cookie2 頭信息,并適當地存儲cookies(須經 CookiePolicy.set_ok() 方法批準)。

response 對象(通常是調用 urllib.request.urlopen() 或類似方法的結果)應該支持 info() 方法,它返回 email.message.Message 實例。

urllib.request 的文檔所說,request 對象(通常是一個 urllib.request.Request 實例)必須支持 get_full_url(), get_host(), unverifiable()origin_req_host 屬性。 該請求用于設置 cookie-attributes 的默認值,以及檢查 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 的cookies將被刪除。如果給定兩個參數,那么屬于指定的 domain 和 URL path 的cookie將被刪除。 如果給定三個參數,那么屬于指定的 domain 、pathname 的cookie將被刪除

如果不存在匹配的 cookie,則會引發 KeyError

CookieJar.clear_session_cookies()?

丟棄所有session cookie。

丟棄所有 discard 屬性為真值的已包含 cookie(通常是因為它們沒有 max-ageexpires cookie 屬性,或者顯式的 discard cookie 屬性)。 對于交互式瀏覽器,會話的結束通常對應于關閉瀏覽器窗口。

請注意 save() 方法并不會保存會話的 cookie,除非你通過傳入一個真值給 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, delayload=None, policy=None)?

一個能夠以 Mozilla cookies.txt 文件格式(該格式也被 Lynx 和 Netscape 瀏覽器所使用)從磁盤加載和存儲 cookie 的 FileCookieJar。

注解

這會丟失有關 RFC 2965 cookie 的信息,以及有關較新或非標準的 cookie 屬性例如 port。

警告

在存儲之前備份你的 cookie,如果你的 cookie 丟失/損壞會造成麻煩的話(有一些微妙的因素可能導致文件在加載/保存的往返過程中發生細微的變化)。

還要注意在 Mozilla 運行期間保存的 cookie 將可能被 Mozilla 清除。

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

一個能夠以 libwww-perl 庫的 Set-Cookie3 文件格式從磁盤加載和存儲 cookie 的 FileCookieJar。 這適用于當你想以人類可讀的文件來保存 cookie 的情況。

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() 返回真值并將所有工作留給 return_ok()。

如果 domain_return_ok() 為 cookie 域返回真值,則會為 cookie 路徑調用 path_return_ok()。 在其他情況下,則不會為該 cookie 域調用 path_return_ok()return_ok()。 如果 path_return_ok() 返回真值,則會調用 return_ok() 并附帶 Cookie 對象本身以進行全面檢查。 在其他情況下,都永遠不會為該 cookie 路徑調用 return_ok()

請注意 domain_return_ok() 會針對每個 cookie 域被調用,而非只針對 request 域。 例如,該函數會針對 ".example.com""www.example.com" 被調用,如果 request 域為 "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)。

A domain blacklist and whitelist is provided (both off by default). Only domains not in the blacklist and present in the whitelist (if the whitelist is active) participate in cookie setting and returning. Use the blocked_domains constructor argument, and blocked_domains() and set_blocked_domains() methods (and the corresponding argument and methods for allowed_domains). If you set a whitelist, you can turn it off again by setting it to None.

Domains in block or allow lists that do not start with a dot must equal the cookie domain to be matched. For example, "example.com" matches a blacklist entry of "example.com", but "www.example.com" does not. Domains that do start with a dot are matched by more specific domains too. For example, both "www.example.com" and "www.coyote.example.com" match ".example.com" (but "example.com" itself does not). IP addresses are an exception, and must match exactly. For example, if blocked_domains contains "192.168.1.2" and ".168.1.2", 192.168.1.2 is blocked, but 193.168.1.2 is not.

DefaultCookiePolicy 實現了下列附加方法:

DefaultCookiePolicy.blocked_domains()?

返回被阻止域的序列(元組類型)。

DefaultCookiePolicy.set_blocked_domains(blocked_domains)?

設置被阻止域的序列。

DefaultCookiePolicy.is_blocked(domain)?

Return whether domain is on the blacklist for setting or receiving cookies.

DefaultCookiePolicy.allowed_domains()?

返回 None,或者被允許域的序列(元組類型)。

DefaultCookiePolicy.set_allowed_domains(allowed_domains)?

設置被允許域的序列,或者為 None

DefaultCookiePolicy.is_not_allowed(domain)?

Return whether domain is not on the whitelist for setting or receiving cookies.

DefaultCookiePolicy 實例具有下列屬性,它們都是基于同名的構造器參數來初始化的,并且都可以被賦值。

DefaultCookiePolicy.rfc2109_as_netscape?

如為真值,則請求 CookieJar 實例將 RFC 2109 cookie (即在帶有 version 值為 1 的 cookie 屬性的 Set-Cookie 標頭中接收到的 cookie) 降級為 Netscape cookie: 即將 Cookie 實例的 version 屬性設為 0。 默認值為 None,在此情況下 RFC 2109 cookie 僅在s are downgraded if and only if RFC 2965 處理被關閉時才會被降級。 因此,RFC 2109 cookie 默認會被降級。

通用嚴格性開關:

DefaultCookiePolicy.strict_domain?

不允許網站設置帶國家碼頂級域的包含兩部分的域名例如 .co.uk, .gov.uk, .co.nz 等。 此開關尚未十分完善,并不保證有效!

RFC 2965 協議嚴格性開關:

DefaultCookiePolicy.strict_rfc2965_unverifiable?

遵循針對不可驗證事務的 RFC 2965 規則(不可驗證事務通常是由重定向或請求發布在其它網站的圖片導致的)。 如果該屬性為假值,則 永遠不會 基于可驗證性而阻止 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: 即名稱前綴為 '{TX-PL-LABEL}#x27; 的標頭。

DefaultCookiePolicy.strict_ns_set_path?

不允許設置路徑與請求 URL 路徑不匹配的 cookie。

strict_ns_domain 是一組旗標。 其值是通過或運算來構造的(例如,DomainStrictNoDots|DomainStrictNonDomain 表示同時設置兩個旗標)。

DefaultCookiePolicy.DomainStrictNoDots?

當設置 cookie 是,'host prefix' 不可包含點號(例如 www.foo.bar.com 不能為 .bar.com 設置 cookie,因為 www.foo 包含了一個點號)。

DefaultCookiePolicy.DomainStrictNonDomain?

沒有顯式指明Cookies that did not explicitly specify a domain cookie 屬性的 cookie 只能被返回給與設置 cookie 的域相同的域(例如 spam.example.com 不會是來自 example.com 的返回 cookie,如果該域名沒有 domain cookie 屬性的話)。

DefaultCookiePolicy.DomainRFC2965Match?

當設置 cookie 時,要求完整的 RFC 2965 域匹配。

下列屬性是為方便使用而提供的,是上述旗標的幾種最常用組合:

DefaultCookiePolicy.DomainLiberal?

等價于 0 (即所有上述 Netscape 域嚴格性旗標均停用)。

DefaultCookiePolicy.DomainStrict?

等價于 DomainStrictNoDots|DomainStrictNonDomain

Cookie 對象?

Cookie 實例具有與各種 cookie 標準中定義的標準 cookie 屬性大致對應的 Python 屬性。 這并非一一對應,因為存在復雜的賦默認值的規則,因為 max-ageexpires cookie 屬性包含相同信息,也因為 RFC 2109 cookie 可以被 http.cookiejar 從第 1 版 '降級為' 第 0 版 (Netscape) cookie。

對這些屬性的賦值在 CookiePolicy 方法的極少數情況以外應該都是不必要的。 該類不會強制內部一致性,因此如果這樣做則你應當清楚自己在做什么。

Cookie.version?

整數或 None。 Netscape cookie 的 version 值為 0。 RFC 2965RFC 2109 cookie 的 version cookie 屬性值為 1。 但是,請注意 http.cookiejar 可以將 RFC 2109 cookie '降級' 為 Netscape cookie,在此情況下 version 值也為 0。

Cookie.name?

Cookie 名稱(一個字符串)。

Cookie.value?

Cookie 值(一個字符串),或為 None。

Cookie.port?

代表一個端口或一組端口(例如 '80' 或 '80,8080')的字符串,或為 None。

Cookie.path?

Cookie 路徑 (字符串類型,例如 '/acme/rocket_launchers')。

Cookie.secure?

如果 cookie 應當只能通過安全連接返回則為 True

Cookie.expires?

整數類型的過期時間,以距離 Unix 紀元的秒數表示,或者為 None。 另請參閱 is_expired() 方法。

Cookie.discard?

如果是會話 cookie 則為 True。

Cookie.comment?

來自服務器的解釋此 cookie 功能的字符串形式的注釋,或者為 None

Cookie.comment_url?

鏈接到來自服務器的解釋此 cookie 功能的注釋的 URL,或者為 None。

Cookie.rfc2109?

如果 cookie 是作為 RFC 2109 cookie 被接收(即該 cookie 是在 Set-Cookie 標頭中送達,且該標頭的 Version cookie 屬性的值為 1)則為 True。 之所以要提供該屬性是因為 http.cookiejar 可能會從 RFC 2109 cookies '降級' 為 Netscape cookie,在此情況下 version 值為 0。

Cookie.port_specified?

如果服務器顯式地指定了一個端口或一組端口(在 Set-Cookie / Set-Cookie2 標頭中)則為 True。

Cookie.domain_specified?

如果服務器顯式地指定了一個域則為 True。

Cookie.domain_initial_dot?

該屬性為 True 表示服務器顯式地指定了以一個點號 ('.') 打頭的域。

Cookie 可能還有額外的非標準 cookie 屬性。 這些屬性可以通過下列方法來訪問:

Cookie.has_nonstandard_attr(name)?

如果 cookie 具有相應名稱的 cookie 屬性則返回 True。

Cookie.get_nonstandard_attr(name, default=None)?

如果 cookie 具有相應名稱的 cookie 屬性,則返回其值。 否則,返回 default。

Cookie.set_nonstandard_attr(name, value)?

設置指定名稱的 cookie 屬性的值。

Cookie 類還定義了下列方法:

Cookie.is_expired(now=None)?

如果 cookie 傳入了服務器請求其所應過期的時間則為 True。 如果給出 now 值(距離 Unix 紀元的秒數),則返回在指定的時間 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/")