Requests
python的request庫官方介紹就是讓HTTP服務人類,所以從這點我們就可以知道request庫是為了讓我們更加方便的進行http相關的各種操作
我們學習request有什么用呢?
1)web時代我們需要熟悉掌握web交互原理
2)爬蟲
3)服務器編程
4)自動化測試
實驗環境準備
首先是環境的準備,首先我們肯定要裝requests庫 直接使用pip命令即可(注意:本文使用的是py3.6版本)
同時我們需要一個服務器來測試我們的各種操作,我們可以直接使用requests庫作者寫的一個網站 httpbin.org 來進行我們的各種實驗操作
?requests例程
我們可以從下面的簡單的例程來簡單了解下requests
import requests #實驗web地址 http://httpbin.org url_ip='http://httpbin.org/ip' url_get='http://httpbin.org/get' #直接使用 def requests_simple(): #利用get方法得到一個response response1=requests.get(url_ip) #打印頭部headders print('Response Headers:',response1.headers) #打印Body print('Response Body:',response1.text) #帶參數的請求 def requests_params(): params_test={'param1':'hello','param2':'world'} #發送請求 response2=requests.get(url_get,params=params_test) #處理響應 #打印頭部headders print('Response Headers:', response2.headers) #打印Status Code print('Response Status Code',response2.status_code) # 打印Body 上面用到的是text 我們可以直接使用 .json()方法得到js格式 print('Response Body:', response2.json()) if __name__=='__main__': print('___________requests_simple方法____________') requests_simple() print('___________requests_params方法____________') requests_params()
看下輸出結果:
___________requests_simple方法____________ Response Headers: {'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Origin': '*', 'Content-Encoding': 'gzip', 'Content-Type': 'application/json', 'Date': 'Tue, 13 Aug 2019 08:21:40 GMT', 'Referrer-Policy': 'no-referrer-when-downgrade', 'Server': 'nginx', 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'DENY', 'X-XSS-Protection': '1; mode=block', 'Content-Length': '56', 'Connection': 'keep-alive'} Response Body: { "origin": "115.51.238.17, 115.51.238.17" } ___________requests_params方法____________ Response Headers: {'Access-Control-Allow-Credentials': 'true', 'Access-Control-Allow-Origin': '*', 'Content-Encoding': 'gzip', 'Content-Type': 'application/json', 'Date': 'Tue, 13 Aug 2019 08:21:41 GMT', 'Referrer-Policy': 'no-referrer-when-downgrade', 'Server': 'nginx', 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'DENY', 'X-XSS-Protection': '1; mode=block', 'Content-Length': '215', 'Connection': 'keep-alive'} Response Status Code 200 Response Body: {'args': {'param1': 'hello', 'param2': 'world'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.18.4'}, 'origin': '115.51.238.17, 115.51.238.17', 'url': 'https://httpbin.org/get?param1=hello¶m2=world'}
程序中每一步都有詳細注解,就不再贅述
?
Requests發送請求
請求方法:
- GET: 查看資源
- POST: 增加資源
- PUT: 修改資源
- PATCH: ? ?更新資源
- DELETE: 刪除資源
- HEAD: 查看響應頭
- OPTIONS: 查看可用請求方法
我們利用github提供的api接口來進行詳解 網址https://developer.github.com/v3
我們先來看下github上對于http請求方法的解釋
例程 使用github api接口查看某個用戶的公開信息
網址:https://developer.github.com/v3/users/
如圖中最后一行顯示,我們可以使用 GET /users/:username 來獲取信息 下面為代碼:
import requests import json url='https://api.github.com' #構建url函數 我們需要提交的url是原api網址加上我們自己額外添加的參數 # 所以簡單寫一個組成url的函數 即添加 '/' 號 def build_url(conend): return '/'.join([url,conend]) #更好的顯示返回json的打印參數 #我們從網頁得到的json可以使用下面函數來更好的print def better_jsprint(json_str): return json.dumps(json.loads(json_str),indent=4) #主體函數 get請求得到回應 例如我們查看用戶名為Test的公開資料 def requests_method(): response=requests.get(build_url('users/Test')) print(better_jsprint(response.text)) if __name__=="__main__": requests_method()
結果返回:
{ "login": "test", "id": 383316, "node_id": "MDQ6VXNlcjM4MzMxNg==", "avatar_url": "https://avatars3.githubusercontent.com/u/383316?v=4", "gravatar_id": "", "url": "https://api.github.com/users/test", "html_url": "https://github.com/test", "followers_url": "https://api.github.com/users/test/followers", "following_url": "https://api.github.com/users/test/following{/other_user}", "gists_url": "https://api.github.com/users/test/gists{/gist_id}", "starred_url": "https://api.github.com/users/test/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/test/subscriptions", "organizations_url": "https://api.github.com/users/test/orgs", "repos_url": "https://api.github.com/users/test/repos", "events_url": "https://api.github.com/users/test/events{/privacy}", "received_events_url": "https://api.github.com/users/test/received_events", "type": "User", "site_admin": false, "name": null, "company": null, "blog": "", "location": null, "email": null, "hireable": null, "bio": null, "public_repos": 5, "public_gists": 0, "followers": 23, "following": 0, "created_at": "2010-09-01T10:39:12Z", "updated_at": "2019-02-13T02:44:23Z" }
這樣我們就得到了名稱為Test的用戶的公開信息了
同樣的我們也可以使用githubapi文檔中的其他方法進行測試
?
帶參數的請求
首先來看常用的帶參數請求的三種方法
?
params參數請求例程:
還是使用github的api接口 這次我們使用下面這個提供的請求方法?
可以看到該方法中需要傳入 params參數 下面是程序代碼:
import requests import json url='https://api.github.com' #構建url函數 我們需要提交的url是原api網址加上我們自己額外添加的參數 # 所以簡單寫一個組成url的函數 即添加 '/' 號 def build_url(conend): return '/'.join([url,conend]) #更好的顯示返回json的打印參數 #我們從網頁得到的json可以使用下面函數來更好的print def better_jsprint(json_str): return json.dumps(json.loads(json_str),indent=4) #主體函數 添加params參數來進行請求 def requests_params(): response=requests.get(build_url('users'),params={'since':11}) #打印返回信息 print (better_jsprint(response.text)) #查看具體的url地址 print (response.url) if __name__=="__main__": requests_params()
返回結果很長就不再展示 只展示下此請求的url地址為?https://api.github.com/users?since=11
?
json參數請求例程
例程1 ?我們使用api中更新用戶信息的方法來測試json參數請求
下面為代碼:
import requests import json url='https://api.github.com' #構建url函數 我們需要提交的url是原api網址加上我們自己額外添加的參數 # 所以簡單寫一個組成url的函數 即添加 '/' 號 def build_url(conend): return '/'.join([url,conend]) #更好的顯示返回json的打印參數 #我們從網頁得到的json可以使用下面函數來更好的print def better_jsprint(json_str): return json.dumps(json.loads(json_str),indent=4) #主體函數 添加json參數來進行請求 下面代碼中的auth用來賬戶認證 即自己的賬戶密碼 def requests_json(): response=requests.patch(build_url('user'),auth=('此處為你的賬戶','此處為你的密碼'),json={'name':'此處為你想要改的名字'}) #打印返回信息 print (better_jsprint(response.text)) #查看具體的url地址 print (response.url) if __name__=="__main__": requests_json()
運行代碼之后 我們可以打開github主頁查看自己的賬戶名稱是否改變
例程2 ?使用post json參數請求添加一個email地址
代碼展示:
import requests import json url='https://api.github.com' #構建url函數 我們需要提交的url是原api網址加上我們自己額外添加的參數 # 所以簡單寫一個組成url的函數 即添加 '/' 號 def build_url(conend): return '/'.join([url,conend]) #更好的顯示返回json的打印參數 #我們從網頁得到的json可以使用下面函數來更好的print def better_jsprint(json_str): return json.dumps(json.loads(json_str),indent=4) #主體函數 添加json參數來進行請求 代碼中的auth參數為認證信息 即自己的github賬戶密碼 json參數傳入要添加的email地址 def requests_json(): response=requests.post(build_url('user/emails'),auth=('賬戶','密碼'),json=['test@qq.com']) #打印返回信息 print (better_jsprint(response.text)) #查看具體的url地址 print (response.url) if __name__=="__main__": requests_json()
返回內容:
[ { "email": "1231231230@qq.com", "primary": true, "verified": true, "visibility": "private" }, { "email": "32220+H3213@users.noreply.github.com", "primary": false, "verified": true, "visibility": null }, { "email": "test@qq.com", "primary": false, "verified": false, "visibility": null } ] https://api.github.com/user/emails
至此 我們已經完成了使用json參數進行請求
?
?請求異常處理
?我們都知道在互聯網上經常會出現很多錯誤,比如超時,更比如404之類的,當我們寫的程序遇到請求異常該如何處理呢?
我們以超時(Timeout)和HTTPERR為例寫出一個例程來分析:
首先錯誤都在requests包中的exceptions中 所以我們要引用:
from requests import exceptions
再例如對于timeout的設置有兩種方法:
- requests.get(url,timeout=(3,7))
- requests.get(url,timeout=10)
區別是什么呢? 我們都知道訪問一個網站是我們發送一個請求,然后網站給予我們一個響應,所以第一種方法中的3和7分別對應這兩個過程的超時時間限制,
第二種則是整個訪問過程的時間限制
timeout例程:
import requests import json from requests import exceptions url='https://api.github.com' #構建url函數 我們需要提交的url是原api網址加上我們自己額外添加的參數 # 所以簡單寫一個組成url的函數 即添加 '/' 號 def build_url(conend): return '/'.join([url,conend]) #更好的顯示返回json的打印參數 #我們從網頁得到的json可以使用下面函數來更好的print def better_jsprint(json_str): return json.dumps(json.loads(json_str),indent=4) #主體函數 添加timeout參數限制訪問時間,使用try except來捕獲錯誤并打印 def requests_err(): try: response=requests.get(build_url('user/emails'),timeout=0.1) except exceptions.Timeout as err: print(err) if __name__=="__main__": requests_err()
返回值:
HTTPSConnectionPool(host='api.github.com', port=443): Max retries exceeded with url: /user/emails (Caused by ConnectTimeoutError(, 'Connection to api.github.com timed out. (connect timeout=0.1)'))
httperror例程:
httperror例程中我們可以顯式拋出狀態值statuscode然后捕獲
import requests import json from requests import exceptions url='https://api.github.com' #構建url函數 我們需要提交的url是原api網址加上我們自己額外添加的參數 # 所以簡單寫一個組成url的函數 即添加 '/' 號 def build_url(conend): return '/'.join([url,conend]) #更好的顯示返回json的打印參數 #我們從網頁得到的json可以使用下面函數來更好的print def better_jsprint(json_str): return json.dumps(json.loads(json_str),indent=4) #主體函數 下列代碼中并未添加認證信息,所以狀態值不為200,我們需要raise出狀態值然后捕獲 def requests_err(): try: response=requests.get(build_url('user/emails')) response.raise_for_status() except exceptions.HTTPError as err: print(err) if __name__=="__main__": requests_err()
返回值:
401 Client Error: Unauthorized for url: https://api.github.com/user/emails
定制請求
我們可以自定義構造一些信息然后向目標網址發送來實現某些功能 比如爬蟲之類的 下面舉簡單的修改頭部信息
例程:
import requests #主體函數 在代碼中添加頭部信息來向目標網址發送自己定制請求 def requests_header(): response=requests.get('http://httpbin.org/get',headers={'User-Agent':'fake'}) print(response.text) if __name__=="__main__": requests_header()
看看返回信息:(http://httpbin.org/get 會返回我們的信息)
{ "args": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Host": "httpbin.org", "User-Agent": "fake" }, "origin": "115.51.238.17, 115.51.238.17", "url": "https://httpbin.org/get" }
注意看我們的頭部信息已經完成修改
?
響應的處理?
# 響應的常用屬性
response.text # 響應回去的文本(字符串)
response.content # 響應回去的內容(二進制),一般用來爬取視頻
response.status_code # 響應的狀態碼
response.url # 獲取請求連接地址
response.cookies # 獲取返回的cookies信息
response.cookies.get_dict() # 獲取返回的cookies信息
response.request # 獲取請求方式
response.headers # 查看響應頭
response.history # 重定向歷史 即前一次請求的地址
# 返回結果為json數據處理
response.json() # 將結果進行反序列化
# 爬取文檔亂碼問題
response.apparent_encoding # 文檔的編碼的方式(從HTML文檔找)
response.encoding # 響應體編碼方式
eg: response.encoding = response.apparent_encoding # 文檔的聲明方式
eg: print(response.text.encode('utf-8'))
?
注意:response.headers是服務器發送給我們的頭部信息,response.request.headers才是我們這個客服端向服務器發請求的頭部信息(即自己的信息)
?
下載文件
例如我們現在去網絡下載一張圖片,只不過現在我們使用requests庫來完成
就比如百度官網logo? 地址:https://www.baidu.com/img/bd_logo1.png
簡單的下載 例程 如下:
import requests url = ' https://www.baidu.com/img/bd_logo1.png ' def download_img(): response = requests.get(url) with open( ' logo.png ' , ' wb ' ) as img: #此步驟涉及文件讀寫操作 圖片是二進制,所以要用二進制寫文件 用參數 'wb' img.write(response.content) if __name__ == ' __main__ ' : download_img()
然后會發現當前目錄下出現了 logo.png的圖片? 此時已經下載成功
需要注意的是? 有時候文件很大,我們需要以數據流的方式讀寫,否則可能造成內存溢出問題,
當下載大的文件的時候,我們可以在requests.get()中使用stream參數.
默認情況下是false,他會立即開始下載文件并存放到內存當中,倘若文件過大就會導致內存不足的情況.
當把get函數的stream參數設置成True時,它不會立即開始下載,當你使用iter_content或iter_lines遍歷內容或訪問內容屬性時才開始下載。需要注意一點:文件沒有下載之前,它也需要保持連接。
- iter_content:一塊一塊的遍歷要下載的內容
- iter_lines:一行一行的遍歷要下載的內容
使用上面兩個函數下載大文件可以防止占用過多的內存,因為每次只下載小部分數據。
例程:
import requests url = ' https://www.baidu.com/img/bd_logo1.png ' def download_img(): response =requests.get(url,stream=True) # stream參數記得選為True with open( ' logo.png ' , ' wb ' ) as img: # 圖片是二進制,所以要用二進制寫文件 用參數 'wb' for chunk in response.iter_content(1024): # 規定一次讀取寫入大小 單位為字節 img.write(chunk) response.close() # 關閉數據流連接 if __name__ == ' __main__ ' : download_img()
有時候會被服務器禁止請求,原因可能是user-agent未更改,這就相當于簡單的反爬蟲了,所以一般我們寫爬蟲的時候需要修改user-agent信息,這些問題在講解爬蟲時會講
簡單 總結流程 就是:
瀏覽器模擬(修改headers)-->構建request-->讀取數據-->寫入數據
?
身份認證
auth
前面已經講過,我們可以傳入 auth 參數來將自己的賬號密碼傳入目標網址來進行身份驗證,可是這種方式是安全的嗎?
例如:
import requests url = ' https://api.github.com ' # 構建url函數 我們需要提交的url是原api網址加上我們自己額外添加的參數 # 所以簡單寫一個組成url的函數 即添加 '/' 號 def build_url(conend): return ' / ' .join([url,conend]) # 基礎身份認證 def http_auth(): response =requests.get(build_url( ' user ' ),auth=( ' test ' , ' test123 ' )) # 看下我們的請求的頭部數據 print (response.request.headers) http_auth()
我們再看下返回頭部數據:
{ ' User-Agent ' : ' python-requests/2.18.4 ' , ' Accept-Encoding ' : ' gzip, deflate ' , ' Accept ' : ' */* ' , ' Connection ' : ' keep-alive ' , ' Authorization ' : ' Basic dGVzdDp0ZXN0MTIz ' }
我們發現里面含有?'Authorization': 'Basic dGVzdDp0ZXN0MTIz' 一段 那這個會是我們的賬號密碼嗎? 我們使用解碼來看下
import base64 print (base64.b64decode( ' dGVzdDp0ZXN0MTIz ' ))
輸出:
b ' test:test123 '
發現還真的是我們的賬號密碼,所以這樣也不是很安全
因此現在廣泛使用更安全的Oauth認證
OAuth
oauth是Open Authorization的簡寫,oauth協議為用戶資源的授權提供了一個安全的、開放而又建議的標準。第三方無需使用用戶的用戶名與密碼就可以申請獲得該用戶資源的授權,因此oauth是安全的。
最最簡單的例子就是 現在我們登錄多個網站(例如微博,網盤等)應用可以直接選擇QQ快速登錄,這就是OAuth認證,它無需你輸入賬戶密碼即可認證
?
下面我們還是用github的api來做一個簡單的oauth認證??
首先打開github網址:https://github.com/settings/tokens/new?來申請一個自己的令牌認證 記得勾選需要的權限選項
然后我們就得到了一串神秘代碼如下圖
接下來我們開始寫簡單的例程:
import requests url = ' https://api.github.com ' # 構建url函數 我們需要提交的url是原api網址加上我們自己額外添加的參數 # 所以簡單寫一個組成url的函數 即添加 '/' 號 def build_url(conend): return ' / ' .join([url,conend]) # 基礎oauth認證 def http_oauth(): # 構建頭部數據 加上token信息 header={ ' Authorization ' : ' token 62646e55689b597eb076cb08c5e020e3762bc84f ' } response =requests.get(build_url( ' user ' ),headers= header) print (response.text) http_oauth()
運行發現登錄成功? 雖然這是個個人身份令牌 但是oauth原理也是如此
?
Cookie 和?Session
Cookie,有時也用其復數形式?Cookies,指某些網站為了辨別用戶身份、進行 session 跟蹤而儲存在用戶本地終端上的數據(通常經過加密)。
這樣做的好處就是cookie的體積變小,只存儲session-id信息類似于上面講的token,并且session信息存儲在服務器端也比較安全
?
至此,requests庫的學習就先告一段落,但是哦我們還有更多高階操作可以去學習。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
