网络请求urllib库使用总结
網絡請求urllib庫使用總結
目錄
- 網絡請求urllib庫使用總結
- 1.概述
- 2.Urllib庫基本使用
- 2.1.Urllib庫快速上手
- 1.完成一次簡單的get請求
- 2.read()函數介紹
- 3.獲取其他響應信息
- 2.2.urlretrieve()函數下載數據
- 1.urlretrieve()函數基本使用
- 2.3.構建請求對象
- 1.請求一個https網站
- 2.攻破UA反爬策略
- 2.4.字符編碼集轉換
- 1.發送中文參數請求例子
- 2.字符編碼表介紹
- 3.字符編碼表轉換
- 2.5.發送post請求
- 2.6.Handler處理器定制動態參數請求頭
- 1.Handler基本使用
- 2.Handler實現代理訪問
- 3.代理池
1.概述
Urllib庫是python自帶的發送網絡請求庫,可以滿足日常接口請求接收響應數據任務,在實際場景中發揮出它的價值還需要對這個庫做一些了解,才能熟練使用它完成我們的需求,關于urllib庫的使用都在這篇文章中進行總結。
2.Urllib庫基本使用
2.1.Urllib庫快速上手
1.完成一次簡單的get請求
通過發送一個get請求,獲取響應內容的示例快速掌握urllib庫使用
import urllib.request# 定義訪問的url地址 url = 'http://www.baidu.com'# 模擬瀏覽器向服務器發送請求,獲取響應response ''' urlopen 返回類型是 http.client.HTTPResponse 類對象 ''' response = urllib.request.urlopen(url)# 獲取響應中頁面的源碼 content = response.read() print(content)運行get請求查看返回結果
b'<!DOCTYPE html><!--STATUS OK--><html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta content="always" name="referrer"><meta name="theme-color" content="#ffffff"><meta name="description" content="\xe5\x85\xa8\xe7\x90\x83\xe9\xa2\x86\xe5\x85\x88\xe7\x9a\x84\xe4\xb8\xad\xe6\x96\x87\xe6\x90\x9c\xe7\xb4\xa2\xe5\xbc\x95\xe6\x93\x8e\xe3\x80\x81\xe8\x87\xb4\xe5\x8a\x9b\xe4\xba\x8e\xe8\xae\xa9\xe7\xbd\x91\xe6\xb0\x91\xe6\x9b\xb4\xe4\xbe\xbf\xe6\x8d\xb7\xe5\x9c\xb0\xe8\x8e\xb7\xe5\x8f\x96\xe4\xbf\xa1\xe6\x81\xaf\xef\xbc\x8c\xe6\x89\xbe\xe5\x88\xb0\xe6\x89\x80\xe6\xb1\x82\xe3\x80\x82\xe7\x99\xbe\xe5\xba\xa6\xe8\xb6\x85\xe8\xbf\x87\xe5\x8d\x83\xe4\xba\xbf\xe7\x9a\x84\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x91\xe9\xa1\xb5\xe6\x95\xb0\xe6\x8d\xae\xe5\xba\x93\xef\xbc\x8c\xe5\x8f\xaf\xe4\xbb\xa5\xe7\x9e\xac\xe9\x97\xb4\xe6\x89\xbe\xe5\x88\xb0\xe7\x9b\xb8\xe5\x85\xb3\xe7\x9a\x84\xe6\x90\x9c\xe7\xb4\xa2\xe7\xbb\x93\xe6\x9e\x9c\xe3\x80\x82"><link rel="shortcut icon" href="/favicon.ico" ...省略后面的內容 ...查看返回的數據發現開頭有個b字母,這個代表當前數據是二進制的字節碼,是將字符串編譯后給機器看的,中文顯示格式為\xe5\x85。
這是因為read()函數返回的數據就是一個字節碼,需要解碼轉為字符串后才會顯示中文。可以使用decode()函數解碼,解碼時輸入它的字符編碼要和返回信息的編碼一致中文才不會顯示亂碼。
如何知道使用什么編碼那,在返回數據的請求頭都會顯示它的編碼字符集,例如上面返回結果數據的第一行charset=utf-8 就是他的字符集,使用它來解碼。
# 獲取響應中頁面的源碼 ''' read()返回的信息是字節碼,通過decode()函數將字節碼轉為字符串 ''' content = response.read().decode('utf-8')查看字節碼解碼為字符串運行結果
<!DOCTYPE html><!--STATUS OK--><html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta content="always" name="referrer"><meta name="theme-color" content="#ffffff"><meta name="description" content="全球領先的中文搜索引擎、致力于讓網民更便捷地獲取信息,找到所求。百度超過千億的中文網頁數據庫,可以瞬間找到相關的搜索結果。"><link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" /><link rel="search" type="application/opensearchdescription+xml" href="/content-search.xml" title="百度搜索" />請求返回的數據中開頭的b已經不在了,說明現在是字符串類型,再看中文已經正確顯示。現在使用urllib庫完成了get請求。
2.read()函數介紹
上面的示例中已經使用read函數獲取了響應數據,下面介紹下read函數的其他使用方式。
# read函數默認是按照一個字節一個字節讀取數據 content = response.read().decode('utf-8') print(content)# 獲取指定長度的字節 content = response.read(5) print(content) # 結果輸出5個字節 b'<!DOC'# 讀取一行數據 content = response.readline() print(content)# 讀取多行數據 content = response.readlines() print(content)3.獲取其他響應信息
# 返回狀態碼 print(response.getcode()) # 返回url地址 print(response.geturl())# 獲取header頭 print(response.getheaders())2.2.urlretrieve()函數下載數據
如果我們需要將返回數據中的文件、圖片、視頻等下載到本地,使用urlretrieve()函數可以下載我們需要的內容。
1.urlretrieve()函數基本使用
# 下載圖片 url_img = 'http://pic3.zhimg.com/v2-a08aad3a5f85058844f4237919449ee4_r.jpg?source=172ae18b' # url:下載文件路徑 filename:保存文件的名稱 urllib.request.urlretrieve(url=url_img, filename='cat.jpg')# 下載視頻 url_video = 'https://tv.sohu.com/v/dXMvMTY0NzEzNTc3LzU2NzEwOTQ5LnNodG1s.mp4' urllib.request.urlretrieve(url=url_video, filename='xz.mp4')2.3.構建請求對象
為什么要構建請求對象那?
當我們發送請求爬取數據的時候相對的就會有反爬蟲策略防止網站數據被爬取。當我們遇到反爬策略時還想爬取到數據就需要根據反爬策略做出應對的辦法,構建請求對象就是一種應對反爬策略的辦法。下面通過一個例子感受下通過構建請求對象如何攻破反爬策略。
1.請求一個https網站
下面是一個訪問百度網站請求,但是這次訪問地址協議由http改為了https協議,我們看下會發生什么。
import ssl import urllib.request# Mac系統會校驗ssl證書,通過全局取消ssl證書驗證避免報錯 ssl._create_default_https_context = ssl._create_unverified_contexturl = 'https://www.baidu.com' response = urllib.request.urlopen(url) content = response.read().decode('utf-8') print(content)運行示例查看結果
<html> <head><script>location.replace(location.href.replace("https://","http://"));</script> </head> <body><noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript> </body> </html>查看結果返現訪問百度沒有返回正確的信息,這個就是百度的反爬策略,下面來詳細介紹下這個策略以及如何攻破這個策略拿到數據。
2.攻破UA反爬策略
在介紹UA策略前先普及下url的組成,它有6個部分組成。
https://www.baidu.com/s?wd=周杰倫
- 協議:http/https
- 主機地址:www.baidu.com
- 端口號:http默認80 / https默認443
- 路徑:端口號后面的 s
- 參數: 問號后面 wd=周杰倫
- 錨點:#
當我們使用https協議訪問百度時,它會檢測請求端的UA是否包含正常瀏覽器發起請求信息,如果不包含則認為是爬蟲就會拒絕訪問。
那么什么是UA那,我們要怎么構建一個合格的UA突破反爬那,下面介紹將解決這些疑問。
什么是UA
UA是User Agent中文名為用戶代碼,簡稱UA。 他是一個特殊的字符串,向服務器提交當前客戶端使用的操作系統及版本、CPU類型、瀏覽器內核及版本號等。
查看當前瀏覽器的UA
在瀏覽器上右鍵打開檢查功點擊點擊網絡標簽,然后訪問一個網站,在標頭的最下面就可以看到UA信息。
構建請求頭攜帶UA請求網站
當我們找到了瀏覽器的UA信息后就可以用它來構建我們的請求對象,讓它帶著UA信息再次訪問網站。
運行示例查看結果
<!DOCTYPE html><!--STATUS OK--><html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta content="always" name="referrer"><meta name="theme-color" content="#ffffff"> <meta name="description" content="全球領先的中文搜索引擎、致力于讓網民更便捷地獲取信息,找到所求。百度超過千億的中文網頁數據庫,可以瞬間找到相關的搜索結果。">... ...在運行結果中可以看到我們攻破了UA反爬策略拿到了百度的數據。
2.4.字符編碼集轉換
當我們使用urllib庫發送網絡請求,主要包含兩個內容請求數據和響應數據。這兩個數據的中文如果希望服務器能正確處理,不出現亂碼那么就會與字符編碼表打交道,下面就來介紹下如何使用字符編碼表處理中文。
下面通過一個例子介紹如何使用編碼表處理請求中的中文。
1.發送中文參數請求例子
首先使用瀏覽器打開百度搜下字符編碼,點擊搜索。在瀏覽器的地址欄就能看到搜索的內容,將它復制到pycharm編輯器中。
當我們復制到編輯器后發現中文變成了亂碼,然后我們將亂碼部分改為我們要搜索的中文。
# 復制后的url https://cn.bing.com/search?q=%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81 # 修改后的url https://www.baidu.com/s?wd=字符編碼使用修改后的url發送請求代碼,看看是否能通過。
url = 'https://cn.bing.com/search?q=字符編碼' # 將UA信息放到headers字典中 headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.8' } # 構建請求對象 request = urllib.request.Request(url=url, headers=headers) response = urllib.request.urlopen(request) content = response.read().decode('utf-8') print(content)運行示例查看結果
UnicodeEncodeError: 'ascii' codec can't encode characters in position 14-17: ordinal not in range(128)運行結果提示不能解析characters,它不在ascii 編碼表 range(128)范圍之內。
2.字符編碼表介紹
上面的例子運行結果拋出的異常中告訴我們中文不在ascii編碼表范圍之內,這個異常是什么意思那?下面先普及下字符編碼表再來揭曉答案。
由于計算機早起是在美國誕生的,因此只有127個字符被編碼到計算機中。這個編碼就被定義為ASCII編碼表,在表中只有大小寫字母,數字和一些符號。
隨著計算機的普及,只有127個字符的編碼表已經不能滿足各個國家的需求,因此每個國家都制定了自己語言的編碼表,中國制定了GB2312,但是因為各個編碼表不通用,因此Unicode應用而生,它把所有語言都統一到一套編碼表里,這樣就不會再出現亂碼了。
UTF,是UnicodeTransformation Format的縮寫,意為Unicode轉換格式。UTF-8是UNICODE的一種變長字符編碼,由Ken Thompson于1992年創建。現在已經標準化為RFC 3629。UTF-8用1到6個字節編碼UNICODE字符。
了解了字符編碼表后上面遇到的異常就能解釋了,當我們將瀏覽器中含有中文的url復制到pycharm工具中編程了亂碼,這是因為在瀏覽器中網頁使用的是utf-8編碼表,而pycharm使用ASCII編碼表來解碼遇到中文自然就會出現亂碼。
當我們將URL亂碼改為中文發送請求那么ASCII編碼表因為不能在127個編碼中對中文解碼因此拋出了異常。
3.字符編碼表轉換
現在知道了請求異常的原因后,我們可以通過編碼表對中文進行轉碼,再發送請求解決我們的問題。
將中文轉為ASCII編碼
urllib庫為我們提供了編碼的函數,通過urllib.parse.quote()函數將中文編碼為ASCII編碼字符,下面是將中文轉碼的例子。
# 通過urllib.parse.quote()函數將中文編碼為ASCII編碼字符 name = urllib.parse.quote('字符編碼') print(name)# 運行結果 %E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81# 將輸出的結果和復制過來的url編碼對比他們是一致的。 url = 'https://cn.bing.com/search?q=%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81'使用轉碼后的字符發送請求,看看運行結果。
import ssl import urllib.request # 全局取消ssl證書驗證 ssl._create_default_https_context = ssl._create_unverified_contexturl = 'https://cn.bing.com/search?q=' name = urllib.parse.quote('字符編碼') url = url + name# 將UA信息放到headers字典中 headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.8' } # 構建請求對象 request = urllib.request.Request(url=url, headers=headers) response = urllib.request.urlopen(request) content = response.read().decode('utf-8') print(content)運行示例,查看返回結果返回了請求信息。
<!DOCTYPE html><html dir="ltr" lang="zh" xml:lang="zh" xmlns="http://www.w3.org/1999/xhtml" xmlns:Web="http://schemas.live.com/Web/"><script type="text/javascript" nonce="VnKdTkMMGjdfKEp3CTC1udDuwBYGrOuXYMoe4JWtpDc=" >//<![CDATA[ si_ST=new Date如果一個請求連接中有個多個參數且為中文,那么我們是不是要將所有中文參數都轉換一遍那,如果好幾十個都需要調用下urllib.parse.quote()函數轉換,再拼接url是不是很麻煩。下面我們就來介紹一個新的解決中文參數方法。
批量轉換Unicoe碼
urlencode()函數接收一個字典對象,將需要轉碼的中文參數放到字典中,然后批量轉換字符編碼。
從運行的結果中可以看出它將多個中文參數轉為Unicode碼,同時將多個參數使用&符號拼接
下面使用這個函數發送請求批量轉換多個中文參數
# !/usr/bin/env python3 # -*-coding: UTF-8 -*- ''' @Author :Long @Date :2022/10/21 11:14 ''' import ssl import urllib.request import urllib.parse# 全局取消ssl證書驗證 ssl._create_default_https_context = ssl._create_unverified_context #url地址 url = 'http://www.baidu.com/s?' data = {'wd': '周杰倫','sex': '男','location': '中國臺灣省' }# url參數中文轉為unicode字符編碼 param = urllib.parse.urlencode(data) # 拼接URL url = url +param # 將UA信息放到headers字典中 headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.8' } # 構建請求對象 request = urllib.request.Request(url=url, headers=headers) response = urllib.request.urlopen(request) content = response.read().decode('utf-8') print(content)2.5.發送post請求
post請求和get請求最大的區別就是參數部分,post請求的參數不在url后面拼接,而是放在body中。
下面通過一個例子展示使用urllib庫發送post請求。
urllib發送post請求的例子寫好了,下面運行看看結果。
{"errno":0,"data":[{"k":"spider","v":"n. \u8718\u86db; \u661f\u5f62\u8f6e\uff0c\u5341\u5b57\u53c9; \u5e26\u67c4\u4e09\u811a\u5e73\u5e95\u9505; \u4e09\u811a\u67b6"},{"k":"Spider","v":"[\u7535\u5f71]\u8718\u86db"},{"k":"SPIDER","v":"abbr. SEMATECH process induced damage effect revea"},{"k":"spiders","v":"n. \u8718\u86db( spider\u7684\u540d\u8bcd\u590d\u6570 )"},{"k":"spidery","v":"adj. \u50cf\u8718\u86db\u817f\u4e00\u822c\u7ec6\u957f\u7684; \u8c61\u8718\u86db\u7f51\u7684\uff0c\u5341\u5206\u7cbe\u81f4\u7684"}]}運行結果顯示post請求成功返回數據,但是發現中文不能正確顯示都是\u5e26格式。觀察下這個返回內容是不是一個json格式,那么在打印下他的格式。
# 打印類型 print(type(content)) # 結果 <class 'str'>輸出結果顯示內容是str字符串類型,那么我們將它轉為json格式
# str 轉 json content_json = json.loads(content) print(content_json)運行代碼查看結果
{'errno': 0, 'data': [{'k': 'spider', 'v': 'n. 蜘蛛; 星形輪,十字叉; 帶柄三腳平底鍋; 三腳架'}, {'k': 'Spider', 'v': '[電影]蜘蛛'}, {'k': 'SPIDER', 'v': 'abbr. SEMATECH process induced damage effect revea'}, {'k': 'spiders', 'v': 'n. 蜘蛛( spider的名詞復數 )'}, {'k': 'spidery', 'v': 'adj. 像蜘蛛腿一般細長的; 象蜘蛛網的,十分精致的'}]}2.6.Handler處理器定制動態參數請求頭
在上面的學習中為了攻破UA反爬機制,我們使用urllib.request.Request()定制請求信息完成請求。這些定制的參數都是固定不變的,當發送請求遇到動態參數例如token、cookie每次請求都會變化的數據就不能用這種方式定制請求。
因此我們需要用Handler處理器定制動態參數請求頭
1.Handler基本使用
下面通過一個簡單示例,完成一個post請求了解下handler基本使用。
import urllib.request import ssl # 全局取消ssl證書驗證 ssl._create_default_https_context = ssl._create_unverified_contexturl = 'https://fanyi.baidu.com'headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.8' }request = urllib.request.Request(url=url, headers=headers)# 構建handler對象 (handler、build.opener、open)# 獲取handler對象 handler = urllib.request.HTTPHandler() # 獲取opener對象 opener = urllib.request.build_opener(handler) # 獲取open方法,發送請求 response = opener.open(request) #讀取響應數據 content = response.read().decode('utf-8') print(content)2.Handler實現代理訪問
在爬蟲過程中可能會遇到IP封鎖這也是一個反爬蟲策略,當檢測到同一個IP在短時間內重復方法網站時就可以對這個IP封鎖,禁止它訪問,以此來達到防止爬蟲作用。下面將通過Handler實現代理方式攻破這個反爬蟲策略。
import urllib.request import ssl# 全局取消ssl證書驗證 ssl._create_default_https_context = ssl._create_unverified_contexturl = 'https://www.baidu.com/s?wd=ip'headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.8' }request = urllib.request.Request(url=url, headers=headers)# 設置代理訪問地址 proxies = {'http':'223.96.90.216:8085' } # 創建代理處理器 handler = urllib.request.ProxyHandler(proxies=proxies) # 獲取opener對象 opener = urllib.request.build_opener(handler) # 通過代理地址發送請求 response = opener.open(request) response = urllib.request.urlopen(request) content = response.read().decode('utf-8')with open('dali.html', 'w', encoding='utf-8') as fp:fp.write(content)3.代理池
當我們使用一個代理IP地址訪問同一個網站,數次請求后也會被封,所以我們需要使用許多的代理IP訪問,這個就是代理池。
import urllib.request import ssl# 全局取消ssl證書驗證 ssl._create_default_https_context = ssl._create_unverified_contexturl = 'https://www.baidu.com/s?wd=ip'headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.8' }request = urllib.request.Request(url=url, headers=headers)proxies_pool = [{'http':'223.96.90.216:8085'},{'http':'223.96.90.216:8085'} ]# 隨機選擇代理池中的IP import random proxies = random.choice(proxies_pool) handler = urllib.request.ProxyHandler(proxies=proxies) # 獲取opener對象 opener = urllib.request.build_opener(handler) # 獲取open方法 response = opener.open(request) response = urllib.request.urlopen(request) content = response.read().decode('utf-8')with open('dali.html', 'w', encoding='utf-8') as fp:fp.write(content)總結
以上是生活随笔為你收集整理的网络请求urllib库使用总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 水平集(Level Set)的基本方法
- 下一篇: 计算机网络与多媒体试卷,《计算机网络与多