這個總結主要是結合慕課網的視頻和自己查資料總結而成
什么是Requests庫?
requests庫github地址:https://github.com/requests/requests
Reqyests庫主要用來准備Request和處理Response。
為什么要學習Requests庫?
web開發和爬蟲都需要學習的東西,在服務端編程中理解好Requests庫可以更好的編寫Restful API的程序,還是自動化測試的工具箱。
安裝Requests庫
pip install requests
這個是安裝requests庫的
pip install gunicorn
gunicorn是一個python Wsgi http server,只支持在Unix系統上運行,來源於Ruby的unicorn項目。
pip install httpbin
httpbin是一個http庫的測試工具
gunicorn httpbin:app
通過gunicorn啟動httpbin,可以通過127.0.0.1/8000訪問
簡單了解http協議
http協議:HyperText Transfer Protocl 超文本傳輸協議.
http協議是應用層上的一個無狀態的協議,是一種為分布式,協作式,多媒體信息服務的協議。
> GET / HTTP/1.1 > Host: www.imooc.com > User-Agent: curl/7.47.0 > Accept: */*
Request:
第一行:分別是方法:GET,地址:/,協議:HTTP/1.1。
二三四行以key:value的形式組成headers。
< HTTP/1.1 200 OK < Server: nginx < Date: Sun, 16 Sep 2018 14:36:46 GMT < Content-Type: text/html; charset=utf-8 < Content-Length: 249314 < Connection: keep-alive < Vary: Accept-Encoding < Vary: Accept-Encoding < X-Varnish: 636943726 641514266 < Age: 20 < Via: 1.1 varnish (Varnish/6.0) < X-Cache: HIT from CS42 < Accept-Ranges: bytes
Response:
start line:狀態碼,具體解釋
后面的也是組成一個headers,告訴瀏覽器怎么具體解析
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>慕課網-程序員的夢工廠</title> <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1"> <meta name="renderer" content="webkit" /> <meta name="mobile-agent" content="format=wml"; url="https://m.imooc.com/"> <link rel="alternate" media="only screen and (max-width: 640px)" href="https://m.imooc.com/"> <meta name="mobile-agent" content="format=xhtml"; url="https://m.imooc.com/"> <meta name="mobile-agent" content="format=html5"; url="https://m.imooc.com/"> <meta property="qc:admins" content="77103107776157736375" /> <meta property="wb:webmaster" content="c4f857219bfae3cb" /> <meta http-equiv="Access-Control-Allow-Origin" content="*" /> <meta http-equiv="Cache-Control" content="no-transform " /> <meta http-equiv="Cache-Control" content="no-siteapp" /> <link rel="dns-prefetch" href="//www.imooc.com" /> <link rel="dns-prefetch" href="//img.imooc.com" /> <link rel="dns-prefetch" href="//img.mukewang.com" /> <link rel="apple-touch-icon" sizes="76x76" href="/static/img/common/touch-icon-ipad.png"> <link rel="apple-touch-icon" sizes="120x120" href="/static/img/common/touch-icon-iphone-retina.png"> <link rel="apple-touch-icon" sizes="152x152" href="/static/img/common/touch-icon-ipad-retina.png"> <meta name="Keywords" content="" /> <meta name="Description" content="慕課網(IMOOC)是IT技能學習平台。慕課網(IMOOC)提供了豐富的移動端開發、php開發、web前端、android開發以及html5等視頻教程資源公開課。並且富有交互性及趣味性,你還可以和朋友一起編程。" />
Message Body
urllib
urllib和urllib2是相互獨立的模塊,在使用的時候需要兩個結合使用
requests庫使用了urllib3,urllib3則多了一些功能,比如多次請求重復使用一個socket,提升效率。
# _*_ coding: utf-8 _*_ import urllib2 import urllib URL_IP = 'http://127.0.0.1:8000/ip' URL_GET = 'http://127.0.0.1:8000/get' def use_simple_urllib2(): response = urllib2.urlopen(URL_IP) print '>>>>Response Headers:' print response.info() print '>>>>Response Body:' print ''.join([line for line in response.readlines()]) def use_params_urllib2(): #構建請求參數 params = urllib.urlencode({'param1':'hello', 'param2':'world'}) print 'Request Params:' print params #發送請求 response = urllib2.urlopen('?'.join([URL_GET, '%s'])%params) #處理響應 print '>>>>Response Headers:' print response.info() print '>>>>Status Code:' print response.getcode() print '>>>>Response Body:' print ''.join([line for line in response.readlines()]) if __name__ == '__main__': print '>>>>Use simple urllib2:' use_simple_urllib2() print '>>>>Use params urllib2:' use_params_urllib2()
先啟動gunicorn,然后運行上面的程序,
>>>>Use simple urllib2: >>>>Response Headers: Server: gunicorn/19.9.0 Date: Mon, 17 Sep 2018 03:18:04 GMT Connection: close Content-Type: application/json Content-Length: 23 Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true >>>>Response Body: {"origin":"127.0.0.1"} >>>>Use params urllib2: Request Params: param2=world¶m1=hello >>>>Response Headers: Server: gunicorn/19.9.0 Date: Mon, 17 Sep 2018 03:18:04 GMT Connection: close Content-Type: application/json Content-Length: 245 Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true >>>>Status Code: >>>>Response Body: {"args":{"param1":"hello","param2":"world"},"headers":{"Accept-Encoding":"identity","Connection":"close","Host":"127.0.0.1:8000","User-Agent":"Python-urllib/2.7"},"origin":"127.0.0.1","url":"http://127.0.0.1:8000/get?param2=world¶m1=hello"} View result
可以得到上面的結果
urllib提供了一系列功能可以對URL進行操作,利用程序去執行各種http請求
簡單使用requests

#-*- coding: utf-8 -*- import requests URL_IP = 'http://127.0.0.1:8000/get' def use_simple_requests(): response = requests.get(URL_IP) print '>>>>Response Headers:' print response.headers print '>>>>Response Body:' print response.text def use_params_requests(): params = {'param1':'hello', 'param2':'world'} #發送請求 response = requests.get(URL_IP,params=params) #處理響應 print '>>>>Response Headers:' print response.headers print '>>>>Status Code:' print response.status_code print '>>>>Response Body:' print response.json() if __name__ == '__main__': print '>>>>Use simple requests:' use_simple_requests() print '>>>>Use params requests' use_params_requests()
下面的是結果
>>>>Use simple requests:
>>>>Response Headers:
{'Content-Length': '216', 'Server': 'gunicorn/19.9.0', 'Connection': 'close', 'Access-Control-Allow-Credentials': 'true', 'Date': 'Mon, 17 Sep 2018 07:34:49 GMT', 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json'}
>>>>Response Body:
{"args":{},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"keep-alive","Host":"127.0.0.1:8000","User-Agent":"python-requests/2.19.1"},"origin":"127.0.0.1","url":"http://127.0.0.1:8000/get"}
>>>>Use params requests
>>>>Response Headers:
{'Content-Length': '275', 'Server': 'gunicorn/19.9.0', 'Connection': 'close', 'Access-Control-Allow-Credentials': 'true', 'Date': 'Mon, 17 Sep 2018 07:34:49 GMT', 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json'}
>>>>Status Code:
200
>>>>Response Body:
{u'origin': u'127.0.0.1', u'headers': {u'Connection': u'keep-alive', u'Host': u'127.0.0.1:8000', u'Accept-Encoding': u'gzip, deflate', u'Accept': u'*/*', u'User-Agent': u'python-requests/2.19.1'}, u'args': {u'param2': u'world', u'param1': u'hello'}, u'url': u'http://127.0.0.1:8000/get?param2=world¶m1=hello'}
以上就是一個簡單的使用
requests庫是用python實現的一個http庫,使用起來要比urllib簡單很多
對比requests和urllib的header可以發現,urllib的connection的狀態是close,而requests的則是keep-alive,這是因為requests使用了urllib3,可以保持住連接,多次請求時可以減少資源的消耗,而urllib則是獲取到消息后就關閉連接,再次需要獲取時還需要再次建立,requests還支持更多的encoding格式
請求方法
GET:查看資源
POST:增加資源
PUT:修改資源
PATCH:更新部分資源
DELETE:刪除資源
HEAD:查看響應頭
OPTIONS:查看可用請求方法
使用方法:requests.[method](url)
帶參數的請求
1.URL參數
使用方法:requests.get(url,params={'key1':'value1})
2.表單參數提交
Content-Type:application.x-www-form-urlencoded (表單默認的提交數據格式)
內容:key1=value1&key2=value2
requests.post(url,data={'key1':'value1','key2':'value2'})
3.json參數提交
Content-Type: appliction/json (json數據格式)
內容:'{"key":"value1","key2":"value2"}'
requests.post(url,json={'key1':'value1','key2':'value2'})
請求異常處理
requests庫將常見的http錯誤打了一個包,就是exceptions,通過使用exceptions可以處理項目中各種異常
RequestException:
HTTPError(RequestException)
UnrewindableBodyError(RequestException)
RetryError(RequestException)
ConnectionError(RequestException) ProxyError(ConnectionError)
SSLError(ConnectionError)
ConnectTimeout(ConnectionError, Timeout)
Timeout(RequestException) ReadTimeout
URLRequired(RequestException)
TooManyRedirects(RequestException)
MissingSchema(RequestException, ValueError)
InvalidSchema(RequestException,ValueError)
InvalidURL(RequestException,ValueError)
InvalidHeader(RequestException,ValueError)
ChunkedEncodingError(RequestException)
StreamConsumedError(RequestException,TypeError)
ContentDecodingError(RequestException,BaseHTTPError)
常見的異常處理如上:
自定義Request
Session:包括代理信息(proxy),超時信息(timeout),驗證信息等
PreparedRequest:在session中定義的另一個對象,包括消息主體(body),消息頭部(headers),認證信息(auth)
Response:Request對象發出后,會獲得一個Response對象,包括text,json等信息
處理響應
http狀態碼:
1xx:消息
100 Continue:客戶端應當繼續發送請求。這個臨時響應是用來通知客戶端它的部分請求已經被服務器接收,且仍未被拒絕。客戶端應當繼續發送請求的剩余部分,或者如果請求已經完成,忽略這個響應。服務器必須在請求完成后向客戶端發送一個最終響應。
2xx:成功
200 OK:請求已成功,請求所希望的響應頭或數據體將隨此響應返回。
202 Accepted:服務器已接受請求,但尚未處理。正如它可能被拒絕一樣,最終該請求可能會也可能不會被執行。在異步操作的場合下,沒有比發送這個狀態碼更方便的做法了。
返回202狀態碼的響應的目的是允許服務器接受其他過程的請求(例如某個每天只執行一次的基於批處理的操作),而不必讓客戶端一直保持與服務器的連接直到批處理操作全部完成。在接受請求處理並返回202狀態碼的響應應當在返回的實體中包含一些指示處理當前狀態的信息,以及指向處理狀態監視器或狀態預測的指針,以便用戶能夠估計操作是否已經完成。
3xx:重定向
301 Moved Permanently:被請求的資源已永久移動到新位置,並且將來任何對此資源的引用都應該使用本響應返回的若干個URI之一。如果可能,擁有鏈接編輯功能的客戶端應當自動把請求的地址修改為從服務器反饋回來的地址。除非額外指定,否則這個響應也是可緩存的。新的永久性的URI應當在響應的Location域中返回。除非這是一個HEAD請求,否則響應的實體中應當包含指向新的URI的超鏈接及簡短說明。如果這不是一個GET或者HEAD請求,因此瀏覽器禁止自動進行重定向,除非得到用戶的確認,因為請求的條件可能因此發生變化。
注意:對於某些使用HTTP/1.0協議的瀏覽器,當它們發送的POST請求得到了一個301響應的話,接下來的重定向請求將會變成GET方式。
4xx:客戶端錯誤
403 Forbidden:服務器已經理解請求,但是拒絕執行它。與401響應不同的是,身份驗證並不能提供任何幫助,而且這個請求也不應該被重復提交。如果這不是一個HEAD請求,而且服務器希望能夠講清楚為何請求不能被執行,那么就應該在實體內描述拒絕的原因。當然服務器也可以返回一個404響應,假如它不希望讓客戶端獲得任何信息。
404 Not Found:請求失敗,請求所希望得到的資源未被在服務器上發現。沒有信息能夠告訴用戶這個狀況到底是暫時的還是永久的。假如服務器知道情況的話,應當使用410狀態碼來告知舊資源因為某些內部的配置機制問題,已經永久的不可用,而且沒有任何可以跳轉的地址。404這個狀態碼被廣泛應用於當服務器不想揭示到底為何請求被拒絕或者沒有其他適合的響應可用的情況下。
5xx:服務器錯誤
500 Internal Server Error:服務器遇到了一個未曾預料的狀況,導致了它無法完成對請求的處理。一般來說,這個問題都會在服務器的程序碼出錯時出現。
Response對象api:status_code(狀態碼),reason(狀態碼信息),headers(消息頭部信息),url(來自的url),history(查看歷史狀況,從哪里跳轉到哪里),elapsed(請求耗費的時間)。
ecoding(編碼格式),raw(直接讀取原始的response對象),content(string格式),text(這個是轉換過的,unicode格式),json(方便獲取信息)。
下載圖片
利用簡單的爬蟲下載目標圖片

# -*- coding: utf-8 -*- import requests def download_image(): """ demo:下載圖片 :return: """ # 偽造headers信息 headers = {'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linu…) Gecko/20100101 Firefox/62.0'} # 限定url url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1537271716866&di=ce23d74908c86b8450dfb1ddf397c748&imgtype=jpg&src=http%3A%2F%2Fimg0.imgtn.bdimg.com%2Fit%2Fu%3D2410671045%2C2907191728%26fm%3D214%26gp%3D0.jpg" response = requests.get(url, headers=headers, stream=True) from contextlib import closing with closing(requests.get(url, headers=headers, stream=True)) as response: #打開文件 with open('demo.jpg', 'wb') as fd: #每128寫入一次 for chunk in response.iter_content(128): fd.write(chunk) if __name__ == '__main__': download_image()
流程是首先要模擬瀏覽器,通過開發者工具中User-Agent模擬,然后構建一個request對象,再讀取流data,最后新建文件存入數據
事件鈎子(Event Hooks)
Requests庫線性處理
先發出一個IO請求,如GET,POST等,和服務器交互后返回,事件鈎子會將Response塞入到回調處理中

#-*- coding: utf-8 -*- import requests def get_key_info(response, *args, **kwargs): """ 回調參數 :return: """ print response.headers['Content-Type'] if __name__ == '__main__': requests.get('https://api.github.com', hooks=dict(response=get_key_info))
運行結果:
application/json; charset=utf-8
HTTP認證
比較簡單的認證:客戶端發送一個requests要獲取一個被保護的資源,Server端要求客戶端提供賬號和密碼,客戶端接着發送用戶名和密碼,服務端驗證用戶名和密碼驗證通過返回需要的資源

# -*- coding: utf-8 -*- import requests BASE_URL = 'https://api.github.com' def construct_url(end_point): return '/'.join([BASE_URL, end_point]) def basic_auth(): """ 基本認證 """ response = requests.get(construct_url('user'), auth=('imoocdemo', 'imoocdemo123')) print response.text print response.request.headers if __name__ == '__main__': basic_auth()
{"login":"imoocdemo","id":20262371,"node_id":"MDQ6VXNlcjIwMjYyMzcx","avatar_url":"https://avatars0.githubusercontent.com/u/20262371?v=4","gravatar_id":"","url":"https://api.github.com/users/imoocdemo","html_url":"https://github.com/imoocdemo","followers_url":"https://api.github.com/users/imoocdemo/followers","following_url":"https://api.github.com/users/imoocdemo/following{/other_user}","gists_url":"https://api.github.com/users/imoocdemo/gists{/gist_id}","starred_url":"https://api.github.com/users/imoocdemo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/imoocdemo/subscriptions","organizations_url":"https://api.github.com/users/imoocdemo/orgs","repos_url":"https://api.github.com/users/imoocdemo/repos","events_url":"https://api.github.com/users/imoocdemo/events{/privacy}","received_events_url":"https://api.github.com/users/imoocdemo/received_events","type":"User","site_admin":false,"name":"babymooc2","company":"尖峰科技","blog":"http://2333.org","location":"aufe-xx","email":null,"hireable":true,"bio":"future is now","public_repos":1,"public_gists":0,"followers":1,"following":1,"created_at":"2016-07-03T03:12:42Z","updated_at":"2018-08-24T08:12:37Z","private_gists":1,"total_private_repos":0,"owned_private_repos":0,"disk_usage":0,"collaborators":0,"two_factor_authentication":false,"plan":{"name":"free","space":976562499,"collaborators":0,"private_repos":0}} {'Authorization': 'Basic aW1vb2NkZW1vOmltb29jZGVtbzEyMw==', 'Connection': 'keep-alive', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'User-Agent': 'python-requests/2.19.1'}
OAUTH認證:用戶打開客戶端頁面,客戶端請求用戶的授權,用戶確認以后會向客戶端返回一個含有code的url,客戶端會截取其中的code,向獲取授權的服務器發起一個POST請求,要求獲取access_token,授權服務器認證以后,會返回一個access_token,然后客戶端會用這個access_token向資源服務器獲取資源,資源服務器返回受保護的資源.這個過程客戶端是一直沒有接觸到用戶的用戶名和密碼的,比較安全。
代理Proxy
代理就是一個中間人,客戶端和proxy(充當服務端)建立連接,proxy就負責將客戶端請求發送到外網,再將返回的信息發送給客戶端
Session和Cookie
Session是保存在服務端的用戶信息,cookie是保存在瀏覽器的用戶信息。
瀏覽器向服務器發出一個http請求(是無cookie的),服務器認證后會發回一個http響應(set cookie),服務這時是可以設置cookie有效期,權限范圍等。瀏覽器獲取cookie后會解析並保存再本地,之后瀏覽器的http請求都會帶上cookie,服務器則直接解析cookie,識別地址,確認后http響應。
瀏覽器向服務器發出一個http請求(是無cookie的),服務器認證后會建立一個會話,存儲session,接着發回一個http響應(set cookie-session-id),客戶端接收http響應,解析cookie保存再本地,這個解析出來的東西很小,只有一個session-id,瀏覽器發起帶cookie的http請求,服務器收到后解析獲取到其中的session-id,然后在存儲中查對應的用戶信息權限等,然后再傳回一個http響應。