http.cookiejar --- HTTP 用戶端的 Cookie 處理

原始碼:Lib/http/cookiejar.py


http.cookiejar 模組定義了自動處理 HTTP cookie 的類別。當需要存取小量資料 ——cookies —— 的網站時會非常有用。這些資料會依據網頁伺服器的 HTTP 回應來設置於用戶端機器,並在之後的請求中被回傳到伺服器。

一般的 Netscape cookie 協定和RFC 2965 定義的 cookie 協定都會被處理。RFC 2965 的處理預設是關閉的。RFC 2109 cookie 會被剖析為 Netscape cookie,然後根據有生效的「策略」來被看作為 Netscape 或 RFC 2965 cookie。http.cookiejar 會嘗試遵循實際上的 Netscape cookie 協定(與原始的 Netscape 規格中的協定有很大的不同),包括 RFC 2965 所引進的max-ageport cookie 屬性。

備註

Set-CookieSet-Cookie2 標頭中出現的各種命名參數(例如domainexpires)通常被稱為attributes。為了與 Python 的屬性分別開,這個模組的說明檔案改用cookie-attribute 來稱呼。

模組定義了以下例外:

exceptionhttp.cookiejar.LoadError

當從檔案載入 cookies 失敗時,FileCookieJar 的實例會引發這個例外。LoadErrorOSError 的子類別。

在 3.3 版的變更:LoadError 以前是IOError 的子型別,現在是OSError 的別名。

這個模組提供了以下類別:

classhttp.cookiejar.CookieJar(policy=None)

policy 是實作了CookiePolicy 介面的一個物件。

CookieJar 類別會儲存 HTTP cookies。它會從 HTTP 請求中抽取出 cookies,並在 HTTP 回應中將它們回傳。CookieJar 實例會在必要時自動使包含的 cookies 過期。它的子類別也負責從檔案或資料庫中儲存和擷取 cookies。

classhttp.cookiejar.FileCookieJar(filename=None,delayload=None,policy=None)

policy 是實作了CookiePolicy 介面的一個物件。至於其他引數,請參閱對應屬性的說明文件。

一個可以從磁碟上的檔案載入 Cookie,也可以儲存 Cookie 到磁碟上檔案的CookieJar。在load()revert() 方法被呼叫之前,Cookie 並不會從指定的檔案載入。這個類別的子類別有記載於FileCookieJar 子類別及與網頁瀏覽器的合作 章節。

這個類別不應該直接初始化 - 請使用下面的子類別代替。

在 3.8 版的變更:filename 參數支援傳入一個path-like object

classhttp.cookiejar.CookiePolicy

此類別負責決定是否應從伺服器接受 / 回傳每個 cookie。

classhttp.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 是我們從不接受 cookies 或回傳 cookies 的網域名稱序列。allowed_domains 如果不是None,這是我們接受並回傳 cookies 的唯一網域名稱序列。secure_protocols 是可以加入安全 cookies 的通訊協定序列。預設情況下,httpswss(安全 websocket)會被視為安全通訊協定。所有其他引數請參閱CookiePolicyDefaultCookiePolicy 物件的說明文件。

DefaultCookiePolicy 實作了 Netscape 和RFC 2965 cookies 的標準接受/拒絕規則。預設情況下,RFC 2109 cookies(即在Set-Cookie 標頭中接收到的版本 cookie-attribute 為 1 的 cookies)會根據 RFC 2965 規則處理。 但是,如果 RFC 2965 處理被關閉,或者rfc2109_as_netscapeTrue,RFC 2109 cookie 會被CookieJar 實例「降級 」為 Netscape cookie,方法是將Cookie 實例的version 屬性設為 0。DefaultCookiePolicy 也提供了一些參數來允許對策略進行一些微調。

classhttp.cookiejar.Cookie

這個類別代表 Netscape、RFC 2109RFC 2965 cookies。 我們不希望http.cookiejar 的使用者建立自己的Cookie 實例。 如有必要,請在CookieJar 實例上呼叫make_cookies()

也參考

urllib.request 模組

URL 打開時會自動處理 cookie。

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 所取代,會使用Set-Cookie 設定 version=1。

RFC 2965 - HTTP 狀態管理機制

有錯誤修正的 Netscape 通訊協定。使用Set-Cookie2 取代Set-Cookie。未被廣泛使用。

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

未完成的RFC 2965 勘誤表。

RFC 2964 - HTTP 狀態管理使用方法

CookieJar 與 FileCookieJar 物件

CookieJar 物件支援iterator 協定來遍歷包含的Cookie 物件。

CookieJar 擁有以下方法:

CookieJar.add_cookie_header(request)

將正確的Cookie 標頭加入request

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

urllib.request 文件所述,request 物件(通常是urllib.request.Request 的實例)必須支援get_full_url()has_header()get_header()header_items()add_unredirected_header() 方法與hosttypeunverifiableorigin_req_host 屬性。

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

CookieJar.extract_cookies(response,request)

在策略允許的情況下,從 HTTPresponse 抽取出 cookies 並儲存到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() 方法以及hostunverifiableorigin_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() 的說明檔案。

CookieJar.set_cookie_if_ok(cookie,request)

如果策略允許這麼做,設定Cookie

CookieJar.set_cookie(cookie)

設定一個Cookie,不經過策略檢查。

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

清除一些 cookies。

如果不帶引數地叫用,則清除所有 cookies。如果給定單一引數,則只移除屬於該domain 的 cookies。如果給定兩個引數,則會移除屬於指定domain 和 URLpath 的 cookie。 如果給定三個引數,則會移除指定domainpathname 的 cookie。

如果沒有符合的 cookie 存在,則引發KeyError

CookieJar.clear_session_cookies()

刪除所有 session cookies。

刪除所有包含有 truediscard 屬性的 cookie (通常是因為它們沒有max-ageexpires cookie 屬性,或有明確的discard cookie 屬性)。 對於互動式瀏覽器,工作階段的結束通常對應於關閉瀏覽器視窗。

請注意save() 方法無論如何都不會儲存 session cookies,除非你透過傳入 trueignore_discard 引數來要求。

FileCookieJar 實例有下列附加方法:

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

將 cookies 儲存到檔案中。

這個基底類別會產生NotImplementedError。子類別可以不實作此方法。

filename 是儲存 cookies 的檔案名稱。 如果filename 未指定,則會使用self.filename (其預設值是傳給建構函式的值(如果有));如果self.filenameNone,則會產生ValueError

ignore_discard: 即使設定為捨棄的 cookies 也會儲存。ignore_expires: 保存過期的 cookie

如果檔案已經存在,則會被覆寫,因此會抹除其中包含的所有 cookies。 儲存的 cookies 可以稍後使用load()revert() 方法還原。

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

從檔案中載入 cookies。

舊的 cookies 會被保留,除非被新載入的 cookies 覆蓋。

引數與save() 相同。

被命名的檔案必須是類別所能正確剖析的格式,否則會產生LoadError。此外,OSError 可能會被引發,例如檔案不存在時。

在 3.3 版的變更:以前會引發IOError,現在它是OSError 的別名。

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

清除所有 cookies, 並從儲存的檔案重新載入 cookies。

revert() 可以產生與load() 相同的例外。如果失敗,物件的狀態不會被改變。

FileCookieJar 實例擁有以下公開屬性:

FileCookieJar.filename

保存 cookie 的預設檔案的檔案名稱。 此屬性可以被指定。

FileCookieJar.delayload

若為 true,則從硬盤惰性地載入 cookies。 此屬性不應被指定。 這只是一個提示,因為這只會影響效能,不會影響行為 (除非磁碟上的 cookies 正在改變)。一個CookieJar 物件可以忽略它。 沒有一個包含在標準函式庫中的FileCookieJar 類別會惰性地載入 cookies。

FileCookieJar 子類別及與網頁瀏覽器的合作

以下CookieJar 子類別提供用於讀取和寫入。

classhttp.cookiejar.MozillaCookieJar(filename=None,delayload=None,policy=None)

一個能夠以 Mozillacookies.txt 檔案格式(該格式也被 curl 和 Lynx 以及 Netscape 瀏覽器所使用)從磁碟載入和儲存 cookie 的FileCookieJar

備註

這會遺失關於RFC 2965 cookie 的訊息,以及較新或非標準 cookie 屬性(例如port)的訊息。

警告

如果 Cookie 遺失或損壞會造成不便,請在儲存之前先備份 Cookie(有些微妙的情況可能會導致檔案在載入/儲存往返過程中發生輕微變化)。

另外請注意,在 Mozilla 執行時儲存的 cookies 會被 Mozilla 刪除。

classhttp.cookiejar.LWPCookieJar(filename=None,delayload=None,policy=None)

一個FileCookieJar 可以從 libwww-perl 函式庫的Set-Cookie3 檔案格式載入 cookies 並儲存 cookies 到磁碟。如果你想要將 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,path_return_ok() 就會被用來呼叫 cookie 路徑。否則path_return_ok()return_ok() 永遠不會被呼叫。如果path_return_ok() 回傳 true,則會呼叫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)。

DefaultCookiePolicy 為子類別定義CookiePolicy 類別,並覆寫其中的一些或全部方法是最有用的。CookiePolicy 本身可以用做 '無策略',允許設定和接收任何和所有的 cookies (這不太可能有用)。

DefaultCookiePolicy 物件

執行接受和回傳 cookie 的標準規則。

同時支援RFC 2965 和 Netscape cookies。 RFC 2965 的處理預設為關閉。

提供你自己的策略的最簡單方法是覆寫此類別,並在你覆寫的實作中呼叫其方法,然後再加入你自己的額外檢查:

importhttp.cookiejarclassMyCookiePolicy(http.cookiejar.DefaultCookiePolicy):defset_ok(self,cookie,request):ifnothttp.cookiejar.DefaultCookiePolicy.set_ok(self,cookie,request):returnFalseifi_dont_want_to_store_this_cookie(cookie):returnFalsereturnTrue

除了實作CookiePolicy 介面所需的功能外,這個類別還允許你阻止或允許網域名稱設定和接收 cookies。 還有調整嚴格度的控制選項,可讓你稍微收緊相對寬鬆的 Netscape 通訊協定(代價是阻擋一些良性 cookies)。

提供網域阻止清單和允許清單(預設都關閉)。只有不在阻止清單中和在允許清單中(如果允許清單是有效的)的網域才參與 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 在設定或接收 cookies 的阻止列表上,則回傳True

DefaultCookiePolicy.allowed_domains()

回傳None,或允許網域的序列(以元組形式)。

DefaultCookiePolicy.set_allowed_domains(allowed_domains)

設定允許網域的序列,或None

DefaultCookiePolicy.is_not_allowed(domain)

如果domain 不在設定或接收 cookies 的允許清單上,則回傳True

DefaultCookiePolicy 實例有以下屬性,這些屬性都是由同名的建構函式引數初始化,而且都可以被指定。

DefaultCookiePolicy.rfc2109_as_netscape

如果為 true,請求CookieJar 實例透過設定Cookie 實例的版本屬性為 0,將RFC 2109 cookies (即在Set-Cookie 標頭中收到的、版本 cookie 屬性為 1 的 cookies) 降級為 Netscape cookies。 預設值是None,在這種情況下,如果且僅如果RFC 2965 處理被關閉,RFC 2109 cookies 才會被降級。 因此,RFC 2109 cookie 在預設情況下被降級。

一般的調整嚴格度的控制選項:

DefaultCookiePolicy.strict_domain

不允許網站設定具有國家代碼頂層域名的兩層域名,如.co.uk.gov.uk.co.nz 等。 這遠遠不夠完美,也不能保證一定有效!

RFC 2965 通訊協定調整嚴格度的控制選項:

DefaultCookiePolicy.strict_rfc2965_unverifiable

遵循針對不可驗證事務(transaction)的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: 標頭中名稱以'$' 開頭的 cookies。

DefaultCookiePolicy.strict_ns_set_path

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

strict_ns_domain 是一系列旗標。它的值由將旗標按位元或組成(例如,DomainStrictNoDots|DomainStrictNonDomain 表示兩個旗標都被設定)。

DefaultCookiePolicy.DomainStrictNoDots

設定 cookie 時,「host 前綴」不得包含點(例如,www.foo.bar.com 不能為.bar.com 設定 cookie,因為www.foo 包含一個點)。

DefaultCookiePolicy.DomainStrictNonDomain

未明確指定domain cookie-attribute 的 Cookie 只能回傳給與設定 Cookie 的網域相同的網域(例如,spam.example.com 將不會回傳來自example.com 但沒有domain cookie-attribute 的 Cookie)。

DefaultCookiePolicy.DomainRFC2965Match

設定 cookie 時,需要完整的RFC 2965 網域匹配。

為了方便起見,以下屬性是上述旗標最有用的組合:

DefaultCookiePolicy.DomainLiberal

等於 0(即關閉上述所有 Netscape 網域嚴格度旗標)。

DefaultCookiePolicy.DomainStrict

等價於DomainStrictNoDots|DomainStrictNonDomain

Cookie 物件

Cookie 實例的 Python 屬性大致對應於各種 cookie 標準中指定的標準 cookie 屬性。 這個對應關係不是一一對應的,因為有複雜的規則來指定預設值,因為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」,或「880,8080」),或None

Cookie.domain

Cookie 網域(字串)。

Cookie.path

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

Cookie.secure

如果 cookie 只能透過安全連線回傳,則為True

Cookie.expires

自 epoch 起計算的整數到期時間,以秒為單位,或None。另請參閱is_expired() 方法。

Cookie.discard

如果這是 session cookie,即為True

Cookie.comment

來自伺服器解釋此 cookie 功能的字串註解,或None

Cookie.comment_url

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

Cookie.rfc2109

True 如果這個 cookie 是以RFC 2109 cookie 的形式收到的 (即這個 cookie 是在Set-Cookie 標頭中收到的,而且在那個標頭中的 Version cookie-attribute 的值是 1)。 提供這個屬性的原因是http.cookiejar 可能會將 RFC 2109 cookie 「降級」 為 Netscape cookie,在這種情況下version 的值是 0。

Cookie.port_specified

如果伺服器顯式地指定了一個連接埠或一組連接埠(在Set-Cookie /Set-Cookie2 標頭中)。

Cookie.domain_specified

如果伺服器明確指定網域,則為True

Cookie.domain_initial_dot

如果伺服器明確指定的網域以點 ('.') 開頭,則為True

Cookies 可能具有額外的非標準 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 (以自紀元起的秒數為單位),則會回傳 cookie 是否已在指定時間過期。

範例

第一個範例展示了http.cookiejar: 最常見的用法:

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

本範例說明如何使用你的 Netscape、Mozilla 或 Lynx cookies 打開 URL (假設 Unix/Netscape 會慣用 cookies 檔案的位置):

importos,http.cookiejar,urllib.requestcj=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 cookies,在設定和回傳 Netscape cookies 時對網域更嚴格,並阻止某些網域設定 cookies 或讓其回傳:

importurllib.requestfromhttp.cookiejarimportCookieJar,DefaultCookiePolicypolicy=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/")