一、urllib 簡介
urllib 是 Python3 中自帶的 HTTP 請求庫,無需復雜的安裝過程即可正常使用,十分適合爬蟲入門
urllib 中包含四個模塊,分別是
- request:請求處理模塊
- parse:URL 處理模塊
- error:異常處理模塊
- robotparser:robots.txt 解析模塊
以下我們將會分別講解 urllib 中各模塊的使用方法,但是由於篇幅問題,本文只會涉及模塊中比較常用的內容
詳細內容可以參考官方文檔:https://docs.python.org/3.7/library/urllib.html
二、urllib 使用
在開始講解前,先給大家提供一個用於測試的網站,http://www.httpbin.org/
這個網站可以在頁面上返回所發送 請求 的相關信息,十分適合練習使用
好了,下面正式開始!
1、request 模塊
request 模塊是 urllib 中最重要的一個模塊,一般用於 發送請求和接收響應
(1)urlopen 方法
urllib.request.urlopen()
urlopen 方法無疑是 request 模塊中最常用的方法之一,常見的參數說明如下:
-
url
:必填,字符串,指定目標網站的 URL -
data
:指定表單數據該參數默認為 None,此時 urllib 使用 GET 方法 發送請求
當給參數賦值后,urllib 使用 POST 方法 發送請求,並在該參數中攜帶表單信息(bytes 類型)
-
timeout
:可選參數,用來指定等待時間,若超過指定時間還沒獲得響應,則拋出一個異常
該方法始終返回一個 HTTPResponse 對象,HTTPResponse 對象常見的屬性和方法如下:
geturl()
:返回 URLgetcode()
:返回狀態碼getheaders()
:返回全部響應頭信息getheader(header)
:返回指定響應頭信息read()
:返回響應體(bytes 類型),通常需要使用decode('utf-8')
將其轉化為 str 類型
例子1:發送 GET 請求
>>> import urllib.request
>>> url = 'http://www.httpbin.org/get'
>>> response = urllib.request.urlopen(url)
>>> type(response)
# <class 'http.client.HTTPResponse'>
>>> response.geturl()
# 'http://www.httpbin.org/get'
>>> response.getcode()
# 200
>>> response.getheaders()
# [('Connection', 'close'), ('Server', 'gunicorn/19.9.0'), ('Date', 'Sat, 11 Aug 2018 01:39:14 GMT'), ('Content-Type', 'application/json'), ('Content-Length', '243'), ('Access-Control-Allow-Origin', '*'), ('Access-Control-Allow-Credentials', 'true'), ('Via', '1.1 vegur')]
>>> response.getheader('Connection')
# 'close'
>>> print(response.read().decode('utf-8'))
# {
# "args": {},
# "headers": {
# "Accept-Encoding": "identity",
# "Host": "www.httpbin.org",
# "User-Agent": "Python-urllib/3.7"
# },
# "origin": "183.6.159.80, 183.6.159.80",
# "url": "https://www.httpbin.org/get"
# }
例子2:發送 POST 請求
urllib.parse.urlencode()
:進行 URL 編碼,實際上是將 dict 類型數據轉化成 str 類型數據
encode('utf-8')
:將 str 類型數據轉化成 bytes 類型數據
>>> import urllib.request
>>> import urllib.parse
>>> url = 'http://www.httpbin.org/post'
>>> params = {
'from':'AUTO',
'to':'AUTO'
}
>>> data = urllib.parse.urlencode(params).encode('utf-8')
>>> response = urllib.request.urlopen(url=url,data=data)
>>> html = response.read().decode('utf-8')
>>> print(html)
# {
# "args": {},
# "data": "",
# "files": {},
# "form": { # 這是我們設置的表單數據
# "from": "AUTO",
# "to": "AUTO"
# },
# "headers": {
# "Accept-Encoding": "identity",
# "Connection": "close",
# "Content-Length": "17",
# "Content-Type": "application/x-www-form-urlencoded",
# "Host": "www.httpbin.org",
# "User-Agent": "Python-urllib/3.6"
# },
# "json": null,
# "origin": "116.16.107.180",
# "url": "http://www.httpbin.org/post"
# }
(2)Request 對象
實際上,我們還可以給 urllib.request.open()
方法傳入一個 Request 對象作為參數
為什么還需要使用 Request 對象呢?因為在上面的參數中我們無法指定 請求頭部,而它對於爬蟲而言又十分重要
很多網站可能會首先檢查請求頭部中的 USER-AGENT
字段來判斷該請求是否由網絡爬蟲程序發起
但是通過修改請求頭部中的 USER_AGENT
字段,我們可以將爬蟲程序偽裝成瀏覽器,輕松繞過這一層檢查
這里提供一個查找常用的 USER-AGENT 的網站:
urllib.request.Request()
參數說明如下:
url
:指定目標網站的 URLdata
:發送 POST 請求時提交的表單數據,默認為 Noneheaders
:發送請求時附加的請求頭部,默認為 {}origin_req_host
:請求方的 host 名稱或者 IP 地址,默認為 Noneunverifiable
:請求方的請求無法驗證,默認為 Falsemethod
:指定請求方法,默認為 None
>>> import urllib.request
>>> url = 'http://www.httpbin.org/headers'
>>> headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
}
>>> req = urllib.request.Request(url, headers=headers, method='GET')
>>> response = urllib.request.urlopen(req)
>>> html = response.read().decode('utf-8')
>>> print(html)
# {
# "headers": {
# "Accept-Encoding": "identity",
# "Connection": "close",
# "Host": "www.httpbin.org",
# "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36" 這是我們設置的 User-Agent
# }
# }
(3) 使用 Cookie
什么是 Cookie?
Cookie 是指某些網站為了辨別用戶身份、進行 session 跟蹤而儲存在用戶本地終端上的數據
① 獲取 Cookie
>>> import urllib.request
>>> import http.cookiejar
>>> cookie = http.cookiejar.CookieJar()
>>> cookie_handler = urllib.request.HTTPCookieProcessor(cookie)
>>> opener = urllib.request.build_opener(cookie_handler)
>>> response = opener.open('http://www.baidu.com')
>>> for item in cookie:
print(item.name + '=' + item.value)
# BAIDUID=486AED46E7F22C0A7A16D9FE6E627846:FG=1
# BDRCVFR[RbWYmTxDkZm]=mk3SLVN4HKm
# BIDUPSID=486AED46E7F22C0A7A16D9FE6E627846
# H_PS_PSSID=1464_21106_26920
# PSTM=1533990197
# BDSVRTM=0
# BD_HOME=0
# delPer=0
② 使用 Cookie
>>> import urllib.request
>>> import http.cookiejar
>>> # 將 Cookie 保存到文件
>>> cookie = http.cookiejar.MozillaCookieJar('cookie.txt')
>>> cookie_handler = urllib.request.HTTPCookieProcessor(cookie)
>>> opener = urllib.request.build_opener(cookie_handler)
>>> response = opener.open('http://www.baidu.com')
>>> cookie.save(ignore_discard=True,ignore_expires=True)
>>> # 從文件讀取 Cookie 並添加到請求中
>>> cookie = http.cookiejar.MozillaCookieJar()
>>> cookie = cookie.load('cookie.txt',ignore_discard=True,ignore_expires=True)
>>> cookie_handler = urllib.request.HTTPCookieProcessor(cookie)
>>> opener = urllib.request.build_opener(cookie_handler)
>>> response = opener.open('http://www.baidu.com')
>>> # 此時已經得到帶有 Cookie 請求返回的響應
(4)使用代理
對於某些網站,如果同一個 IP 短時間內發送大量請求,則可能會將該 IP 判定為爬蟲,進而對該 IP 進行封禁
所以我們有必要使用隨機的 IP 地址來繞開這一層檢查,這里提供幾個查找免費的 IP 地址的網站:
- 西刺代理:http://www.xicidaili.com/nn/
- 雲代理:http://www.ip3366.net/free/
- 快代理:https://www.kuaidaili.com/free/
注意,免費的代理 IP 基本上十分不穩定,而且還可能隨時更新,所以最好自己寫一個爬蟲去維護
>>> import urllib.request
>>> import random
>>> ip_list = [
{'http':'61.135.217.7:80'},
{'http':'182.88.161.204:8123'}
]
>>> proxy_handler = urllib.request.ProxyHandler(random.choice(ip_list))
>>> opener = urllib.request.build_opener(proxy_handler)
>>> response = opener.open('http://www.httpbin.org/ip')
>>> print(response.read().decode('utf-8'))
# {
# "origin": "61.135.217.7"
# }
2、parse 模塊
parse 模塊一般可以用於處理 URL
(1)quote 方法
當你在 URL 中使用中文時,你會發現程序會出現莫名其妙的錯誤
>>> import urllib.request
>>> url = 'https://www.baidu.com/s?wd=爬蟲'
>>> response = urllib.request.urlopen(url)
# UnicodeEncodeError: 'ascii' codec can't encode characters in position 10-11: ordinal not in range(128)
這時,quote 方法就可以派上用場了,它使用轉義字符替換特殊字符,從而將上面的 URL 處理成合法的 URL
>>> import urllib.parse
>>> url = 'https://www.baidu.com/s?wd=' + urllib.parse.quote('爬蟲')
>>> url
# 'https://www.baidu.com/s?wd=%E7%88%AC%E8%99%AB'
(2)urlencode 方法
urlencode 方法在上面的文章中曾經用到過,不知道大家還有沒有印象,這里我們再重新回顧一遍
簡單來說,urlencode 方法就是將 dict 類型數據轉化為符合 URL 標准的 str 類型數據,請看演示:
>>> import urllib.parse
>>> params = {
'from':'AUTO',
'to':'AUTO'
}
>>> data = urllib.parse.urlencode(params)
>>> data
# 'from=AUTO&to=AUTO'
(3)urlparse 方法
urlparse 方法用於解析 URL,返回一個 ParseResult 對象
該對象可以認為是一個六元組,對應 URL 的一般結構:scheme://netloc/path;parameters?query#fragment
>>> import urllib.parse
>>> url = 'http://www.example.com:80/python.html?page=1&kw=urllib'
>>> url_after = urllib.parse.urlparse(url)
>>> url_after
# ParseResult(scheme='http', netloc='www.example.com:80', path='/python.html', params='', query='page=1', fragment='urllib')
>>> url_after.port
# 80
3、error 模塊
error 模塊一般用於進行異常處理,其中包含兩個重要的類:URLError
和 HTTPError
注意,HTTPError 是 URLError 的子類,所以捕獲異常時一般要先處理 HTTPError,常用的格式如下:
>>> import urllib.request
>>> import urllib.error
>>> import socket
>>> try:
response = urllib.request.urlopen('http://www.httpbin.org/get', timeout=0.1)
except urllib.error.HTTPError as e:
print("Error Code: ", e.code)
print("Error Reason: ", e.reason)
except urllib.error.URLError as e:
if isinstance(e.reason, socket.timeout):
print('Time out')
else:
print('Request Successfully')
# Time out
【參考資料】
【爬蟲系列相關文章】