Python之urllib庫詳解


urllib 是 Python 標准庫中用於網絡請求的庫。

該庫有四個模塊,分別是:

urllib.request

urllib.error

urllib.parse

urllib.robotparser

1 發起請求

模擬瀏覽器發起一個 HTTP 請求,我們需要用到 urllib.request 模塊。urllib.request 的作用不僅僅是發起請求, 還能獲取請求返回結果。發起請求,單靠 urlopen() 方法就可以叱吒風雲。我們先看下 urlopen() 的 API:

urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None,context=None)
  • data 是 bytes 類型的內容,可通過 bytes()函數轉為化字節流。它也是可選參數。使用 data 參數,請求方式變成以 POST 方式提交表單。使用標准格式是application/x-www-form-urlencoded
  • timeout 參數是用於設置請求超時時間。單位是秒。
  • cafilecapath代表 CA 證書和 CA 證書的路徑。如果使用HTTPS則需要用到。
  • context參數必須是ssl.SSLContext類型,用來指定SSL設置
  • 該方法也可以單獨傳入urllib.request.Request對象
  • 該函數返回結果是一個http.client.HTTPResponse對象。
使用 urllib.request.urlopen() 去請求百度貼吧,並獲取到它頁面的源代碼。
import urllib.request

url = "http://tieba.baidu.com"
response = urllib.request.urlopen(url)
html = response.read()         # 獲取到頁面的源代碼
print(html.decode('utf-8'))    # 轉化為 utf-8 編碼

1.2 設置請求超時

有些請求可能因為網絡原因無法得到響應。因此,我們可以手動設置超時時間。當請求超時,我們可以采取進一步措施,例如選擇直接丟棄該請求或者再請求一次。

import urllib.request

url = "http://tieba.baidu.com"
response = urllib.request.urlopen(url, timeout=1)
print(response.read().decode('utf-8'))

1.3 使用 data 參數提交數據

在請求某些網頁時需要攜帶一些數據,我們就需要使用到 data 參數。

import urllib.parse
import urllib.request

url = "http://www.baidu.com/"
params = {
  'name':'TTT',
  'author':'Miracle'
}

data = bytes(urllib.parse.urlencode(params), encoding='utf8')
response = urllib.request.urlopen(url, data=data)
print(response.read().decode('utf-8'))

params 需要被轉碼成字節流。而 params 是一個字典。我們需要使用 urllib.parse.urlencode() 將字典轉化為字符串。再使用 bytes() 轉為字節流。最后使用 urlopen() 發起請求,請求是模擬用 POST 方式提交表單數據。

注意:當url地址含有中文或者“/”的時候,這是就需要用做urlencode一下編碼轉換。urlencode的參數是詞典,它可以將key-value這樣的鍵值對轉換成我們想要的格式

1.4 使用 Request

由上我們知道利用 urlopen() 方法可以發起簡單的請求。但這幾個簡單的參數並不足以構建一個完整的請求,如果請求中需要加入headers(請求頭)、指定請求方式等信息,我們就可以利用更強大的Request類來構建一個請求。
按照國際慣例,先看下 Request 的構造方法:

urllib.request.Request(url, data=None, headers={}, origin_req_host=None,
unverifiable=False, method=None)
  • data 參數跟 urlopen() 中的 data 參數用法相同。
  • headers 參數是指定發起的 HTTP 請求的頭部信息。headers 是一個字典。它除了在 Request 中添加,還可以通過調用 Reques t實例的 add_header() 方法來添加請求頭。
  • origin_req_host 參數指的是請求方的 host 名稱或者 IP 地址。
  • unverifiable 表示請求是否是無法驗證的,默認False。意思就是說用戶沒有足夠權限來選擇接收這個請求的結果。例如我們請求一個HTML文檔中的圖片,但是我們沒有自動抓取圖像的權限,我們就要將 unverifiable 的值設置成 True。
  • method 參數指的是發起的 HTTP 請求的方式,有 GET、POST、DELETE、PUT等
1.4.1 簡單使用 Request

使用 Request 偽裝成瀏覽器發起 HTTP 請求。如果不設置 headers 中的 User-Agent,默認的User-AgentPython-urllib/3.5。可能一些網站會將該請求攔截,所以需要偽裝成瀏覽器發起請求。我使用的 User-Agent 是 Chrome 瀏覽器。

#修改User-Agent為chrome的UA進行偽裝
import urllib.request

url = "http://tieba.baidu.com/"
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'
}
request = urllib.request.Request(url=url, headers=headers)
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))

1.4.2 Request 高級用法

如果我們需要在請求中添加代理、處理請求的 Cookies,我們需要用到HandlerOpenerDirector

1) Handler
Handler 的中文是處理者、處理器。 Handler 能處理請求(HTTP、HTTPS、FTP等)中的各種事情。它的具體實現是這個類 urllib.request.BaseHandler。它是所有的 Handler 的基類,其提供了最基本的Handler的方法,例如default_open()、protocol_request()等。
繼承 BaseHandler 有很多個,我就列舉幾個比較常見的類:

  • ProxyHandler:為請求設置代理
  • HTTPCookieProcessor:處理 HTTP 請求中的 Cookies
  • HTTPDefaultErrorHandler:處理 HTTP 響應錯誤。
  • HTTPRedirectHandler:處理 HTTP 重定向。
  • HTTPPasswordMgr:用於管理密碼,它維護了用戶名密碼的表。
  • HTTPBasicAuthHandler:用於登錄認證,一般和 HTTPPasswordMgr 結合使用。
2) OpenerDirector
對於 OpenerDirector,我們可以稱之為 Opener。我們之前用過 urlopen() 方法,實際上它就是 urllib 為我們提供的一個Opener。那 Opener 和 Handler 又有什么關系?opener 對象是由 build_opener(handler) 方法來創建出來 。我們需要創建自定義的 opener,就需要使用 install_opener(opener)方法。值得注意的是,install_opener 實例化會得到一個全局的 OpenerDirector 對象。

1.5 使用代理

我們已經了解了 opener 和 handler,接下來我們就通過示例來深入學習。第一個例子是為 HTTP 請求設置代理
有些網站做了瀏覽頻率限制。如果我們請求該網站頻率過高。該網站會被封 IP,禁止我們的訪問。所以我們需要使用代理來突破這“枷鎖”。

import urllib.request

url = "http://tieba.baidu.com/"
headers = {
    'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 Chrome/56.0.2924.87 Safari/537.36'
}

proxy_handler = urllib.request.ProxyHandler({
    'http': 'web-proxy.oa.com:8080',
    'https': 'web-proxy.oa.com:8080'
})
opener = urllib.request.build_opener(proxy_handler)
urllib.request.install_opener(opener)

request = urllib.request.Request(url=url, headers=headers)
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))        
1.6 認證登錄

有些網站需要攜帶賬號和密碼進行登錄之后才能繼續瀏覽網頁。碰到這樣的網站,我們需要用到認證登錄。我們首先需要使用 HTTPPasswordMgrWithDefaultRealm() 實例化一個賬號密碼管理對象;然后使用 add_password() 函數添加賬號和密碼;接着使用 HTTPBasicAuthHandler() 得到 hander;再使用 build_opener() 獲取 opener 對象;最后使用 opener 的 open() 函數發起請求。

第二個例子是攜帶賬號和密碼請求登錄博客園,代碼如下:

import urllib.request
url = "http://cnblogs.com/xtznb/"
user = '奇跡'
password = 'password'
pwdmgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
pwdmgr.add_password(None,url,user,password)

auth_handler = urllib.request.HTTPBasicAuthHandler(pwdmgr)
opener = urllib.request.build_opener(auth_handler)
response = opener.open(url)
print(response.read().decode('utf-8'))
1.7 Cookies設置

如果請求的頁面每次需要身份驗證,我們可以使用 Cookies 來自動登錄,免去重復登錄驗證的操作。獲取 Cookies 需要使用 http.cookiejar.CookieJar() 實例化一個 Cookies 對象。再用 urllib.request.HTTPCookieProcessor 構建出 handler 對象。最后使用 opener 的 open() 函數即可。

第三個例子是獲取請求百度貼吧的 Cookies 並保存到文件中,代碼如下:

import http.cookiejar
import urllib.request

url = "http://tieba.baidu.com/"
fileName = 'cookie.txt'

cookie = http.cookiejar.CookieJar()
handler = urllib.request.HTTPCookieProcessor(cookie)
opener = urllib.request.build_opener(handler)
response = opener.open(url)

f = open(fileName,'a')
for item in cookie:
    f.write(item.name+" = "+item.value+'\n')
f.close()

1.8 HTTPResponse

從上面的例子可知, 使用 urllib.request.urlopen() 或者 opener.open(url) 返回結果是一個 http.client.HTTPResponse 對象。它具有 msg、version、status、reason、debuglevel、closed等屬性以及read()、readinto()、getheader(name)、getheaders()、fileno()等函數。

 

2 錯誤解析

發起請求難免會出現各種異常,我們需要對異常進行處理,這樣會使得程序比較人性化。
異常處理主要用到兩個類,urllib.error.URLErrorurllib.error.HTTPError

  • URLError
    URLError 是 urllib.error 異常類的基類, 可以捕獲由urllib.request 產生的異常。
    它具有一個屬性reason,即返回錯誤的原因。

捕獲 URL 異常的示例代碼:

import urllib.request
import urllib.error

url = "http://www.google.com"
try:
    response = request.urlopen(url)
except error.URLError as e:
    print(e.reason)
  • HTTPError HTTPError 是 UEKRrror 的子類,專門處理 HTTP 和 HTTPS 請求的錯誤。它具有三個屬性。

  1)code:HTTP 請求返回的狀態碼。

  2)reason:與父類用法一樣,表示返回錯誤的原因。

  3)headers`:HTTP 請求返回的響應頭信息。

獲取 HTTP 異常的示例代碼, 輸出了錯誤狀態碼、錯誤原因、服務器響應頭

import urllib.request
import urllib.error

url = "http://www.google.com"
try:
    response = request.urlopen(url)
except error.HTTPError as e:
   print('code: ' + e.code + '\n')
   print('reason: ' + e.reason + '\n')
   print('headers: ' + e.headers + '\n')

 2.urllib.response 

(在使用urlopen()方法或者opener的open()方法發起請求后,獲得的結果是一個response對象。這個對象有一些方法和屬性,可以讓我們對請求返回的結果進行一些處理。)

geturl()  : 返回獲取的真實的URL,這個很有用,因為 urlopen(或者 opener 對象使用的)或許會有重定向。獲取的 URL 或許跟請求 URL 不同。

info() : 這個返回對象的字典對象,該字典描述了獲取的頁面情況。通常是服務器發送的特定頭 headers。

read():獲取響應返回的數據,只能使用一次。

getcode():獲取服務器返回的狀態碼。

getheaders():獲取返回響應的響應報頭。

3.urllib.parse
(urllib.parse是urllib中用來解析各種數據格式的模塊)

1. urllib.parse.quote
在url中,是只能使用ASCII中包含的字符的,也就是說,ASCII不包含的特殊字符,以及中文等字符都是不可以在url中使用的。而我們有時候又有將中文字符加入到url中的需求,例如百度的搜索地址:https://www.baidu.com/s?wd=南北。?之后的wd參數,則是我們搜索的關鍵詞。那么我們實現的方法就是將特殊字符進行url編碼,轉換成可以url可以傳輸的格式,urllib中可以使用quote()方法來實現這個功能。

from urllib import parse
keyword = '南北'
parse.quote(keyword)
=======>>'%E5%8D%97%E5%8C%97'

#如果需要將編碼后的數據轉換回來,可以使用unquote()方法。
parse.unquote('%E5%8D%97%E5%8C%97')
=======>>'南北'

2. urllib.parse.urlencode

在訪問url時,我們常常需要傳遞很多的url參數,而如果用字符串的方法去拼接url的話,會比較麻煩,所以urllib中提供了urlencode這個方法來拼接url參數。

from urllib import parse 
params = {'wd': '南北', 'code': '1', 'height': '188'}  
parse.urlencode(params)
 
=======>>'wd=%E5%8D%97%E5%8C%97&code=1&height=188'

4.urllib.error

在urllib中主要設置了兩個異常,一個是URLError,一個是HTTPErrorHTTPErrorURLError的子類。

HTTPError還包含了三個屬性:

  • code:請求的狀態碼
  • reason:錯誤的原因
  • headers:響應的報頭
from urllib.error import HTTPError 
try:
    request.urlopen('https://www.jianshu.com') 
except HTTPError as e:
    print(e.code)

403

一個使用代理的例子:

proxy_handler = urllib.request.ProxyHandler({'http':
'http://www.example.com:3128/'})
proxy_auth_handler = urllib.request.ProxyBasicAuth()
proxy_auth_handler.add_password('realm', 'host', 'username', 'password')

opener = urllib.request.build_opener(proxy_handler, proxy_auth_handler)
opener.open('http://www.example.com/login.html')

添加HTTP請求頭部:

import urllib.request
req = urllib.request.Request('http://www.example.com/')
req.add_header('Referer', 'http://www.python.org/')
r = urllib.request.urlopen(req)

更改User-agent:

import urllib.request
opener = urllib.request.build_opener()
opener.addheaders = [('User-agent', 'Mozilla/5.0')]
opener.open('http://www.example.com/')

三、Python3.X中使用整合后的urllib

Python2.x 有這些庫名可用: urllib,urllib2,urllib3,httplib,httplib2,requestsPython3.x 有這些庫名可用: urllib,urllib3,httplib2,requests

若只使用Python3.x,記住有個urllib的庫就行了。Pyhton2.x和Python3.x都有urllib3和requests, 它們不是標准庫。urllib3提供線程安全連接池和文件post等支持,與urllib及urllib2的關系不大。requests 自稱HTTP for Humans,使用更簡潔方便。

Python3.x中將urllib2合並到了urllib,之后此包分成了以下幾個模塊:

    urllib.request 用於打開和讀取URL

    urllib.error 用於處理前面request引起的異常

    urllib.parse 用於解析URL

    urllib.robotparser用於解析robots.txt文件

Python3.x中,隨着urllib2合入urllib,一些常用的方法也發生了變化:2

    在Python2.x中使用import urlparse——在Python3.x中會使用import urllib.parse

    在Python2.x中使用urllib2.urlopen或urllib.urlopen(已棄用)——在Python3.x中會使用urllib.request.urlopen

    在Python2.x中使用urllib2.Request——在Python3.x中會使用urllib.request.Request

    在Python2.x中使用urllib.quote——在Python3.x中會使用urllib.request.quote

    在Python2.x中使用urllib.urlencode——在Python3.x中會使用urllib.parse.urlencode

    在Python2.x中使用cookielib.CookieJar——在Python3.x中會使用http.CookieJar

    異常處理:在Python2.x中使用urllib2.URLError,urllib2.HTTPError——在Python3.x中會使用urllib.error.URLError,urllib.error.HTTPError

注:在Python3.3后urllib2已經不能再用,所有urllib2全部用urllib.request來代替。

PUT一個請求:

import urllib.request 
DATA=b'some data' 
req = urllib.request.Request(url='http://localhost:8080', data=DATA, method='PUT') 
with urllib.request.urlopen(req) as f: 
    pass 
print(f.status) 
print(f.reason)

基本的HTTP認證:

import urllib.request 

auth_handler = urllib.request.HTTPBasicAuthHandler() 
auth_handler.add_password(realm='PDQ Application', uri='https://mahler:8092/site-updates.py', user='klem', passwd='kadidd!ehopper') opener = urllib.request.build_opener(auth_handler)
urllib.request.install_opener(opener)
urllib.request.urlopen('http://www.example.com/login.html')

指定proxy:

import urllib.request 
proxies = {'http': 'http://proxy.example.com:8080/'} 
opener = urllib.request.FancyURLopener(proxies)
with opener.open("http://www.python.org") as f: 
  f.read().decode('utf-8')

不使用proxy, 覆蓋環境變量的proxy:

import urllib.request
opener = urllib.request.FancyURLopener({}) 
with opener.open("http://www.python.org/") as f:
    f.read().decode('utf-8')

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM