【Python爬蟲學習筆記2】urllib庫的基本使用
urllib庫是python內置的實現HTTP請求的基本庫,通過它可以模擬瀏覽器的行為,向指定的服務器發送一個請求,並保存服務器返回的數據。
urlopen函數
函數原型:urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,*, cafile=None, capath=None, cadefault=False, context=None)
此函數位於request模塊中,可以用來發送請求並獲取服務器的響應,其中常用的參數有url(必須指定的參數,HTTP請求地址)、data(可選參數,用於POST請求傳遞數據,但內容需要進行字節流編碼)、timeout(可選參數,用於設置超時時間,單位為秒,當超時後還未得到響應就會拋出異常)。其返回的是一個<http.client.HTTPResponse>響應對象,具有read(size)、readline、readlines以及getcode等方法。
## 示例1——使用urlopen函數發送請求並獲取響應
# 導入request模塊 from urlib import request # 設置url url = ‘http://www.baidu.com‘ # 使用urlopen發送HTTP請求 response = request.urlopen(url,timeout=3) # 返回html webpage_html = response.read().decode(‘utf-8‘) print(webpage_html) # 返回請求狀態碼 webpage_status = response.getcode() # 或webpage_status=response.statusprint(webpage_status)
urlretrieve函數
函數原型:urlretrieve(url, filename=None, reporthook=None, data=None)
該函數位於request模塊中,可以用於文件的下載,如html代碼、image圖片等。其中參數url和data含義與urlopen函數一樣;filename為所保存文件的文件名;reporthook 為回調函數,當連接服務器並傳輸完數據塊後會自動觸發,可以利用這個回調函數來顯示當前的下載進度。
## 示例2——使用urlretrieve函數下載文件 from urllib import request# 下載html文件 weburl = ‘http://www.baidu.com‘ request.urlretrieve(weburl, ‘baidu.html‘) # 下載jpg文件 jpgurl = ‘http://pic33.nipic.com/20130918/8952533_114903002000_2.jpg‘ request.urlretrieve(jpgurl,‘nipic.jpg‘)
urlencode函數和parse_qs函數
函數原型:urlencode(query, doseq=False, safe=‘‘, encoding=None, errors=None,quote_via=quote_plus)
由於瀏覽器url編碼規則,我們使用代碼發送請求時如果有中文和其他字符時,必須進行一定的編碼,這時可使用urlencode函數來幫助我們實現數據的URL編碼轉換。該函數位於parse模塊中,其有多個參數,在爬蟲應用中只需要掌握query參數(待編碼的數據)。
## 示例3——使用urlencode實現百度中文搜索 from urllib import request from urllib import parse # 設置url,此處url的構造法則可參看學習筆記——網絡協議與請求基礎 url = ‘http://www.baidu.com/s‘ # 設置請求的數據參數 parameters = {‘wd‘: ‘博客園‘} # 編碼查詢字符串並重定義url querystring = parse.urlencode(parameters) # querystring = ‘wd=%E5%8D%9A%E5%AE%A2%E5%9B%AD‘ url = url + ‘?‘ + querystring # 發送請求並返回信息 response = request.urlopen(url) print(response.read().decode(‘utf-8‘))
同樣,有編碼亦有解碼,在parse模塊中解碼函數為parse_qs,使用方法也比較簡單,傳入參數待解碼字符串即可。
##示例4——使用parse_qs函數解碼 # 對url傳遞的參數進行格式化解碼 scoreparam = parse.parse_qs(querystring) print(scoreparam) # {‘wd‘: [‘博客園‘]}
urlsplit函數和urlparse函數
urlparse函數和urlsplit函數均可以用於實現對url地址字符串的格式化分割,即將url分為幾個不同的部分。這兩個函數均位於pasre模塊中,使用時其參數均只需要傳入一個編碼後的url即可,返回值為一個保存了url各部分的字典數據。其中,二者唯一的區別是urlparse函數的返回對象比urlsplit函數的多了params屬性。
## 示例5——使用urlsplit函數和urlparse函數解析url from urllib import parse # 設置url並解析字符串 url = ‘http://www.baidu.com/s;hello?wd=python&username=UnikFox#3‘ result_parse = parse.urlparse(url) result_split = parse.urlsplit(url) # 獲取url解析數據 print(result_parse) #ParseResult(scheme=‘http‘, netloc=‘www.baidu.com‘, path=‘/s‘, params=‘hello‘, query=‘wd=python&username=UnikFox‘, fragment=‘3‘) print(result_split) #SplitResult(scheme=‘http‘, netloc=‘www.baidu.com‘, path=‘/s;hello‘, query=‘wd=python&username=UnikFox‘, fragment=‘3‘) print(‘netloc‘,result_parse.netloc) #netloc www.baidu.com print(‘query‘,result_parse.query) #query wd=python&username=UnikFox
request.Request類
在我們發送HTTP請求時,如果僅靠urlopen幾個參數是不足以構建一個完整的請求,特別是在一些反爬蟲機制中常常通過請求頭來判斷是否為合法用戶,因此我們爬蟲代碼中常常需要添加請求頭和一些附加數據來反-反爬蟲,這時候便可利用Request類來實現這些設置。
類原型:request.Request(url, data=None, headers={},origin_req_host=None, unverifiable=False,method=None)
其中,參數url為請求URL,data為字節流bytes型數據,headers為請求頭字典,origin_req_host為請求方域名或IP地址,unverifiable表示請求是否是無法驗證的,method表示請求方法字符串。
##示例6——使用Request類發送請求 from urllib import request,parse # 設置url為拉勾網數據源 url = ‘https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false‘ # 設置請求頭 headers = { ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36‘, ‘Referer‘: ‘https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=‘ } # 設置 data = { ‘first‘: ‘true‘, ‘pn‘: ‘1‘, ‘kd‘: ‘python‘ } # 實例化Request類 res = request.Request(url, headers=headers, data=parse.urlencode(data).encode(‘utf-8‘), method=‘POST‘) # 發送請求 response = request.urlopen(res) print(response.read().decode(‘utf-8‘))
ProxyHandler處理器(代理設置)
在實際中,很多網站常常檢測IP訪問量等信息來判斷請求是否為爬蟲所發,當訪問量過於異常(如1s內發送數百次請求)時服務器就會將此IP加入黑名單以拒絕訪問。這種反爬蟲機制對與爬蟲來說是非常不友好的,特別是當我們主機IP被封的時候,因此我們在編寫爬蟲時很有必要使用代理。
那麽,什麽是代理?其實,代理就是不直接通過主機而是通過第三方中轉渠道訪問目標服務器,其過程大概是這樣:主機(爬蟲)——代理服務器——目標服務器。使用代理後目標服務器則只會標識代理服務器IP,而不知道爬蟲的IP,因此不用擔心爬蟲IP被封,當然代理服務器的IP仍然會被封,這時候換一個代理IP便可以了。另外,返回的響應也是一個逆過程,即目標服務器——代理服務器——主機(爬蟲),這裏要註意的是,由於代理的中轉使用,數據的傳輸可能會比較慢。
在urllib庫中,代理依賴request模塊,其通過ProxyHandler類和opener對象來設置並使用代理服務器。
##示例7——使用ProxyHandler類設置代理 # 設置url——用於IP檢查 url = ‘http://httpbin.org/ip‘ # Step1:實例化ProxyHandler類,傳入參數代理的字典數據 handler = request.ProxyHandler({‘http‘:‘223.241.78.43:8010‘}) # Step2:生成opener對象,傳入參數handler opener = request.build_opener(handler) # Step3:使用opener發送請求 response = opener.open(url) print(response.read().decode(‘utf-8‘))
另外,關於代理服務器,可以自行查閱網絡資料。
使用Cookie模擬登陸
在前一篇博客中已經介紹,Cookie 是網站服務器用於識別用戶身份和數據追蹤而儲存在本地的文本文件,使用Cookie後可以保持登錄信息以方便與服務器的會話。這也是常用的反爬蟲機制數據,如果要反-反爬蟲,我們可以直接在請求頭header中設置Cookie。
Cookie設置格式:Set-Cookie: NAME=VALUE;Expires/Max-age=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE
其中,NAME為cookie名,VALUE為cookie值,Expires為過期時間,Path為cookie作用路徑,Domain為作用的域名,SECURE為是否設置只在https協議下起作用。
通常來說,在爬蟲裏我們可以直接設置復制正常訪問下獲取的Cookie就行,在此不進行演示。
雖然這種復制Cookie方法可行,但過於繁瑣,因此,我們可以借助http.cookiejar模塊和urllib模塊的HTTPCookieProcessor處理器類來處理Cookie。http.cookiejar模塊主要是提供用於存儲cookie的對象。而HTTPCookieProcessor處理器主要是處理cookie對象,並構建handler對象。
##示例8——使用cookieJar自動登陸 from urllib import request,parse from http.cookiejar import CookieJar # 構建opener對象 # Step1:實例化CookieJar類對象 cookiejar = CookieJar() # Step2:生成handler對象,傳入參數cookiejar handler = request.HTTPCookieProcessor(cookiejar) # Step3:生成opener對象,傳入參數handler opener = request.build_opener(handler) # 設置headers和data(具體數據名可從HTML文件的id獲取) headers = { ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36‘ } data = { ‘input1‘:‘UnikFox‘, ‘input2‘:‘123456‘ } # 設置登陸url並實例化Request類,再通過opener發送http請求(即可為登陸狀態) Login_url = ‘https://passport.cnblogs.com/user/signin‘ req = request.Request(Login_url,headers=headers,data=parse.urlencode(data).encode(‘utf-8‘)) opener.open(req) # 此後同樣設置url實例化對象,再通過同一個opener發送請求即可利用源Cookie訪問頁面 dapeng_url = ‘http://www.example.com‘ req = request.Request(dapeng_url,headers=headers) response = opener.open(req) print(response.read().decode(‘utf-8‘))
Cookie本地化保存與讀取
在爬蟲中,如果每次都設置cookie是一個很費勁的事,因此我們可以將某次的Cookie保存在本地以便下次需要時讀取便可。實現這一功能的是http.cookiejar模塊中的MozillaCookieJar,其是一個滿足火狐協議用於管理cookie保存與讀取的類。
保存cookie到本地,可以使用cookiejar.save方法,而從本地加載cookie,則需要使用cookiejar.load方法,這兩種方法均需要指定文件名。
##示例9——Cookie本地化保存與讀取 from urllib import request from http.cookiejar import CookieJar,MozillaCookieJar #保存 # 構建opener對象 cookiejar = MozillaCookieJar(‘cookie.txt‘) #在此指定文件名後save可以不用再次指定文件名 handler = request.HTTPCookieProcessor(cookiejar) opener = request.build_opener(handler) # 發送請求 response = opener.open(‘https://cn.bing.com/‘) # 使用cookiejar保存cookie(同時參數ignore_discard表示也保存一些過期的cookie) cookiejar.save(ignore_discard=True) #讀取 cookiejar = MozillaCookieJar(‘cookie.txt‘) #在此指定文件名後load可以不用再次指定文件名 cookiejar.load(ignore_discard=True) for cookie in cookiejar: print(cookie)
如下為cookie.txt文件內容:
【Python爬蟲學習筆記2】urllib庫的基本使用