首先說明一下,我使用的是 Python3 的 urllib,但 Python2.x 同理(使用 urllib2)。
想用腳本去登錄一個網站。和很多網站一樣,該網站使用 cookie 來保存會話信息。這個我以前是自己提取 response 中的 Set-Cookie
頭來處理的。這次本想如法炮制,卻發現沒保存需要的 cookie,所以登錄失敗。
很郁悶地想了半天,最后出去 wireshark 抓包,終於發現原來重要的 cookie 在登錄后的應答中,但這個應答是個 302 重定向,所以 urllib 默認的 opener (urllib.request.urlopen)直接就跟從這個重定向了,沒有對 cookie 進行任何處理。
我首先想到的是,不要跟從重定向。我看到有個 HTTPRedirectHandler
,但文檔里沒寫它怎么用。郁悶……自己找到 request.py 文件看源代碼,折騰了好久無果,遂想到 Google (早該想到了。。。)於是找到了 StackOverflow 上。有兩個解決辦法:要么不跟從重定向,要么弄個 HTTPCookieProcessor
保存 cookie 信息。看我自己的需求,當然選后者了。而且,那個回答問題的人也沒有給出如何不讓它跟從重定向(所給代碼只是在重定向前對 cookie 進行處理而已)。
於是,我再一次地打開了 http.cookiejar 的文檔,嘗試弄明白這東西到底怎么用。當初折騰 cookie 的時候,沒弄明白這個,所以才自己處理的。
看 request.py 里的代碼,這個 CookieJar 用起來相當不錯:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class
HTTPCookieProcessor(BaseHandler):
def
__init__(
self
, cookiejar
=
None
):
import
http.cookiejar
if
cookiejar
is
None
:
cookiejar
=
http.cookiejar.CookieJar()
self
.cookiejar
=
cookiejar
def
http_request(
self
, request):
self
.cookiejar.add_cookie_header(request)
return
request
def
http_response(
self
, request, response):
self
.cookiejar.extract_cookies(response, request)
return
response
https_request
=
http_request
https_response
=
http_response
|
不過我需要將 cookie 信息保存到文件。從文檔上看到有個 FileCookieJar
。我嘗試了下,出錯了,沒有 _really_load
方法,我暈。。。之后才注意到其源代碼開頭有個ASCII圖:
1
2
3
4
5
6
7
8
9
10
11
|
CookieJar____
/ \ \
FileCookieJar \ \
/ | \ \ \
MozillaCookieJar | LWPCookieJar \ \
| | \
| ---MSIEBase | \
| / | | \
| / MSIEDBCookieJar BSDDBCookieJar
|/
MSIECookieJar
|
原來具體實現還在子類啊。好吧,我就用 MozillaCookieJar
好了。
用法很簡單,初始化時把文件名傳給它,載入用 load()
,保存用 save()
。不過要注意的是,文件不存在時不能載入,touch 個空文件出來也不行的。
另外,那個 StackOverflow 的頁面還提到了 mechanize 這個模塊,有時間去嘗試下 :-)
最后,如果我不要它重定向該怎么做呢?難道非要我去用更底層的 http.client?