禁止自動重定向
python3的urllib.request模塊發http請求的時候,如果服務器響應30x會自動跟隨重定向,返回的結果是重定向后的最終結果而不是30x的響應結果。
request是靠HTTPRedirectHandler這個中的方法攔截重定並發起重新發起請求的,網上有方法說繼承這個類並把類下面的方法都改成pass,這樣可以阻止重定向,但是無法阻止30x響應被HTTPErrorProcessor類捕獲,會最終拋出異常。可以通過處理這個exception來解決,但是稍麻煩。
有沒有辦法讓302響應像200一樣不拋異常而返回response類對象呢?我看了一下urllib.request模塊的代碼,是可以很簡單地實現的。看代碼:
from urllib import request class NoRedirHandler(request.HTTPRedirectHandler): def http_error_302(self, req, fp, code, msg, headers): return fp http_error_301 = http_error_302 # other_handler = ... opener = request.build_opener( NoRedirHandler, other_handlers) rsp = opener.open('http://example.com') # rsp.code #>> 302 # rsp.read() #>> b''
主意上面的“other_handler”是個示例,你可能會把他替換成HTTPCookieProcessor或其他handler類實例或直接刪除它。
實際上就是http_error_302函數的fp這個傳參比較令人疑惑,我發現request這個庫里其他地方傳參給這個函數時這個pf其實就是response,只有在這里變成了pf,不知道作者是故意不想讓人改呢還是什么原因。
重定向攜帶cookie(會話)
request庫會自動跟隨重定向,返回新頁面的信息,但是如果重定向后的頁面需要會話信息(cookie),就可能導致重定向循環,直到重定向次數過多,拋出錯誤。
解決這個問題用上HTTPCookieProcessor,這樣請求會自動保存獲得的cookie並在后面使用,不需要自己去set header,全自動的。例:
from urllib import request cookie_hdr = request.HTTPCookieProcessor() opener = request.build_opener(cookie_hdr) req = request.Request('http://example.com') with opener.open(req) as f: # bla...bla...bla page_data = f.read()
CookieProcess也能支持把cookie放一個文件里,可以再程序重啟后保持之前的會話。