詳解 python3 urllib

圖片來自 unsplash

本文是爬蟲系列文章的第一篇,主要講解 Python 3 中的 urllib 庫的用法。urllib 是 Python 標(biāo)準(zhǔn)庫中用于網(wǎng)絡(luò)請(qǐng)求的庫。該庫有四個(gè)模塊,分別是urllib.request,urllib.error,urllib.parse,urllib.robotparser。其中urllib.request,urllib.error兩個(gè)庫在爬蟲程序中應(yīng)用比較頻繁。那我們就開門見山,直接講解這兩個(gè)模塊的用法。

1 發(fā)起請(qǐng)求

模擬瀏覽器發(fā)起一個(gè) HTTP 請(qǐng)求,我們需要用到 urllib.request 模塊。urllib.request 的作用不僅僅是發(fā)起請(qǐng)求, 還能獲取請(qǐng)求返回結(jié)果。發(fā)起請(qǐng)求,單靠 urlopen() 方法就可以叱咤風(fēng)云。我們先看下 urlopen() 的 API

urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
  • 第一個(gè)參數(shù) String 類型的地址或者
  • data 是 bytes 類型的內(nèi)容,可通過 bytes()函數(shù)轉(zhuǎn)為化字節(jié)流。它也是可選參數(shù)。使用 data 參數(shù),請(qǐng)求方式變成以 POST 方式提交表單。使用標(biāo)準(zhǔn)格式是application/x-www-form-urlencoded
  • timeout 參數(shù)是用于設(shè)置請(qǐng)求超時(shí)時(shí)間。單位是秒。
  • cafilecapath代表 CA 證書和 CA 證書的路徑。如果使用HTTPS則需要用到。
  • context參數(shù)必須是ssl.SSLContext類型,用來指定SSL設(shè)置
  • cadefault參數(shù)已經(jīng)被棄用,可以不用管了。
  • 該方法也可以單獨(dú)傳入urllib.request.Request對(duì)象
  • 該函數(shù)返回結(jié)果是一個(gè)http.client.HTTPResponse對(duì)象。

1.1 簡單抓取網(wǎng)頁

我們使用 urllib.request.urlopen() 去請(qǐng)求百度貼吧,并獲取到它頁面的源代碼。

import urllib.request

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

1.2 設(shè)置請(qǐng)求超時(shí)

有些請(qǐng)求可能因?yàn)榫W(wǎng)絡(luò)原因無法得到響應(yīng)。因此,我們可以手動(dòng)設(shè)置超時(shí)時(shí)間。當(dāng)請(qǐng)求超時(shí),我們可以采取進(jìn)一步措施,例如選擇直接丟棄該請(qǐng)求或者再請(qǐng)求一次。

import urllib.request

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

1.3 使用 data 參數(shù)提交數(shù)據(jù)

在請(qǐng)求某些網(wǎng)頁時(shí)需要攜帶一些數(shù)據(jù),我們就需要使用到 data 參數(shù)。

import urllib.parse
import urllib.request

url = "http://127.0.0.1:8000/book"
params = {
  'name':'浮生六記',
  'author':'沈復(fù)'
}

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

params 需要被轉(zhuǎn)碼成字節(jié)流。而 params 是一個(gè)字典。我們需要使用 urllib.parse.urlencode() 將字典轉(zhuǎn)化為字符串。再使用 bytes() 轉(zhuǎn)為字節(jié)流。最后使用 urlopen() 發(fā)起請(qǐng)求,請(qǐng)求是模擬用 POST 方式提交表單數(shù)據(jù)。

1.4 使用 Request

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

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

使用 Request 偽裝成瀏覽器發(fā)起 HTTP 請(qǐng)求。如果不設(shè)置 headers 中的 User-Agent,默認(rèn)的User-AgentPython-urllib/3.5??赡芤恍┚W(wǎng)站會(huì)將該請(qǐng)求攔截,所以需要偽裝成瀏覽器發(fā)起請(qǐng)求。我使用的 User-Agent 是 Chrome 瀏覽器。

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 高級(jí)用法

如果我們需要在請(qǐng)求中添加代理、處理請(qǐng)求的 Cookies,我們需要用到HandlerOpenerDirector。

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

  • ProxyHandler:為請(qǐng)求設(shè)置代理
  • HTTPCookieProcessor:處理 HTTP 請(qǐng)求中的 Cookies
  • HTTPDefaultErrorHandler:處理 HTTP 響應(yīng)錯(cuò)誤。
  • HTTPRedirectHandler:處理 HTTP 重定向。
  • HTTPPasswordMgr:用于管理密碼,它維護(hù)了用戶名密碼的表。
  • HTTPBasicAuthHandler:用于登錄認(rèn)證,一般和 HTTPPasswordMgr 結(jié)合使用。

2) OpenerDirector
對(duì)于 OpenerDirector,我們可以稱之為 Opener。我們之前用過 urlopen() 這個(gè)方法,實(shí)際上它就是 urllib 為我們提供的一個(gè)Opener。那 Opener 和 Handler 又有什么關(guān)系?opener 對(duì)象是由 build_opener(handler) 方法來創(chuàng)建出來 。我們需要?jiǎng)?chuàng)建自定義的 opener,就需要使用 install_opener(opener)方法。值得注意的是,install_opener 實(shí)例化會(huì)得到一個(gè)全局的 OpenerDirector 對(duì)象。

1.5 使用代理

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

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'
}

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 認(rèn)證登錄

有些網(wǎng)站需要攜帶賬號(hào)和密碼進(jìn)行登錄之后才能繼續(xù)瀏覽網(wǎng)頁。碰到這樣的網(wǎng)站,我們需要用到認(rèn)證登錄。我們首先需要使用 HTTPPasswordMgrWithDefaultRealm() 實(shí)例化一個(gè)賬號(hào)密碼管理對(duì)象;然后使用 add_password() 函數(shù)添加賬號(hào)和密碼;接著使用 HTTPBasicAuthHandler() 得到 hander;再使用 build_opener() 獲取 opener 對(duì)象;最后使用 opener 的 open() 函數(shù)發(fā)起請(qǐng)求。

第二個(gè)例子是攜帶賬號(hào)和密碼請(qǐng)求登錄百度貼吧,代碼如下:

import urllib.request

url = "http://tieba.baidu.com/"
user = '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設(shè)置

如果請(qǐng)求的頁面每次需要身份驗(yàn)證,我們可以使用 Cookies 來自動(dòng)登錄,免去重復(fù)登錄驗(yàn)證的操作。獲取 Cookies 需要使用 http.cookiejar.CookieJar() 實(shí)例化一個(gè) Cookies 對(duì)象。再用 urllib.request.HTTPCookieProcessor 構(gòu)建出 handler 對(duì)象。最后使用 opener 的 open() 函數(shù)即可。

第三個(gè)例子是獲取請(qǐng)求百度貼吧的 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) 返回結(jié)果是一個(gè) http.client.HTTPResponse 對(duì)象。它具有 msg、version、status、reason、debuglevel、closed等屬性以及read()、readinto()、getheader(name)、getheaders()、fileno()等函數(shù)。

2 錯(cuò)誤解析

發(fā)起請(qǐng)求難免會(huì)出現(xiàn)各種異常,我們需要對(duì)異常進(jìn)行處理,這樣會(huì)使得程序比較人性化。
異常處理主要用到兩個(gè)類,urllib.error.URLErrorurllib.error.HTTPError。

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

捕獲 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 請(qǐng)求的錯(cuò)誤。它具有三個(gè)屬性。 1)code:HTTP 請(qǐng)求返回的狀態(tài)碼。 1)renson:與父類用法一樣,表示返回錯(cuò)誤的原因。 1)headers`:HTTP 請(qǐng)求返回的響應(yīng)頭信息。

獲取 HTTP 異常的示例代碼, 輸出了錯(cuò)誤狀態(tài)碼、錯(cuò)誤原因、服務(wù)器響應(yīng)頭

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')

上篇文章:學(xué)爬蟲之道


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、概述 urllib2是Python的一個(gè)針對(duì)URLs的庫。他以u(píng)rlopen函數(shù)的形式提供了一個(gè)非常簡單的...
    MiracleJQ閱讀 1,557評(píng)論 0 5
  • urllib庫 python內(nèi)置的HTTP請(qǐng)求庫 四個(gè)模塊:request,parse,error,rebotpa...
    我是一只菜鳥呀閱讀 3,108評(píng)論 0 2
  • 1 前言 作為一名合格的數(shù)據(jù)分析師,其完整的技術(shù)知識(shí)體系必須貫穿數(shù)據(jù)獲取、數(shù)據(jù)存儲(chǔ)、數(shù)據(jù)提取、數(shù)據(jù)分析、數(shù)據(jù)挖掘、...
    whenif閱讀 18,313評(píng)論 45 523
  • python模塊(包)之urllib urllib:官方文檔是最好的模塊表達(dá)說明。 urllib is a pac...
    道無虛閱讀 1,706評(píng)論 0 1
  • 終于在傍晚七點(diǎn)左右看完了《人民的名義》的36集,像我過去說的,這是一個(gè)陰謀,可以20集講完的故事,為了多拉住觀眾,...
    楊知行閱讀 757評(píng)論 0 0

友情鏈接更多精彩內(nèi)容