urllib2模塊
說明:
- python2.7不需要額外安裝urllib2模塊,因為urllib2是python2.7的自帶模塊
- urllib2官方文檔:https://docs.python.org/2/library/urllib2.html
- urllib2源碼:https://hg.python.org/cpython/file/2.7/Lib/urllib2.py
- urllib2在python3中被修改為urllib.request
1 #! usr/bin/env python 2 #-*-coding:utf-8-*- 3 import urllib2 #引入urllib庫 4 response = urllib2.urlopen("http://www.baidu.com") #使用urllib2的urlopen()方法去獲取百度主頁,返回一個response對象 5 html = response.read() #使用response的read()方法可以將返回的主頁信息轉換成字符串賦值給html變量 6 print html #打印html
1 ============================================================ 2 Urllib2爬蟲 3 ============================================================ 4 5 URLlib2基本操作: 6 1 7 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 8 | import urllib2 9 | response = urllib2.open("http://www.baidu.com") # 使用urllib2.open()方法發送請求,並返回服務器響應的類文件對象 10 | html = response.read() # 類文件對象支持文件對象操作方法,如read()方法讀取返回文件對象的全部內容並將其轉換成字符串格式並賦值給html變量 11 | print html # 打印html變量,即可顯示出整個頁面 12 | 13 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 14 15 2 16 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 17 | import urllib2 18 | request = urllib2.Request("http://www.baidu.com") # 使用將urllib2.Request()實例化,需要訪問的URL地址則作為Request實例的參數 19 | response = urllib2.urlopen(request) # Request對象作為urlopen()方法的參數,發送給服務器並接收響應的類文件對象 20 | html = response.read() # 類文件對象支持文件對象操作方法,如read()方法讀取返回文件對象的全部內容並將其轉換成字符串格式並賦值給html變量 21 | print html # 打印字符串 22 | 23 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 24 25 3 26 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 27 | import urllib2 28 | url = "http://www.baidu.com" 29 | ua_header = {"User-Agent":"Mozzila/5.0(compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"} 30 | request = urllib2.Reuqest(url,headers=ua_header) # url連同headers一起構造Request請求,這個請求將附帶IE9.0瀏覽器的User-Agent 31 | response = urllib2.urlopen(request) # 向服務器發送這個請求並接收響應的類文件對象 32 | html = response.read() # 類文件對象支持文件對象操作方法,如read()方法讀取返回文件對象的全部內容並將其轉換成字符串格式並賦值給html變量 33 | print html # 打印字符串 34 | 35 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 36 37 4 38 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 39 | import urllib2 40 | url = "http://www.itcast.cn" 41 | ua = {"User-Agent":"Mozzila/5.0(compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"} 42 | request = urllib2.Request(url,headers = ua) # IE9.0的User-Agent 43 | request.add_header("Connection":"keep-alive") # 也可以通過Request.add_header()添加/修改一個特定的header 44 | response = urllib2.urlopen(request) 45 | html = response.read() 46 | print html 47 | print response.code 48 | print request.get_header("Connection") # 查看響應狀態碼 49 | print request.get_header(header_name = "Connection") # 也可以通過Request.get_header()查看header信息 50 | 51 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 52 53 54 5.隨機添加/修改User-Agent 55 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 56 | import urllib2 57 | import random 58 | 59 | url = "http://www.baidu.com" 60 | ua_list = [ 61 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv2.0.1) Gecko/20100101 Firefox/4.0.1", 62 | "Mozilla/5.0 (Windows NT 6.1; rv2.0.1) Gecko/20100101 Firefox/4.0.1", 63 | "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; en) Presto/2.8.131 Version/11.11", 64 | "Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11", 65 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11" 66 | ] 67 | user_agent = random.choice(ua_list) 68 | print user_agent 69 | request = urllib2.Request(url) 70 | request.add_header("User-Agent",user_agent) # 也可以通過Request.add_header()添加/修改一個特定的header 71 | response = urllib2.urlopen(request) 72 | html = response.read() 73 | print html 74 | print response.get_header("User-agent") # 注意:第一個字母大寫,后面的全部小寫 75 | 76 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 77 78 79 6.網絡編碼格式轉換 ---- urllib2的post之urllib.urlencode() 80 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 81 | import urllib2 82 | import urllib #引入urllib負責url編碼處理 83 | 84 | url = "http://www.baidu.com" 85 | word = {"wd":"長城"} 86 | word = urllib.urlencode(word) # 轉換成url編碼格式(字符串) 87 | fullurl = url + "?" + word # url首個分隔符就是? 88 | headers = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; rv 2.0.1) Gecko/20100101 Firefox/4.0.1"} 89 | request = urllib2.Reuqest(fullurl,headers=headers) 90 | response = urllib2.urlopen(request) 91 | html = response.read() 92 | print html 93 | 94 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 95 96 97 7.百度貼吧爬取(post請求的應用) 98 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 99 | import urllib 100 | import urllib2 101 | 102 | def load_page(fullurl,filename): 103 | print "正在下載" + filename 104 | headers = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; rv 2.0.1) Gecko/20100101 Firefox/4.0.1"} 105 | request = urllib.Reuqest(fullurl,headers=headers) 106 | response = urllib2.urlopen(request) 107 | return response.read() 108 | 109 | def write_page(html,filename): 110 | print "正在存儲" + str(filename) 111 | with open(filename,"w") as f: 112 | f.write(html) 113 | print "-"*30 114 | 115 | def tieba_spider(url,beginpage,endpage): 116 | for page in range(beginpage,endpage+1): 117 | filename = "第" + str(page) + "頁" 118 | pn = (page-1)*50 119 | fullurl = url + "&pn" + str(pn) 120 | html = load_page(fullurl,filename) 121 | write_page(html,filename) 122 | 123 | if __name__ == "__main__": 124 | kw = raw_input("請輸入需要爬取的貼吧名:") 125 | beginpage = raw_input("請輸入爬取的起始頁:") 126 | endpage = raw_input("請輸入爬取的終止頁:") 127 | url = "http://tieba.baidu.com/f?" 128 | kw = urllib.urlencode(kw) 129 | url = url + kw 130 | 131 | tieba_spider(url,beginpage,endpage) 132 | 133 | 134 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 135 136 137 8.有道翻譯(post請求的應用) 138 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 139 | import urllib 140 | import urllib2 141 | 142 | key = raw_input("請輸入需要翻譯的內容:") 143 | url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule&sessionFrom=null" 144 | headers = { 145 | "Accept" : "application/json, text/javascript, */*; q=0.01", 146 | "X-Requested-With" : "XMLHttpRequest", 147 | "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", 148 | "Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8", 149 | } 150 | formdata = { 151 | "i" : key, 152 | "from" : "AUTO", 153 | "to" : "AUTO", 154 | "smartresult":"dict", 155 | "client" : "fanyideskweb", 156 | "doctype" : "json", 157 | "version":"2.1", 158 | "keyfrom" : "fanyi.web", 159 | "action" : "FY_BY_ENTER", 160 | "typoResult" : "true" 161 | } 162 | 163 | data = urllib.urlencode(formdata) 164 | request = urllib2.Request(url,data=data,headers=headers) 165 | response = urllib2.urlopen(request) 166 | print response.read() 167 | 168 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 169 170 171 9 獲取Ajax加載內容(post請求的應用) 豆瓣電影top100前20 172 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 173 | import urllib 174 | import urllib2 175 | 176 | url = "https://movie.douban.com/j/chart/top_list?type=11&interval_id=100%3A90&action" 177 | headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} 178 | formdata = { # 變動的是這兩個參數,從start開始往后顯示limit個數據 179 | "start":"0", # 這兩個參數會在發送post請求的時候自定添加到url中 180 | "limit":"20" 181 | } 182 | data = urllib.urlencode(formdata) 183 | request = urllib2.Request(url,data=data,headers=headers) 184 | response = urllib2.urlopen(request) 185 | print response.read() 186 | 187 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 188 189 190 10.忽略HTTPS請求SSL證書驗證(post請求的應用) 12306忽略https證書驗證 191 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 192 | import urllib2 193 | import ssl # 導入Python SSL處理模塊 194 | 195 | context = ssl._create_unverified_context() # 表示忽略未經核實的SSL證書認證 196 | url = "https://www.12306.cn/mormhweb" 197 | headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"} 198 | request = urllib2.Request(url,headers=headers) 199 | response = urllib2.urlopen(request,context = context) # 注意這里使用的是context參數,是沒有放在Request中的,而是在urlopen中指明context參數 200 | print response.read() 201 | 202 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 203 204 205 URLllib2自定義opener 206 207 208 准備知識:Handler處理器和自定義Opener 209 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 210 | opener是 urllib2.OpenerDirector 的實例,我們之前一直都在使用的urlopen,它是一個特殊的opener(也就是模塊幫我們構建好的)。 211 | 212 | 但是基本的urlopen()方法不支持代理、cookie等其他的HTTP/HTTPS高級功能。所以要支持這些功能: 213 | 214 | 步驟1: 創建處理器對象----使用相關的 Handler處理器 來創建特定功能的處理器對象; 215 | 216 | 步驟2: 創建opener對象----通過 urllib2.build_opener()方法使用這些處理器對象,創建自定義opener對象; 217 | 218 | 步驟3: 使用opener對象----調用自定義的opener對象的open()方法發送請求。 219 | 220 | 根據需要,可以使用urllib2.install_opener()將自定義的opener定義為全局opener,表示如果之后凡是調用urlopen,都將使用這個opener 221 | 222 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 223 224 225 1.利用HTTPHandler處理器創建支持處理HTTP請求的opener 226 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 227 | imort urllib2 228 | http_handler = urllib2.HTTPHandler() # 第一步:創建處理器對象(這里:創建一個(支持處理HTTP請求)的HTTPHandler處理器對象) 229 | http_opener = urllib2.build_opener(http_handler) # 第二步:創建opener對象(這里:調用urllib2.build_opener()方法來創建(支持HTTP請求)的opener對象) 230 | http_response = http_opener.open("http://www.baidu.com") # 第三步:使用opener對象(這里:調用opener對象的open()方法發送request請求) 231 | print http_response.read() # 打印服務器響應內容 232 | 233 | 這種方式發送請求得到的結果,和使用urllib2.urlopen()發送HTTP請求得到的結果是一樣的。 234 | 如果在 HTTPHandler()增加 debuglevel=1參數,即(HTTPHandler(debuglevel=1)),還會將DebugLog 打開, 235 | 這樣程序在執行的時候,會把收包和發包的報頭在屏幕上自動打印出來,方便調試,有時可以省去抓包的工作。 236 | 237 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 238 239 240 241 2.利用HTTPShandler處理器創建支持處理HTTPS請求的opener 242 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 243 | import urllib2 244 | https_handler = urllib2.HTTPSHandler() # 第一步:創建處理器對象(這里:創建一個(支持處理HTTP請求)的HTTPHandler處理器對象) 245 | https_opener = urllib2.build_opener(https_handler) # 第二步:創建opener對象(這里:build_opener()方法來創建(支持HTTP請求)的opener對象) 246 | https_response = https_opener.open("https://www.12306.cn/mormhweb/") # 第三步:使用opener對象(這里:調用opener對象的open()方法發送request請求) 247 | print https_response.read() # 打印服務器響應內容 248 | 249 | 這種方式發送請求得到的結果,和使用urllib2.urlopen()發送HTTPS請求得到的結果是一樣的。 250 | 如果在 HTTPSHandler()增加 debuglevel=1參數,即(HTTPSHandler(debuglevel=1)),還會將DebugLog 打開, 251 | 這樣程序在執行的時候,會把收包和發包的報頭在屏幕上自動打印出來,方便調試,有時可以省去抓包的工作。 252 | 253 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 254 255 256 3.利用ProxyHandler處理器創建支持非私密代理訪問的opener 257 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 258 | 259 | import urllib2 260 | 261 | have_proxy_handler = urllib2.ProxyHandler({"http":"122.72.18.35:80"}) # 第一步:創建處理器對象(這里:創建一個(支持有代理)和一個(支持無代理)的ProxyHandler處理器對象) 262 | null_proxy_handler = urllib2.ProxyHandler({}) 263 | proxy_switch = True # 創建了一個是否使用代理的開關, 264 | if proxy_switch: # 第二步:創建opener對象(這里:調用build_opener()方法來創建opener對象) 265 | opener = urllib2.build_opener(have_proxy_handler) # 如果代理開關打開,則創建一個支持有代理的opener對象 266 | else: 267 | opener = urllib2.build_opener(null_proxy_handler) # 如果代理開關關閉,則創建一個支持無代理的opener對象 268 | request = urllib2.Request("http://www.baidu.com") 269 | response = opener.open(request) # 第三步:使用opener對象(這里:調用opener對象的open()方法發送request請求) 270 | print response.read() 271 | 272 | 273 | 附加1:選擇隨機代理去訪問制定網頁 274 | ------------------------------------------------------------------------------------------------------------------------------------------------------- 275 | #如果代理IP足夠多,就可以像隨機獲取User-Agent一樣,隨機選擇一個代理去訪問網站。 276 | 277 | #!/usr/bin/env python 278 | #coding:utf-8 279 | 280 | import urllib2 281 | import random #引入隨機模塊 282 | 283 | proxy_list = [ # 創建一個可供選擇的隨機代理列表 284 | {"http":"200.200.200.200:80"}, 285 | {"http":"200.200.200.201:8080"}, 286 | {"http":"200.200.200.202:808"}, 287 | {"http":"200.200.200.203:880"}, 288 | ] 289 | proxy = random.choice(proxy_list) # 從列表中隨機選擇一個代理 290 | proxy_handler = urllib2.ProxyHandler(proxy_list) # 第一步:創建處理器對象(這里創建一個(支持有代理)的ProxyHandler處理器對象) 291 | proxy_opener = urllib2.build_opener(proxy_handler) # 第二步:創建opener對象(這里:調用urllib2.build_opener()方法來創建opener對象) 292 | response = proxy_opener.open("http://www.baidu.com") # 第三步:使用opener對象(這里:調用opener對象的open()方法發送request請求) 293 | print response.read() 294 | 295 | 296 | 附加2:采用ProxyHandler處理器創建支持私密代理訪問的opener(代碼中直接顯示用戶名和密碼) 297 | ---------------------------------------------------------------------------------------------------------------------------------------------------------- 298 | #ProxyHandler處理器也能創建支持私密代理的opener 299 | 300 | import urllib2 # 第一步:創建處理器對象(這里創建一個(支持私密代理驗證) 的ProxyHandler處理器)----注意驗證用戶名\密碼\代理IP\端口的寫法 301 | authproxy_handler = urllib2.ProxyHandler({"http":"mr_mao_hacker:sffqry9r@61.158.163.130:16816"}) 302 | opener = urllib2.build_opener(authproxy_handler) # 第二步:創建opener對象 303 | response = opener.open("http://www.baidu.com") # 第三步:使用opener對象 304 | print response.read() 305 | 306 | 307 | 附加3:采用ProxyHandler處理器創建支持私密代理訪問的opener(代碼中隱藏用戶名和密碼) 308 | ---------------------------------------------------------------------------------------------------------------------------------------------------------- 309 | #將用戶名和密碼保存為環境變量,通過獲取環境變量的方式獲得用戶名和密碼,從而在代碼中隱藏用戶名和密碼 310 | 311 | import urllib2 312 | import os 313 | proxyuser = os.environ.get("proxyuser") # 獲取存放在環境變量中的授權代理用戶名/密碼 314 | proxypasswd = os.environ.get("proxypasswd") # 第一步:創建處理器對象(這里創建一個(支持私密代理驗證)的ProxyHanlder處理器)------采用用戶名/密碼/代理IP/端口采用拼接的方式 315 | authproxy_handler = urllib2.ProxyHandler({"http":proxyuser+":"+proxypasswd+"@61.158.163.130:16816"}) 316 | opener = urllib2.build_opener(authproxy_handler) # 第二步:創建opener對象(這里:調用urllib2.build_opener()方法來創建opener對象) 317 | request = urllib2.Request("http://www.baidu.com") # 構建請求 318 | response = opener.open(request) # 第三步:使用opener對象(這里:調用opener對象的open()方法發送request請求) 319 | print response.read() 320 | 321 | #錯誤知曉:如果私密代理用戶名或密碼錯誤,會報407錯誤(HTTP Error 407: Proxy Authentication Required)表示代理沒有通過身份驗證. 322 | #注意:ProxyHandler()處理器雖然也能夠創建支持私密代理的opener對象,但是專業的還是下面的ProxyBasicAuthHandler()處理器(專門進行私密代理授權驗證) 323 | 324 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 325 326 327 4.利用ProxyBasicAuthHandler(代理授權驗證)處理器創建支持私密代理訪問的opener 328 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 329 | 330 | 准備知識:HTTPPasswordMgrWithDefaultRealm()類 331 | ---------------------------------------------------- 332 | HTTPPasswordMgrWithDefaultRealm()類將創建一個密碼管理對象,用來保存HTTP請求相關的用戶名和密碼,主要有兩個應用場景: 333 | (1).驗證代理授權的用戶名和密碼(ProxyBasicAuthHandler) 334 | (2).驗證web客戶端的用戶名和密碼(HTTPBasicAuthHandler) 335 | 336 | 代碼思路: 337 | (1)使用HTTPPasswordMgrWithDefaultRealm()來保存私密代理的用戶名和密碼 338 | (2)使用ProxyBasicAuthHandler()來處理代理的身份驗證 339 | 340 | import urllib2 341 | user = "mr_mao_hacker" # 設置代理賬戶/密碼/代碼IP端口 342 | passwd = "sffqry9r" 343 | proxy_server = "61.158.163.130:16816" 344 | passwdmgr = urllib2.HTTPPasswordMgrWithDefaultRealm() # 創建一個密碼管理器對象,用來保存代理賬戶/密碼/代理IP端口 345 | passwdmgr.add_password(None,proxy_server,user,passwd) # 將設置好的代理賬戶/密碼/代理IP端口信息保存到這個密碼管理器對象中 346 | proxy_auth_handler = urllib2.ProxyBasicAuthHandler(passwdmgr) # 第一步:創建處理器對象(這里創建一個(私密代理驗證)的ProxyBasicAuthHanlder處理器)----傳入的參數是密碼管理器對象 347 | opener = urllib2.build_opener(proxy_auth_handler) # 第二步:創建opener對象(這里:調用build_opener()方法來創建opener對象) 348 | request = urllib2.Request("http://www.baidu.com") # 構建請求 349 | response = opener.open(request) # 第三步:使用opener對象(這里:調用opener對象的open()方法發送request請求) 350 | print response.read() 351 | 352 | # 也可以采用上述將用戶名/密碼設置成環境變量的方式,避免直接在代碼中出現明顯的用戶名/密碼信息!! 353 | 354 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 355 356 357 5.利用HTTPBasicAuthHandler(web客戶端授權驗證)處理器創建訪問web頁面需要用戶身份驗證的opener 358 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 359 | # 有些web服務器(包括HTTP/FTP等)訪問時,需要進行用戶身份驗證,爬蟲直接訪問會報HTTP 401錯誤(HTTP Error 401: Unauthorized)表示訪問身份未經授權 360 | # 如果我們有這些web服務器的用戶名和密碼,就可通過下述方法去訪問爬取 361 | 362 | 代碼思路: 363 | ---------------------------------------------------- 364 | (1) 使用HTTPPasswordMgrWithDefaultRealm()來保存web客戶端的用戶名和密碼 365 | (2) 使用ProxyBasicAuthHandler()來處理web客戶端的身份驗證 366 | 367 | import urllib2 368 | user = "zhangsan" # 設置代理賬戶/密碼/代碼IP端口 369 | passwd = "123456" 370 | web_server = "http://200.200.200.200:80" 371 | passwdmgr = urllib2.HTTPPasswordMgrWithDefaultRealm() # 創建一個密碼管理器對象,用來保存代理賬戶/密碼/代理IP端口 372 | passwdmgr.add_password(None,web_server,user,passwd) # 將設置好的代理賬戶/密碼/代理IP端口信息保存到這個密碼管理器對象中 373 | http_auth_handler = urllib2.HTTPBasicAuthHandler(passwdmgr) # 第一步:創建處理器對象(這里創建一個(web客戶端授權驗證)的HTTPBasicAuthHandler處理器)----傳入的參數是密碼管理器對象 374 | opener = urllib2.build_opener(http_auth_handler) # 第二步:創建opener對象(這里:調用urllib2.build_opener()方法來創建opener對象) 375 | urllib2.install_opener(opener) # 如果需要,可以選擇通過install_opener()方法將自定義的opener定義為全局的opener 376 | request = urllib2.Request("http://www.baidu.com") # 創建請求 377 | response = urllib2.urlopen(request) # 第三步:使用opener對象(因為自定義opener被定義為全局opener,這里:可使用urllib2.urlopen()方法調用opener對象發送request請求) 378 | print response.read() 379 | 380 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 381 382 383 6.利用HTTPCookieProcessor處理器創建支持處理cookie的opener 384 ---------------------------------------------------------------------------------------------------------------------------------------------------------- 385 | 386 | 預先了解:cookie/cookie原理/cookie格式 387 | ---------------------------------------------------- 388 | cookie: 是指某些網站服務器為了辨別用戶身份和進行session跟蹤,而儲存在用戶瀏覽器上的文本文件,cookie可以保持登陸信息到用戶下次與服務器的對話. 389 | 390 | cookie原理: HTTP是無狀態的面向連接的協議,為了保存連接狀態,引入了cookie機制,cookie是http消息頭部中的一種屬性包括: 391 | cookie名字(Name)/值(Value)/過期時間(Expires/Max-Age)/作用路徑(Path)/所在域名(Domain)/使用cookie進行安全連接(Secure) (Name和Value是cookie的必要條件) 392 | 393 | cookie格式: (cookie由變量名和值組成)-----Set-Cookie: NAME=VALUE;Expires=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE 394 | 395 | 396 | 預先案例:通過post抓包工具抓取到的有登陸信息的完整cookie信息模擬登陸之前已登錄的人人網頁 397 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- 398 | | cookie在爬蟲方面最典型的應用是判定注冊用戶是否已經登陸網站,用戶可能會得到提示,是否在下一次進入此網站時保留用戶信息以便簡化登陸手續. 399 | | 400 | | import urllib2 401 | | "Host":"www.renren.com", 402 | | 403 | | headers = { # 1. 構建一個已經登錄過的用戶的headers信息 404 | | "Connection":"keep-alive", 405 | | "Upgrade-Insercure-Reuqests":"1", 406 | | "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36", 407 | | "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", 408 | | "Accept-Language":"zh-CN,zh;q=0.8,en;q=0.6", 409 | | # Accept-Encoding: gzip, deflate, sdch, # 便於終端閱讀,表示不支持壓縮文件 410 | | "Cookie": " ln_uact=mr_mao_hacker@163.com; id=327550029; xnsid=745033c5; ver=7.0;...... " 411 | | } # 重點:這個cookie是保存了密碼無需重復登錄的用戶的cookie,這個Cookie里記錄了用戶名,密碼(通常經過RAS加密) 412 | | 413 | | request = urllib2.Request("http://www.renren.com",headers = headers) # 2. 通過headers里的報頭信息(主要是Cookie信息),構建Request對象 414 | | response = urllib2.urlopen(request) # 3. 直接訪問renren主頁,服務器會根據headers報頭信息(主要是Cookie信息),判斷這是一個已經登錄的用戶,並返回相應的頁面 415 | | print response.read() # 4. 打印響應內容(會看到"人人網-毛兆軍") 416 | | 417 | | # 這種方式雖然能夠獲取一個有登錄信息的Cookie實現模擬登陸,但是太過復雜,我們需要首先在瀏覽器登陸賬戶,並且設置保存密碼,並且通過抓包工具才能獲得這個cookie,為了不使 418 | | 用這么復雜的方式,於是下面利用cookielib庫和HTTPCookieProcessor處理器的簡單方法應運而生! 419 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- 420 | 421 | 422 | 預先了解:cookielib庫 423 | ---------------------------------------------------- 424 | cookielib模塊的主要對象有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar 425 | (1)CookieJar(): 整個cookie都存儲在內存中,對CookieJar實例進行垃圾回收后cookie也將丟失.用於管理HTTP cookie值、存儲HTTP請求生成的cookie、向傳出的HTTP請求添加cookie的對象. 426 | (2)FileCookieJar(filename,delayload=None,policy=None): 從CookieJar派生而來,用來創建FileCookieJar實例,檢索cookie信息並將cookie存儲到文件中。filename是存儲cookie的文件名, 427 | delayload為True時支持延遲訪問訪問文件,即只有在需要時才讀取文件或在文件中存儲數據。 428 | (3)MozillaCookieJar(filename,delayload=None,policy=None): 從FileCookieJar派生而來,創建與Mozilla瀏覽器 cookies.txt兼容的FileCookieJar實例。 429 | (4)LWPCookieJar(filename,delayload=None,policy=None): 從FileCookieJar派生而來,創建與libwww-perl標准的 Set-Cookie3 文件格式兼容的FileCookieJar實例。 430 | 注意:大多數情況下,我們只用CookieJar(),如果需要和本地文件交互,就用 MozillaCookjar() 或 LWPCookieJar() 431 | 432 | 433 | 代碼思路:結合cookielib庫和HTTPCookieProcessor處理器 434 | ---------------------------------------------------- 435 | 在python中處理cookie,一般是通過cookielib模塊和urllib2.HTTPCookieProcessor()類一起使用.其各自作用如下: 436 | cookielib模塊: 提供存儲cookie的對象 437 | HTTPCookieProcessor處理器: 用於處理這些cookie對象,並構建handler對象 438 | 439 | 440 | 實操1:獲取cookie並保存到內存中---利用CookieJar()對象 441 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- 442 | | import urllib2 443 | | import cookielib 444 | | cookie_jar = cookielib.CookieJar() # 創建一個CookieJar對象實例來保存cookie到內存中 445 | | cookie_handler = urllib2.HTTPCookieProcessor(cookie_jar) # 第一步:創建處理器對象(這里創建一個(處理cookie)的HTTPCookieProcessor處理器)----傳入的參數是CookieJar()對象 446 | | opener = urllib2.build_opener(cookie_handler) # 第二步:創建opener對象(這里:調用urllib2.build_opener()方法來創建opener對象) 447 | | opener.open("http://www.baidu.com") # 第三步:使用opener對象(這里:調用opener對象的open()方法發送request請求) 448 | | cookie_string = "" 449 | | for item in cookie_jar: 450 | | cookie_string = cookie_string + item.name + "=" + item.value + ";" 451 | | print cookie_string[:-1] # 去掉最后一位分號,這樣就按標准格式將保存的cookie打印出來了 452 | | 453 | | # 以上方法將Cookie保存到cookiejar對象中,然后打印出了cookie中的值,也就是訪問百度首頁的Cookie值。 454 | | 455 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- 456 | 457 | 458 | 實操2:獲取cookie並保存到文件中---利用MozillaCookieJar()對象 459 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- 460 | | import urllib2 461 | | import cookielkib 462 | | filename = "cookie_save.txt" # 本地保存cookie的文件名 463 | | cookie_save_jar = cookielib.MozillaCookieJar(filename) # 創建一個MozillaCookieJar對象實例來保存cookie到本地文件中---參數是本地文件名 464 | | cookie_handler = urllib2.HTTPCookieProcessor(cookie_save_jar) # 第一步:創建處理器對象(這里創建一個(處理cookie)的HTTPCookieProcessor處理器)----傳入的參數是MozillaCookieJar()對象 465 | | opener = urllib2.build_opener(cookie_handler) # 第二步:創建opener對象(這里:調用urllib2.build_opener()方法來創建opener對象) 466 | | opener.open("http://www.baidu.com") # 第三步:使用opener對象(這里:調用opener對象的open()方法發送request請求) 467 | | cookie_save_jar.save() # 保存cookie到本地文件 468 | | 469 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- 470 | 471 | 472 | 實操3:從文件中獲取cookies,做為請求的一部分去訪問---利用MozillaCookieJar()對象 473 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- 474 | | import urllib2 475 | | import cookielib 476 | | cookie_load_jar = cookielib.MozillaCookJar() # 創建一個MozillaCookieJar對象實例來讀取本地文件中 477 | | cookie_load_jar.load("cookie_save.txt") # 利用這個MozillaCookieJar對象實例來讀取本地存放cookie的文件--cookie_save.txt 478 | | cookie_handler = urllib2.HTTPCookieProcessor(cookie_load_jar) # 第一步:創建處理器對象(這里創建一個(處理cookie)的HTTPCookieProcessor處理器)----傳入的參數是MozillaCookieJar()對象 479 | | opener = urllib2.build_opener(cookie_handler) # 第二步:創建opener對象(這里:調用urllib2.build_opener()方法來創建opener對象) 480 | | response=opener.open("http://www.baidu.com") # 第三步:使用opener對象(這里:調用opener對象的open()方法發送request請求) 481 | | print response.read() 482 | | 483 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- 484 | 485 | 486 | 案例:利用cookielib和post模擬登錄人人網 487 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- 488 | | 即:先通過post用戶名和密碼登陸人人網並同時保存好本次成功登陸的cookie,然后帶着這個cookie第二次直接訪問好友主頁 489 | | 490 | | import urllib 491 | | import urllib2 492 | | import cookielib 493 | | cookie_jar =cookielib.CookieJar() # 創建一個CookieJar對象實例來保存cookie到內存中 494 | | cookie_handler = urllib2.HTTPCookieProcessor(cookie_jar) # 第一步:創建處理器對象(這里創建一個(處理cookie)的HTTPCookieProcessor處理器)----傳入的參數是CookieJar()對象 495 | | opener = urllib2.build_opener(cookie_handler) # 第二步:創建opener對象(這里:調用urllib2.build_opener()方法來創建opener對象) 496 | | opener.addheaders = [("User-Agent","Mozilla/5.0 .....") # 向headers中添加一個User-Agent信息,addheaders接受一個列表,里面每個元素都是一個headers信息的元祖, opener將附帶headers信息 497 | | post_data = {"email":"583803258@qq.com","password":"123456"} # 登陸需要的用戶名和密碼信息 498 | | post_data = urllib.urlencode(post_data) # 將這些登陸需要的信息進行urlencode()轉碼,轉碼后才能post 499 | | url = "http://www.renren.com/PLogin.do" # 第一次訪問的登陸頁面 500 | | request = urllib2.Request(url,data=post_data) # 創建post請求 501 | | first_response = opener.open(request) # 第三步:使用opener對象(這里:調用opener對象的open()方法發送post請求),獲取到成功登陸的cookie信息被CookieJar()存放在內存中 502 | | second_response = opener.open("http://www.renren.com/405858138/profile") # 第二次使用opener去請求好友主頁時由HTTPCookieProcessor處理器生成的opener就會附帶上之前的cookie信息 503 | | print second_response.read() # 打印成功訪問到好友的主頁信息 504 | | 505 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- 506 | 507 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 508 509 510 urllib2的異常處理 -----URLError類/HTTPError類 511 512 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 513 | 當我們使用urlopen/opener.open發送一個請求,如果urlopen/opener.open不能處理這個response就會產生錯誤,這里主要說的是URLError和HTTPError 514 | 515 | URLError類 516 | ---------------------------------------------------- 517 | URLError產生的原因主要有: 518 | (1)沒有網絡連接 519 | (2)服務器連接失敗 520 | (3)找不到制定服務器 521 | 我們可以采用try except語句來捕獲異常,例如下面的例子訪問一個不存在的域名([Errno 8] nodename nor servname provided, or not known)錯誤原因找不到制定服務器 522 | 523 | import urllib2 524 | request = urllib2.Request("http://www.abcdxdd.com") 525 | try: 526 | urllib2.urlopen(request,timeout=5) 527 | except urllib2.URLError,err: # 捕獲URLlib.URLError時將錯誤信息保存到err變量並打印err變量值 528 | print err 529 | 運行結果: 530 | <urlopen error [Errno 8] nodename nor servname provided, or not known> 531 | 532 | 533 | HTTPError類 534 | ---------------------------------------------------- 535 | HTTPError是URLError的子類,使用urllib2.HTTPError時會返回服務器的狀態響應碼和錯誤信息,使用如下: 536 | 537 | import urllib2 538 | 539 | request = urllib2.Request("http://blog.baidu.com/itcast") 540 | try: 541 | urllib2.urlopen(request) 542 | except urllib2.HTTPError,err: # 捕獲URLlib.HTTPError時將錯誤信息保存到err變量並打印狀態碼和err信息 543 | print err.code 544 | print err 545 | 運行結果: 546 | 404 547 | HTTP Error 404: Not Found # 404錯誤,要么URL不對,要么IP被封 548 | 注意: urllib2可以為我們處理重定向的頁面(也就是3開頭的響應碼),100-299范圍的號碼表示成功,所以我們只能看到400-599的錯誤號碼。 549 | 550 | 551 | 綜合編寫urllib2異常處理: 552 | ---------------------------------------------------- 553 | 兩種錯誤都能捕獲-----由於HTTPError的父類是URLError,所以父類的異常應當寫到子類異常的后面 554 | 555 | import urllib2 556 | 557 | request = urllib2.Request("http://blog.baidu.com/itcast") 558 | try: 559 | urllib2.urlopen(request) 560 | except urllib2.HTTPError,err: #如果首先捕獲到HTTPError這個子類異常,則打印出錯誤狀態碼 561 | print err.code 562 | except urllib2.URLError.err: #如果父類URLError捕獲到了(HTTPError子類沒有捕獲到的)異常,則打印出該異常的內容 563 | print err 564 | else: 565 | print "OK" 566 | 運行結果: 567 | 404 568 | 如上形式便可做到-----首先捕獲子類的異常,如果子類捕獲不到,那么可以捕獲父類的異常。 569 | 570 | 571 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 572 573 附錄:HTTP響應狀態碼參考 574 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 575 | 1xx:信息 576 | 577 | 100 Continue 578 | 服務器僅接收到部分請求,但是一旦服務器並沒有拒絕該請求,客戶端應該繼續發送其余的請求。 579 | 101 Switching Protocols 580 | 服務器轉換協議:服務器將遵從客戶的請求轉換到另外一種協議。 581 | 582 | 583 | 584 | 2xx:成功 585 | 586 | 200 OK 587 | 請求成功(其后是對GET和POST請求的應答文檔) 588 | 201 Created 589 | 請求被創建完成,同時新的資源被創建。 590 | 202 Accepted 591 | 供處理的請求已被接受,但是處理未完成。 592 | 203 Non-authoritative Information 593 | 文檔已經正常地返回,但一些應答頭可能不正確,因為使用的是文檔的拷貝。 594 | 204 No Content 595 | 沒有新文檔。瀏覽器應該繼續顯示原來的文檔。如果用戶定期地刷新頁面,而Servlet可以確定用戶文檔足夠新,這個狀態代碼是很有用的。 596 | 205 Reset Content 597 | 沒有新文檔。但瀏覽器應該重置它所顯示的內容。用來強制瀏覽器清除表單輸入內容。 598 | 206 Partial Content 599 | 客戶發送了一個帶有Range頭的GET請求,服務器完成了它。 600 | 601 | 602 | 603 | 3xx:重定向 604 | 605 | 300 Multiple Choices 606 | 多重選擇。鏈接列表。用戶可以選擇某鏈接到達目的地。最多允許五個地址。 607 | 301 Moved Permanently 608 | 所請求的頁面已經轉移至新的url。 609 | 302 Moved Temporarily 610 | 所請求的頁面已經臨時轉移至新的url。 611 | 303 See Other 612 | 所請求的頁面可在別的url下被找到。 613 | 304 Not Modified 614 | 未按預期修改文檔。客戶端有緩沖的文檔並發出了一個條件性的請求(一般是提供If-Modified-Since頭表示客戶只想比指定日期更新的文檔)。服務器告訴客戶,原來緩沖的文檔還可以繼續使用。 615 | 305 Use Proxy 616 | 客戶請求的文檔應該通過Location頭所指明的代理服務器提取。 617 | 306 Unused 618 | 此代碼被用於前一版本。目前已不再使用,但是代碼依然被保留。 619 | 307 Temporary Redirect 620 | 被請求的頁面已經臨時移至新的url。 621 | 622 | 623 | 624 | 4xx:客戶端錯誤 625 | 626 | 400 Bad Request 627 | 服務器未能理解請求。 628 | 401 Unauthorized 629 | 被請求的頁面需要用戶名和密碼。 630 | 401.1 631 | 登錄失敗。 632 | 401.2 633 | 服務器配置導致登錄失敗。 634 | 401.3 635 | 由於 ACL 對資源的限制而未獲得授權。 636 | 401.4 637 | 篩選器授權失敗。 638 | 401.5 639 | ISAPI/CGI 應用程序授權失敗。 640 | 401.7 641 | 訪問被 Web 服務器上的 URL 授權策略拒絕。這個錯誤代碼為 IIS 6.0 所專用。 642 | 402 Payment Required 643 | 此代碼尚無法使用。 644 | 403 Forbidden 645 | 對被請求頁面的訪問被禁止。 646 | 403.1 647 | 執行訪問被禁止。 648 | 403.2 649 | 讀訪問被禁止。 650 | 403.3 651 | 寫訪問被禁止。 652 | 403.4 653 | 要求 SSL。 654 | 403.5 655 | 要求 SSL 128。 656 | 403.6 657 | IP 地址被拒絕。 658 | 403.7 659 | 要求客戶端證書。 660 | 403.8 661 | 站點訪問被拒絕。 662 | 403.9 663 | 用戶數過多。 664 | 403.10 665 | 配置無效。 666 | 403.11 667 | 密碼更改。 668 | 403.12 669 | 拒絕訪問映射表。 670 | 403.13 671 | 客戶端證書被吊銷。 672 | 403.14 673 | 拒絕目錄列表。 674 | 403.15 675 | 超出客戶端訪問許可。 676 | 403.16 677 | 客戶端證書不受信任或無效。 678 | 403.17 679 | 客戶端證書已過期或尚未生效。 680 | 403.18 681 | 在當前的應用程序池中不能執行所請求的 URL。這個錯誤代碼為 IIS 6.0 所專用。 682 | 403.19 683 | 不能為這個應用程序池中的客戶端執行 CGI。這個錯誤代碼為 IIS 6.0 所專用。 684 | 403.20 685 | Passport 登錄失敗。這個錯誤代碼為 IIS 6.0 所專用。 686 | 404 Not Found 687 | 服務器無法找到被請求的頁面。 688 | 404.0 689 | 沒有找到文件或目錄。 690 | 404.1 691 | 無法在所請求的端口上訪問 Web 站點。 692 | 404.2 693 | Web 服務擴展鎖定策略阻止本請求。 694 | 404.3 695 | MIME 映射策略阻止本請求。 696 | 405 Method Not Allowed 697 | 請求中指定的方法不被允許。 698 | 406 Not Acceptable 699 | 服務器生成的響應無法被客戶端所接受。 700 | 407 Proxy Authentication Required 701 | 用戶必須首先使用代理服務器進行驗證,這樣請求才會被處理。 702 | 408 Request Timeout 703 | 請求超出了服務器的等待時間。 704 | 409 Conflict 705 | 由於沖突,請求無法被完成。 706 | 410 Gone 707 | 被請求的頁面不可用。 708 | 411 Length Required 709 | "Content-Length" 未被定義。如果無此內容,服務器不會接受請求。 710 | 412 Precondition Failed 711 | 請求中的前提條件被服務器評估為失敗。 712 | 413 Request Entity Too Large 713 | 由於所請求的實體的太大,服務器不會接受請求。 714 | 414 Request-url Too Long 715 | 由於url太長,服務器不會接受請求。當post請求被轉換為帶有很長的查詢信息的get請求時,就會發生這種情況。 716 | 415 Unsupported Media Type 717 | 由於媒介類型不被支持,服務器不會接受請求。 718 | 416 Requested Range Not Satisfiable 719 | 服務器不能滿足客戶在請求中指定的Range頭。 720 | 417 Expectation Failed 721 | 執行失敗。 722 | 423 723 | 鎖定的錯誤。 724 | 725 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------