前言
urllib、urllib2、urllib3、httplib、httplib2 都是和 HTTP 相關(guān)的 Python 模塊,看名字就覺得很反人類,更糟糕的是這些模塊在 Python2 與 Python3 中有很大的差異,如果業(yè)務(wù)代碼要同時兼容 2 和 3,寫起來會讓人崩潰。
好在,還有一個非常驚艷的 HTTP 庫叫 requests,它是 GitHUb 關(guān)注數(shù)最多的 Python 項目之一,requests 的作者是 Kenneth Reitz 大神。
requests 實現(xiàn)了 HTTP 協(xié)議中絕大部分功能,它提供的功能包括 Keep-Alive、連接池、Cookie持久化、內(nèi)容自動解壓、HTTP代理、SSL認(rèn)證、連接超時、Session等很多特性,最重要的是它同時兼容 python2 和 python3。requests 的安裝可以直接使用 pip 方法:pip install requests
發(fā)送請求
>>> import requests# GET 請求>>> response = requests.get(https://foofish.net)
響應(yīng)內(nèi)容
請求返回的值是一個Response 對象,Response 對象是對 HTTP 協(xié)議中服務(wù)端返回給瀏覽器的響應(yīng)數(shù)據(jù)的封裝,響應(yīng)的中的主要元素包括:狀態(tài)碼、原因短語、響應(yīng)首部、響應(yīng)體等等,這些屬性都封裝在Response 對象中。
# 狀態(tài)碼>>> response.status_code200# 原因短語>>> response.reason'OK'# 響應(yīng)首部>>> for name,value in response.headers.items():... print("%s:%s" % (name, value))...Content-Encoding:gzipServer:nginx/1.10.2Date:Thu, 06 Apr 2017 16:28:01 GMT# 響應(yīng)內(nèi)容>>> response.content'<html><body>此處省略一萬字...</body></html>requests 除了支持 GET 請求外,還支持 HTTP 規(guī)范中的其它所有方法,包括 POST、PUT、DELTET、HEADT、OPTIONS方法。
>>> r = requests.post('http://httpbin.org/post', data = {'key':'value'})>>> r = requests.put('http://httpbin.org/put', data = {'key':'value'})>>> r = requests.delete('http://httpbin.org/delete')>>> r = requests.head('http://httpbin.org/get')>>> r = requests.options('http://httpbin.org/get')查詢參數(shù)
很多URL都帶有很長一串參數(shù),我們稱這些參數(shù)為URL的查詢參數(shù),用"?"附加在URL鏈接后面,多個參數(shù)之間用"&"隔開,比如:http://fav.foofish.net/?p=4&s=20 ,現(xiàn)在你可以用字典來構(gòu)建查詢參數(shù):
>>> args = {"p": 4, "s": 20}>>> response = requests.get("http://fav.foofish.net", params = args)>>> response.url'http://fav.foofish.net/?p=4&s=2'請求首部
requests 可以很簡單地指定請求首部字段 Headers,比如有時要指定 User-Agent 偽裝成瀏覽器發(fā)送請求,以此來蒙騙服務(wù)器。直接傳遞一個字典對象給參數(shù) headers 即可。
>>> r = requests.get(url, headers={'user-agent': 'Mozilla/5.0'})請求體
requests 可以非常靈活地構(gòu)建 POST 請求需要的數(shù)據(jù),如果服務(wù)器要求發(fā)送的數(shù)據(jù)是表單數(shù)據(jù),則可以指定關(guān)鍵字參數(shù) data,如果要求傳遞 json 格式字符串參數(shù),則可以使用json關(guān)鍵字參數(shù),參數(shù)的值都可以字典的形式傳過去。
作為表單數(shù)據(jù)傳輸給服務(wù)器
>>> payload = {'key1': 'value1', 'key2': 'value2'}>>> r = requests.post("http://httpbin.org/post", data=payload)作為 json 格式的字符串格式傳輸給服務(wù)器
>>> import json>>> url = 'http://httpbin.org/post'>>> payload = {'some': 'data'}>>> r = requests.post(url, json=payload)響應(yīng)內(nèi)容
HTTP返回的響應(yīng)消息中很重要的一部分內(nèi)容是響應(yīng)體,響應(yīng)體在 requests 中處理非常靈活,與響應(yīng)體相關(guān)的屬性有:content、text、json()。
content 是 byte 類型,適合直接將內(nèi)容保存到文件系統(tǒng)或者傳輸?shù)骄W(wǎng)絡(luò)中
>>> r = requests.get("https://pic1.zhimg.com/v2-2e92ebadb4a967829dcd7d05908ccab0_b.jpg")>>> type(r.content)<class 'bytes'># 另存為 test.jpg>>> with open("test.jpg", "wb") as f:... f.write(r.content)text 是 str 類型,比如一個普通的 HTML 頁面,需要對文本進(jìn)一步分析時,使用 text。
>>> r = requests.get("https://foofish.net/understand-http.html")>>> type(r.text)<class 'str'>>>> re.compile('xxx').findall(r.text)如果使用第三方開放平臺或者API接口爬取數(shù)據(jù)時,返回的內(nèi)容是json格式的數(shù)據(jù)時,那么可以直接使用json()方法返回一個經(jīng)過json.loads()處理后的對象。
>>> r = requests.get('https://www.v2ex.com/api/topics/hot.json')>>> r.json()[{'id': 352833, 'title': '在長沙,父母同住...代理設(shè)置
當(dāng)爬蟲頻繁地對服務(wù)器進(jìn)行抓取內(nèi)容時,很容易被服務(wù)器屏蔽掉,因此要想繼續(xù)順利的進(jìn)行爬取數(shù)據(jù),使用代理是明智的選擇。如果你想爬取墻外的數(shù)據(jù),同樣設(shè)置代理可以解決問題,requests 完美支持代理。這里我用的是本地 ShadowSocks 的代理,(socks協(xié)議的代理要這樣安裝 pip install requests[socks] )
import requestsproxies = { 'http': 'socks5://127.0.0.1:1080', 'https': 'socks5://127.0.0.1:1080',}requests.get('https://foofish.net', proxies=proxies, timeout=5)超時設(shè)置
requests 發(fā)送請求時,默認(rèn)請求下線程一直阻塞,直到有響應(yīng)返回才處理后面的邏輯。如果遇到服務(wù)器沒有響應(yīng)的情況時,問題就變得很嚴(yán)重了,它將導(dǎo)致整個應(yīng)用程序一直處于阻塞狀態(tài)而沒法處理其他請求。
>>> import requests>>> r = requests.get("http://www.google.coma")...一直阻塞中正確的方式的是給每個請求顯示地指定一個超時時間。
>>> r = requests.get("http://www.google.coma", timeout=5)5秒后報錯Traceback (most recent call last):socket.timeout: timed outSession
在python爬蟲入門教程--快速理解HTTP協(xié)議(一)中介紹過HTTP協(xié)議是一中無狀態(tài)的協(xié)議,為了維持客戶端與服務(wù)器之間的通信狀態(tài),使用 Cookie 技術(shù)使之保持雙方的通信狀態(tài)。
有些網(wǎng)頁是需要登錄才能進(jìn)行爬蟲操作的,而登錄的原理就是瀏覽器首次通過用戶名密碼登錄之后,服務(wù)器給客戶端發(fā)送一個隨機的Cookie,下次瀏覽器請求其它頁面時,就把剛才的 cookie 隨著請求一起發(fā)送給服務(wù)器,這樣服務(wù)器就知道該用戶已經(jīng)是登錄用戶。
import requests# 構(gòu)建會話session = requests.Session()# 登錄urlsession.post(login_url, data={username, password})# 登錄后才能訪問的urlr = session.get(home_url)session.close()構(gòu)建一個session會話之后,客戶端第一次發(fā)起請求登錄賬戶,服務(wù)器自動把cookie信息保存在session對象中,發(fā)起第二次請求時requests 自動把session中的cookie信息發(fā)送給服務(wù)器,使之保持通信狀態(tài)。
項目實戰(zhàn)
最后是一個實戰(zhàn)項目,如何用 requests 實現(xiàn)知乎自動登錄并給用戶發(fā)私信,我會在下一篇文章中進(jìn)行講解。
總結(jié)
好了,以上就是這篇文章的全部內(nèi)容,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對武林網(wǎng)的支持。
新聞熱點
疑難解答
圖片精選