概念:urllib是Python自帶的一個用於爬蟲的庫,其主要做用就是能夠經過代碼模擬瀏覽器發送請求。其常被用到的子模塊在Python3中的爲urllib.request和urllib.parse,在Python2中是urllib和urllib2。html
使用流程:web
1.第一個簡單的爬蟲程序:爬取搜狗首頁的頁面數據ajax
import urllib.request import urllib.parse #1.指定url url = 'https://www.sogou.com/' #2.發起請求:使用urlopen函數發起請求,該函數返回一個響應對象 response = urllib.request.urlopen(url=url) #3.獲取響應對象中的頁面數據:read函數能夠獲取響應對象中byte類型的數據值 page_text = response.read() #4.持久化存儲:將爬取的頁面數據寫入文件進行保存 with open('./sogou.html','w',encoding='utf-8') as fp: fp.write(page_text.decode())#使用decode將page_text轉成字符串類型
補充說明:瀏覽器
urlopen函數原型: urllib.request.urlopen(url, data=None, timeout=<object object at 0x10af327d0>, *, cafile=None, capath=None, cadefault=False, context=None) 在上述案例中咱們只使用了該函數中的第一個參數url。在平常開發中,咱們能用的只有url和data這兩個參數。 url參數:指定向哪一個url發起請求 data參數:能夠將post請求中攜帶的參數封裝成字典的形式傳遞給該參數(暫時不須要理解,後期會講) urlopen函數返回的響應對象,相關函數調用介紹: response.headers():獲取響應頭信息 response.getcode():獲取響應狀態碼 response.geturl():獲取請求的url response.read():獲取響應中的數據值(字節類型)
2.二進制數據的爬取:爬取網絡上的某張圖片數據,且存儲到磁盤服務器
方法 1:cookie
import urllib.request import urllib.parse #1.指定url url = 'https://pic.qiushibaike.com/system/pictures/12112/121121212/medium/ZOAND29U4NKNEWEF.jpg' #2.發起請求:使用urlopen函數發起請求,該函數返回一個響應對象 response = urllib.request.urlopen(url=url) #3.獲取響應對象中的圖片二進制類型的數據 img_data = response.read() #4.持久化存儲:將爬取的圖片寫入本地進行保存 with open('./tupian.png','wb') as fp: fp.write(img_data)
方法 2:網絡
import urllib.request import urllib.parse url = 'https://pic.qiushibaike.com/system/pictures/12112/121121212/medium/ZOAND29U4NKNEWEF.jpg' # 函數原型:urllib.request.urlretrieve(url, filename=None) # 做用:對url發起請求,且將響應中的數據值寫入磁盤進行存儲 urllib.request.urlretrieve(url=url,filename='./img.png')
3.url的特性:url必須爲ASCII編碼的數據值。因此咱們在爬蟲代碼中編寫url時,若是url中存在非ASCII編碼的數據值,則必須對其進行ASCII編碼後,該url方可被使用。負載均衡
案例:爬取使用搜狗根據指定詞條搜索到的頁面數據(例如爬取詞條爲‘周杰倫’的頁面數據)dom
import urllib.request import urllib.parse url = 'https://www.sogou.com/web?query=周杰倫' response = urllib.request.urlopen(url=url) data = response.read() with open('./周杰倫.html','wb') as fp: fp.write(data) print('寫入文件完畢')
【注意】上述代碼中url存在非ascii編碼的數據,則該url無效。若是對其發起請求,則會報以下錯誤:函數
UnicodeEncodeError: 'ascii' codec can't encode characters in position 15-17: ordinal not in range
因此必須對url中的非ascii的數據進行ascii的編碼,則該url方可被髮起請求:
方法 1:使用quote函數
import urllib.request import urllib.parse url = 'https://www.sogou.com/web?query=%s' #對url中的非ascii進行編碼.quote函數能夠對非ascii的數據值進行ascii的編碼 word = urllib.parse.quote('周杰倫') #將編碼後的數據值拼接回url中 url = format(url%word) response = urllib.request.urlopen(url=url) data = response.read() with open('./周杰倫.html','wb') as fp: fp.write(data) print('寫入文件完畢')
方法2: 使用urlencode函數
import urllib.request import urllib.parse url = 'https://www.sogou.com/web?' #將get請求中url攜帶的參數封裝至字典中 param = { 'query':'周杰倫' } #對url中的非ascii進行編碼 param = urllib.parse.urlencode(param) #將編碼後的數據值拼接回url中 url += param response = urllib.request.urlopen(url=url) data = response.read() with open('./周杰倫1.html','wb') as fp: fp.write(data) print('寫入文件完畢')
4.經過自定義請求對象,用於假裝爬蟲程序請求的身份。
以前在講解http經常使用請求頭信息時,咱們講解過User-Agent參數,簡稱爲UA,該參數的做用是用於代表本次請求載體的身份標識。若是咱們經過瀏覽器發起的請求,則該請求的載體爲當前瀏覽器,則UA參數的值代表的是當前瀏覽器的身份標識表示的一串數據。若是咱們使用爬蟲程序發起的一個請求,則該請求的載體爲爬蟲程序,那麼該請求的UA爲爬蟲程序的身份標識表示的一串數據。有些網站會經過辨別請求的UA來判別該請求的載體是否爲爬蟲程序,若是爲爬蟲程序,則不會給該請求返回響應,那麼咱們的爬蟲程序則也沒法經過請求爬取到該網站中的數據值,這也是反爬蟲的一種初級技術手段。那麼爲了防止該問題的出現,則咱們能夠給爬蟲程序的UA進行假裝,假裝成某款瀏覽器的身份標識。
上述案例中,咱們是經過request模塊中的urlopen發起的請求,該請求對象爲urllib中內置的默認請求對象,咱們沒法對其進行UA進行更改操做。urllib還爲咱們提供了一種自定義請求對象的方式,咱們能夠經過自定義請求對象的方式,給該請求對象中的UA進行假裝(更改)操做。
import urllib.request import urllib.parse url = 'https://www.sogou.com/web?' #將get請求中url攜帶的參數封裝至字典中 param = { 'query':'周杰倫' } #對url中的非ascii進行編碼 param = urllib.parse.urlencode(param) #將編碼後的數據值拼接回url中 url += param #封裝自定義的請求頭信息的字典: #將瀏覽器的UA數據獲取,封裝到一個字典中。該UA值能夠經過抓包工具或者瀏覽器自帶的開發者工具中獲取某請求,從中獲取UA的值 #注意:在headers字典中能夠封裝任意的請求頭信息 headers={ 'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36' } #自定義請求對象,能夠在該請求對象中添加自定義的請求頭信息 request = urllib.request.Request(url=url,headers=headers) #使用自定義請求對象發起請求 response = urllib.request.urlopen(request) data = response.read() with open('./周杰倫.html','wb') as fp: fp.write(data) print('寫入文件完畢')
5.攜帶參數的post請求:
案例:百度翻譯發起post請求
import urllib.request import urllib.parse #經過抓包工具抓取post請求的url post_url='https://fanyi.baidu.com/sug' #封裝post請求參數 data={ "kw":"dog" } data=urllib.parse.urlencode(data) #自定義請求頭信息字典 headers={ "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36" } #自定義請求對象,而後將封裝好的post請求參數賦值給Requst方法的data參數。 #data參數:用來存儲post請求的參數 request=urllib.request.Request(post_url,data=data.encode(),headers=headers) #自定義的請求對象中的參數(data必須爲bytes類型) response=urllib.request.urlopen(request) response.read()
- 什麼是代理:代理就是第三方代替本體處理相關事務。例如:生活中的代理:代購,中介,微商......
- 爬蟲中爲何須要使用代理?
一些網站會有相應的反爬蟲措施,例如不少網站會檢測某一段時間某個IP的訪問次數,若是訪問頻率太快以致於看起來不像正常訪客,它可能就會會禁止這個IP的訪問。因此咱們須要設置一些代理IP,每隔一段時間換一個代理IP,就算IP被禁止,依然能夠換個IP繼續爬取。
- 代理的分類:
正向代理:代理客戶端獲取數據。正向代理是爲了保護客戶端防止被追究責任。
反向代理:代理服務器提供數據。反向代理是爲了保護服務器或負責負載均衡。
import urllib.request import urllib.parse #1.建立處理器對象,在其內部封裝代理ip和端口 handler=urllib.request.ProxyHandler(proxies={'http':'95.172.58.224:52608'}) #2.建立opener對象,而後使用該對象發起一個請求 opener=urllib.request.build_opener(handler) url='http://www.baidu.com/s?ie=UTF-8&wd=ip' headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36', } request = urllib.request.Request(url, headers=headers) #使用opener對象發起請求,該請求對應的ip即爲咱們設置的代理ip response = opener.open(request) with open('./daili.html','wb') as fp: fp.write(response.read())
引言:有些時候,咱們在使用爬蟲程序去爬取一些用戶相關信息的數據(爬取張三「人人網」我的主頁數據)時,若是使用以前requests模塊常規操做時,每每達不到咱們想要的目的,例如:
import urllib.request import urllib.parse #指定url url = 'http://www.renren.com/289676607/profile' #自定義請求頭信息 headers={ 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36', } #自定義請求對象 request = urllib.request.Request(url=url,headers=headers) #發起請求 response = urllib.request.urlopen(request) with open('./renren.html','w') as fp: fp.write(response.read().decode())
【注意】上述代碼中,咱們爬取到的是登陸首頁面,而不是張三的我的主頁也面。why?首先咱們來回顧下cookie的相關概念及做用
- cookie概念:當用戶經過瀏覽器首次訪問一個域名時,訪問的web服務器會給客戶端發送數據,以保持web服務器與客戶端之間的狀態保持,這些數據就是cookie。
- cookie做用:咱們在瀏覽器中,常常涉及到數據的交換,好比你登陸郵箱,登陸一個頁面。咱們常常會在此時設置30天內記住我,或者自動登陸選項。那麼它們是怎麼記錄信息的呢,答案就是今天的主角cookie了,Cookie是由HTTP服務器設置的,保存在瀏覽器中,但HTTP協議是一種無狀態協議,在數據交換完畢後,服務器端和客戶端的連接就會關閉,每次交換數據都須要創建新的連接。就像咱們去超市買東西,沒有積分卡的狀況下,咱們買完東西以後,超市沒有咱們的任何消費信息,但咱們辦了積分卡以後,超市就有了咱們的消費信息。cookie就像是積分卡,能夠保存積分,商品就是咱們的信息,超市的系統就像服務器後臺,http協議就是交易的過程。
- 通過cookie的相關介紹,其實你已經知道了爲何上述案例中爬取到的不是張三我的信息頁,而是登陸頁面。那應該如何抓取到張三的我的信息頁呢?
思路:
1.咱們須要使用爬蟲程序對人人網的登陸時的請求進行一次抓取,獲取請求中的cookie數據
2.在使用我的信息頁的url進行請求時,該請求須要攜帶 1 中的cookie,只有攜帶了cookie後,服務器纔可識別此次請求的用戶信息,方可響應回指定的用戶信息頁數據
cookiejar對象: - 做用:自動保存請求中的cookie數據信息 - 注意:必須和handler和opener一塊兒使用 cookiejar使用流程: - 建立一個cookiejar對象 import http.cookiejar cj = http.cookiejar.CookieJar() - 經過cookiejar建立一個handler handler = urllib.request.HTTPCookieProcessor(cj) - 根據handler建立一個opener opener = urllib.request.build_opener(handler) - 使用opener.open方法去發送請求,且將響應中的cookie存儲到openner對象中,後續的請求若是使用openner發起,則請求中就會攜帶了cookie
使用cookiejar實現爬取人人網我的主頁頁面數據:
#使用cookiejar實現人人網的登錄 import urllib.request import urllib.parse import http.cookiejar cj = http.cookiejar.CookieJar() #請求中的cookie會自動存儲到cj對象中 #建立處理器對象(攜帶cookiejar對象的) handler=urllib.request.HTTPCookieProcessor(cj) #建立opener對象 (攜帶cookiejar對象) opener=urllib.request.build_opener(handler) #要讓cookiejar獲取請求中的cookie數據值 url='http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=201873958471' #自定義一個請求對象,讓該對象做爲opener的open函數中的參數 data={ "email":"www.zhangbowudi@qq.com", "icode":"", "origURL":"http://www.renren.com/home", "domain":"renren.com", "key_id":"1", "captcha_type":"web_login", "password":"40dc65b82edd06d064b54a0fc6d202d8a58c4cb3d2942062f0f7dd128511fb9b", "rkey":"41b44b0d062d3ca23119bc8b58983104", 'f':"https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DpPKf2680yRLbbZMVdntJpyPGwrSk2BtpKlEaAuKFTsW%26wd%3D%26eqid%3Deee20f380002988c000000025b7cbb80" } data=urllib.parse.urlencode(data).encode() request=urllib.request.Request(url,data=data) opener.open(request) #獲取當前用戶的二級子頁面 s_url='http://www.renren.com/289676607/profile' #該次請求中就攜帶了cookie resonse=opener.open(s_url) with open('./renren.html','wb') as fp: fp.write(resonse.read())