1. 程式人生 > >urllib庫的urlopen詳解

urllib庫的urlopen詳解

一 爬蟲基本庫

Python提供了功能齊全的類庫來幫助我們完成網路請求。最基礎的HTTP庫有urllib、httplib2、requests、treq等。

urllib庫,只需要關心請求的連結是什麼,需要傳的引數是什麼以及可選的請求頭設定就好了,不用深入到底層去了解它到底是怎樣傳輸和通訊的。有了它,兩行程式碼就可以完成一個請求和響應的處理過程,得到網頁內容。

二 urllib介紹

在Python 2中,有urllib和urllib2兩個庫來實現請求的傳送。而在Python 3中,已經不存在urllib2這個庫了,統一為urllib,其官方文件連結為:https://docs.python.org/3/library/urllib.html

urllib庫:Python內建的HTTP請求庫,也就是說不需要額外安裝即可使用。

它包含如下4個模組。

  • request:它是最基本的HTTP請求模組,可以用來模擬傳送請求。就像在瀏覽器裡輸入網址然後回車一樣,只需要給庫方法傳入URL以及額外的引數,就可以模擬實現這個過程了。
  • error:異常處理模組,如果出現請求錯誤,可以捕獲這些異常,然後進行重試或其他操作以保證程式不會意外終止。
  • parse:一個工具模組,提供了許多URL處理方法,比如拆分、解析、合併等。
  • robotparser:主要是用來識別網站的robots.txt檔案,然後判斷哪些網站可以爬,哪些網站不可以爬,它其實用得比較少。

三 urllib庫的urlopen介紹

1 urlopen()

1.1 點睛

urllib.request模組提供了最基本的構造HTTP請求的方法,利用它可以模擬瀏覽器的一個請求發起過程,同時它還帶有處理授權驗證(authenticaton)、重定向(redirection)、瀏覽器Cookies以及其他內容。

1.2 程式碼

import urllib.request

response = urllib.request.urlopen('https://www.python.org')
print(response.read().decode('utf-8'))

1.3 結果

2  結果型別分析

2.1 點睛

urlopen返回的是HTTPResposne型別的物件。

它主要包含read()、readinto()、getheader(name)、getheaders()、fileno()等方法,以及msg、version、status、reason、debuglevel、closed等屬性。

得到這個物件之後,我們把它賦值為response變數,然後就可以呼叫這些方法和屬性,得到返回結果的一系列資訊了。

例如,呼叫read()方法可以得到返回的網頁內容,呼叫status屬性可以得到返回結果的狀態碼,如200代表請求成功,404代表網頁未找到等。

2.2 程式碼

import urllib.request

response = urllib.request.urlopen('https://www.python.org')
print(type(response))

2.3 結果

E:\WebSpider\venv\Scripts\python.exe E:/WebSpider/3_1_1.py

<class 'http.client.HTTPResponse'>

3 HTTPResposne的屬性和方法。

3.1 程式碼

import urllib.request

response = urllib.request.urlopen('https://www.python.org')
# 前兩個輸出分別輸出了響應的狀態碼和響應的頭資訊,
# 最後一個輸出通過呼叫getheader()方法並傳遞一個引數Server獲取了響應頭中的Server值,
# 結果是nginx,意思是伺服器是用Nginx搭建的。
print(response.status)
print(response.getheaders())
print(response.getheader('Server'))

3.2 結果

E:\WebSpider\venv\Scripts\python.exe E:/WebSpider/3_1_1.py

200

[('Server', 'nginx'), ('Content-Type', 'text/html; charset=utf-8'), ('X-Frame-Options', 'SAMEORIGIN'), ('x-xss-protection', '1; mode=block'), ('X-Clacks-Overhead', 'GNU Terry Pratchett'), ('Via', '1.1 varnish'), ('Content-Length', '48960'), ('Accept-Ranges', 'bytes'), ('Date', 'Sun, 06 Jan 2019 07:07:47 GMT'), ('Via', '1.1 varnish'), ('Age', '2563'), ('Connection', 'close'), ('X-Served-By', 'cache-iad2151-IAD, cache-hnd18733-HND'), ('X-Cache', 'HIT, HIT'), ('X-Cache-Hits', '1, 1970'), ('X-Timer', 'S1546758468.685275,VS0,VE0'), ('Vary', 'Cookie'), ('Strict-Transport-Security', 'max-age=63072000; includeSubDomains')]

nginx

4 urlopen函式data引數分析

4.1 函式原型

urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)

4.2 data引數

data引數是可選的。如果要新增該引數,並且如果它是位元組流編碼格式的內容,即bytes型別,則需要通過bytes()方法轉化。另外,如果傳遞了這個引數,則它的請求方式就不再是GET方式,而是POST方式。

4.3 程式碼

import urllib.parse
import urllib.request
# 這裡我們傳遞了一個引數word,值是hello。它需要被轉碼成bytes(位元組流)型別。
# 其中轉位元組流採用了bytes()方法,該方法的第一個引數需要是str(字串)型別,
# 需要用urllib.parse模組裡的urlencode()方法來將引數字典轉化為字串;
# 第二個引數指定編碼格式,這裡指定為utf8
data = bytes(urllib.parse.urlencode({'word': 'hello'}), encoding='utf8')
# 這裡請求的站點是httpbin.org,它可以提供HTTP請求測試。
# 本次我們請求的URL為http://httpbin.org/post,這個連結可以用來測試POST請求,
# 它可以輸出請求的一些資訊,其中包含我們傳遞的data引數。
response = urllib.request.urlopen('http://httpbin.org/post', data=data)
print(response.read())

4.4 結果

{
     "args": {},
     "data": "",
     "files": {},
     "form": {
         "word": "hello"
     },
     "headers": {
         "Accept-Encoding": "identity",
         "Content-Length": "10",
         "Content-Type": "application/x-www-form-urlencoded",
         "Host": "httpbin.org",
         "User-Agent": "Python-urllib/3.5"
     },
     "json": null,
     "origin": "123.124.23.253",
     "url": "http://httpbin.org/post"
}

4.5 說明

我們傳遞的引數出現在了form欄位中,這表明是模擬了表單提交的方式,以POST方式傳輸資料。

5 urlopen函式timeout引數分析

5.1 點睛

timeout引數用於設定超時時間,單位為秒,意思就是如果請求超出了設定的這個時間,還沒有得到響應,就會丟擲異常。如果不指定該引數,就會使用全域性預設時間。它支援HTTP、HTTPS、FTP請求。

5.2 例項

import urllib.request
# 這裡我們設定超時時間是0.1秒
response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.1)
print(response.read())

5.3 結果

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/var/py/python/urllibtest.py", line 4, in <module> response = urllib.request.urlopen('http://httpbin.org/get', timeout=1)

...

urllib.error.URLError: <urlopen error timed out>

5.4 結果說明

這裡我們設定超時時間是0.1秒。程式0.1秒過後,伺服器依然沒有響應,於是丟擲了URLError異常。該異常屬於urllib.error模組,錯誤原因是超時。

5.5 捕獲異常實戰

import socket
import urllib.request
import urllib.error
# 這裡我們請求了http://httpbin.org/get測試連結,
# 設定超時時間是0.1秒,然後捕獲了URLError異常,
# 接著判斷異常是socket.timeout型別(意思就是超時異常),
# 從而得出它確實是因為超時而報錯,列印輸出了TIME OUT
try:
    response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.1)
except urllib.error.URLError as e:
    if isinstance(e.reason, socket.timeout):
        print('TIME OUT')

5.6  結果

E:\WebSpider\venv\Scripts\python.exe E:/WebSpider/3_1_1.py

TIME OUT

6 其他引數

除了data引數和timeout引數外,還有context引數,它必須是ssl.SSLContext型別,用來指定SSL設定。

此外,cafile和capath這兩個引數分別指定CA證書和它的路徑,這個在請求HTTPS連結時會有用。

cadefault引數現在已經棄用了,其預設值為False。

urlopen()可以完成簡單的請求和網頁抓取。

若需更加詳細的資訊,可以參見官方文件:https://docs.python.org/3/library/urllib.request.html