前言
更多內(nèi)容,請(qǐng)?jiān)L問我的 個(gè)人博客。
Python
訪問網(wǎng)絡(luò)資源有很多方法狰挡,urllib
, urllib2
, urllib3
, httplib
, httplib2
, requests
,現(xiàn)介紹如下兩種方法:
-
內(nèi)置的
urllib
模塊- 優(yōu)點(diǎn):自帶模塊,無需額外下載第三方庫(kù)
- 缺點(diǎn):操作繁瑣削饵,缺少高級(jí)功能
-
第三方庫(kù)
requests
- 優(yōu)點(diǎn):處理URL資源特別方便
- 缺點(diǎn):需要下載安裝第三方庫(kù)
內(nèi)置的 urllib
模塊
發(fā)起GET請(qǐng)求
主要使用urlopen()方法來發(fā)起請(qǐng)求岩瘦,如下:
from urllib import request
resp = request.urlopen('http://www.baidu.com')
print(resp.read().decode())
訪問的結(jié)果會(huì)是一 個(gè)http.client.HTTPResponse
對(duì)象,使用此對(duì)象的 read()
方法窿撬,則可以獲取訪問網(wǎng)頁(yè)獲得的數(shù)據(jù)启昧。但是要注意的是,獲得的數(shù)據(jù)會(huì)是 bytes
的二進(jìn)制格式劈伴,所以需要 decode()
一下密末,轉(zhuǎn)換成字符串格式。
發(fā)起POST請(qǐng)求
urlopen()
默認(rèn)的訪問方式是GET跛璧,當(dāng)在 urlopen()
方法中傳入data參數(shù)時(shí)严里,則會(huì)發(fā)起POST請(qǐng)求。注意:傳遞的data數(shù)據(jù)需要為bytes格式追城。
設(shè)置timeout參數(shù)還可以設(shè)置超時(shí)時(shí)間田炭,如果請(qǐng)求時(shí)間超出,那么就會(huì)拋出異常漓柑。如下:
from urllib import request
resp = request.urlopen('http://www.baidu.com', data=b'word=hello', timeout=10)
print(resp.read().decode())
添加Headers
通過 urllib
發(fā)起的請(qǐng)求會(huì)有默認(rèn)的一個(gè)Headers:"User-Agent":"Python-urllib/3.6"教硫,指明請(qǐng)求是由 urllib
發(fā)送的。
所以遇到一些驗(yàn)證User-Agent的網(wǎng)站時(shí)辆布,我們需要自定義Headers瞬矩,而這需要借助于urllib.request中的 Request
對(duì)象。
from urllib import request
url = 'http://httpbin.org/get'
headers = {'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'}
# 需要使用url和headers生成一個(gè)Request對(duì)象锋玲,然后將其傳入urlopen方法中
req = request.Request(url, headers=headers)
resp = request.urlopen(req)
print(resp.read().decode())
Request對(duì)象
如上所示景用, urlopen()
方法中不止可以傳入字符串格式的url,也可以傳入一個(gè) Request
對(duì)象來擴(kuò)展功能惭蹂,Request
對(duì)象如下:
class urllib.request.Request(url, data=None, headers={},
origin_req_host=None,
unverifiable=False,
method=None)
構(gòu)造 Request
對(duì)象必須傳入url參數(shù)伞插,data數(shù)據(jù)和headers都是可選的。
最后盾碗, Request
方法可以使用method參數(shù)來自由選擇請(qǐng)求的方法媚污,如PUT,DELETE等等廷雅,默認(rèn)為GET耗美。
添加Cookie
為了在請(qǐng)求時(shí)能帶上Cookie信息,我們需要重新構(gòu)造一個(gè)opener航缀。
使用request.build_opener方法來進(jìn)行構(gòu)造opener商架,將我們想要傳遞的cookie配置到opener中,然后使用這個(gè)opener的open方法來發(fā)起請(qǐng)求芥玉。如下:
from http import cookiejar
from urllib import request
url = 'https://www.baidu.com'
# 創(chuàng)建一個(gè)cookiejar對(duì)象
cookie = cookiejar.CookieJar()
# 使用HTTPCookieProcessor創(chuàng)建cookie處理器
cookies = request.HTTPCookieProcessor(cookie)
# 并以它為參數(shù)創(chuàng)建Opener對(duì)象
opener = request.build_opener(cookies)
# 使用這個(gè)opener來發(fā)起請(qǐng)求
resp = opener.open(url)
# 查看之前的cookie對(duì)象蛇摸,則可以看到訪問百度獲得的cookie
for i in cookie:
print(i)
或者也可以把這個(gè)生成的opener使用install_opener方法來設(shè)置為全局的。
則之后使用urlopen方法發(fā)起請(qǐng)求時(shí)灿巧,都會(huì)帶上這個(gè)cookie赶袄。
# 將這個(gè)opener設(shè)置為全局的opener
request.install_opener(opener)
resp = request.urlopen(url)
設(shè)置Proxy代理
使用爬蟲來爬取數(shù)據(jù)的時(shí)候诬烹,常常需要使用代理來隱藏我們的真實(shí)IP。如下:
from urllib import request
url = 'http://www.baidu.com'
proxy = {'http':'222.222.222.222:80','https':'222.222.222.222:80'}
# 創(chuàng)建代理處理器
proxies = request.ProxyHandler(proxy)
# 創(chuàng)建opener對(duì)象
opener = request.build_opener(proxies)
resp = opener.open(url)
print(resp.read().decode())
下載數(shù)據(jù)到本地
在我們進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí)常常需要保存圖片或音頻等數(shù)據(jù)到本地弃鸦,一種方法是使用python的文件操作绞吁,將read()獲取的數(shù)據(jù)保存到文件中。
而urllib提供了一個(gè)urlretrieve()方法唬格,可以簡(jiǎn)單的直接將請(qǐng)求獲取的數(shù)據(jù)保存成文件家破。如下:
from urllib import request
url = 'http://python.org/'
request.urlretrieve(url, 'python.html')
urlretrieve()
方法傳入的第二個(gè)參數(shù)為文件保存的位置,以及文件名购岗。
注意:urlretrieve()
方法是python2直接移植過來的方法汰聋,以后有可能在某個(gè)版本中棄用。
第三方庫(kù) requests
安裝
由于 requests
是第三方庫(kù)喊积,所以要先安裝烹困,如下:
pip install requests
發(fā)起GET請(qǐng)求
直接用 get
方法,如下:
import requests
r = requests.get('http://www.baidu.com/')
print(r.status_code) #狀態(tài)
print(r.text) #內(nèi)容
對(duì)于帶參數(shù)的URL乾吻,傳入一個(gè)dict作為params參數(shù)髓梅,如下:
import requests
r = requests.get('http://www.baidu.com/', params={'q': 'python', 'cat': '1001'})
print(r.url) #實(shí)際請(qǐng)求的URL
print(r.text)
requests的方便之處還在于,對(duì)于特定類型的響應(yīng)绎签,例如JSON枯饿,可以直接獲取,如下:
r = requests.get('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20%3D%202151330&format=json')
r.json()
# {'query': {'count': 1, 'created': '2017-11-17T07:14:12Z', ...
添加Headers
需要傳入HTTP Header時(shí)诡必,我們傳入一個(gè)dict作為headers參數(shù)奢方,如下:
r = requests.get('https://www.baidu.com/', headers={'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit'})
獲取響應(yīng)頭,如下:
r.headers
# {Content-Type': 'text/html; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Content-Encoding': 'gzip', ...}
r.headers['Content-Type']
# 'text/html; charset=utf-8'
發(fā)起POST請(qǐng)求
要發(fā)送POST請(qǐng)求爸舒,只需要把get()方法變成post()蟋字,然后傳入data參數(shù)作為POST請(qǐng)求的數(shù)據(jù),如下:
r = requests.post('https://accounts.baidu.com/login', data={'form_email': 'abc@example.com', 'form_password': '123456'})
requests默認(rèn)使用application/x-www-form-urlencoded對(duì)POST數(shù)據(jù)編碼扭勉。如果要傳遞JSON數(shù)據(jù)鹊奖,可以直接傳入json參數(shù),如下:
params = {'key': 'value'}
r = requests.post(url, json=params) #內(nèi)部自動(dòng)序列化為JSON
上傳文件
上傳文件需要更復(fù)雜的編碼格式剖效,但是requests把它簡(jiǎn)化成files參數(shù)嫉入,如下:
upload_files = {'file': open('report.xls', 'rb')}
r = requests.post(url, files=upload_files)
在讀取文件時(shí)焰盗,注意務(wù)必使用 'rb'
即二進(jìn)制模式讀取璧尸,這樣獲取的 bytes
長(zhǎng)度才是文件的長(zhǎng)度。
把 post()
方法替換為 put()
熬拒, delete()
等爷光,就可以以PUT或DELETE方式請(qǐng)求資源。
添加Cookie
在請(qǐng)求中傳入Cookie澎粟,只需準(zhǔn)備一個(gè)dict傳入cookies參數(shù)蛀序,如下:
cs = {'token': '12345', 'status': 'working'}
r = requests.get(url, cookies=cs)
requests對(duì)Cookie做了特殊處理欢瞪,使得我們不必解析Cookie就可以輕松獲取指定的Cookie,如下:
r.cookies['token']
# 12345
指定超時(shí)
要指定超時(shí)徐裸,傳入以秒為單位的timeout參數(shù)遣鼓。超時(shí)分為連接超時(shí)和讀取超時(shí),如下:
try:
# 3.1秒后連接超時(shí)重贺,27秒后讀取超時(shí)
r = requests.get(url, timeout=(3.1, 27))
except requests.exceptions.RequestException as e:
print(e)
超時(shí)重連
def gethtml(url):
i = 0
while i < 3:
try:
html = requests.get(url, timeout=5).text
return html
except requests.exceptions.RequestException:
i += 1
添加代理
同添加headers方法骑祟,代理參數(shù)也要是一個(gè)dict,如下:
heads = {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit'
}
proxy = {
'http': 'http://120.25.253.234:812',
'https' 'https://163.125.222.244:8123'
}
r = requests.get('https://www.baidu.com/', headers=heads, proxies=proxy)
更多編程教學(xué)請(qǐng)關(guān)注公眾號(hào):潘高陪你學(xué)編程