一:requests模塊簡介
requests是使用Apache2 licensed 許可證的HTTP庫。
用python編寫。
比urllib2模塊更簡潔。
Request支持HTTP連接保持和連接池,支持使用cookie保持會話,支持文件上傳,支持自動響應內容的編碼,支持國際化的URL和POST數據自動編碼。
在python內置模塊的基礎上進行了高度的封裝,從而使得python進行網絡請求時,變得人性化,使用Requests可以輕而易舉的完成瀏覽器可有的任何操作。
現代,國際化,友好。
requests會自動實現持久連接keep-alive
中文文檔 API: https://docs.python-requests.org/zh_CN/latest/index.html
二:requests基礎入門
2.1 requests安裝
pip install requests
2.1.1HTTP 請求類型:PUT,DELETE,HEAD 以及 OPTIONS如下
requests.get(‘https://github.com/timeline.json’) # GET請求 requests.post(“http://httpbin.org/post”) # POST請求 requests.put(“http://httpbin.org/put”,data = {'key':'value'}) # PUT請求 requests.delete(“http://httpbin.org/delete”) # DELETE請求 requests.head(“http://httpbin.org/get”) # HEAD請求 requests.options(“http://httpbin.org/get” ) # OPTIONS請求
2.2 GET基本請求(headers和params參數)
2.2.1 最基本的GET請求可以直接用get方法
import requests #第一種寫法 response = requests.get("http://www.baidu.com/") #第二中寫法 response = requests.request('get',"http://www.baidu.com/")
2.2.2 添加headders 和查詢參數 params
import request header = {"user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36"} formdata = {'key1': 'value1', 'key2': 'value2'} # params 接收一個字典或者字符串的查詢參數,字典類型自動轉換為url編碼,不需要urlencode() response = requests.get('http://httpbin.org/get',headers=header,params=formdata) # 獲取當前的編碼 print(response.encoding) # 獲取當前的編碼 print(response.status_code) # 以字典對象存儲服務器響應頭,但是這個字典比較特殊,字典鍵不區分大小寫,若鍵不存在則返回None print(response.headers) # 以字典對象存儲請求頭 print(response.request.headers) # 查看完整url地址 print(response.url) # 以encoding解析返回內容。字符串方式的響應體,會自動根據響應頭部的字符編碼進行解碼。 print(response.text) # 以字節形式(二進制)返回。字節方式的響應體,會自動為你解碼 gzip 和 deflate 壓縮。 print(response.content) # Requests中內置的JSON解碼器,返回的數據類型是字典(dict),以json形式返回,前提返回的內容確保是json格式的,不然解析出錯會拋異常 print(response.json())
執行結果:

響應信息總結;response.encoding #獲取當前的編碼
response.encoding = 'utf-8' #設置編碼 response.text #以encoding解析返回內容。字符串方式的響應體,會自動根據響應頭部的字符編碼進行解碼。 response.content #以字節形式(二進制)返回。字節方式的響應體,會自動為你解碼 gzip 和 deflate 壓縮。 response.headers #以字典對象存儲服務器響應頭,但是這個字典比較特殊,字典鍵不區分大小寫,若鍵不存在則返回None response.request.headers #返回請求的頭部信息 response.status_code #響應狀態碼 response.raw #返回原始響應體,也就是 urllib 的 response 對象,使用 r.raw.read() response.ok # 查看r.ok的布爾值便可以知道是否登陸成功 #*特殊方法*# response.json() #Requests中內置的JSON解碼器,以json形式返回,前提返回的內容確保是json格式的,不然解析出錯會拋異常 response.raise_for_status() #失敗請求(非200響應)拋出異常 無異常時返回None
response.cookies #返回cookie
response.history #返回重定向信息,當然可以在請求是加上allow_redirects = false 阻止重定向
使用response.text 時,Requests 會基於 HTTP 響應的文本編碼自動解碼響應內容,大多數 Unicode 字符集都能被無縫地解碼。 使用response.content 時,返回的是服務器響應數據的原始二進制字節流,可以用來保存圖片等二進制文件。 例子如下: from PIL import Image from io import BytesIO i = Image.open(BytesIO(r.content))
2.2.3 返回數據response.json()
import requests def get_token(): url = 'https://api.weixin.qq.com/cgi-bin/token' params = { "grant_type": "client_credential", "appid": "wx74a8627810cfa308", "secret": "e40a02f9d79a8097df497e6aaf93ab80" } resp = requests.get(url,params=params) print(resp.json()) print(type(resp.json()))
if __name == "__main__":
get_token()
#使用resp.json()的前提是返回的數據必須是json格式 否則會報錯,使用resp.json()會自動把json格式的數據進行轉換成字典(dict)類型 ''' {'access_token': '55_8NJ3YufGIpqwspICjxsNe7bolni2uFLvo2Qb1dwI7JLm-BgrEALq_nsrA0b1j_94mev_y0g7k6QSV4TpxKG3liqc4ntKxWlTqcQyFbcocY8LauzZc-YCExzVG7C-s6ZoqJxZhYY1_vTph4wySVMgAHAHKB', 'expires_in': 7200} <class 'dict'> '''
2.3 POST基本請求
2.3.1 最基本的post請求可以直接使用post
#第一種寫法 response = requests.post('http://httpbin.org/post') #第二種寫法 response = requests.request('post', 'http://httpbin.org/post')
2.3.2 傳入參數 data
1)傳入的參數data為字典類型或者是元組類型
#傳入字典類型的 payload = {'key1': 'value1', 'key2': 'value2'} response = requests.post("http://httpbin.org/post", data=payload) print(response.text) #執行結果: { ... "form": { "key2": "value2", "key1": "value1" }, ... } # 傳入元組類型的 payload = (('key1', 'value1'), ('key1', 'value2')) response = requests.post("http://httpbin.org/post", data=payload) print(response.text) #執行結果: { ... "form": { "key1": [ "value1", "value2" ] } }
2)參數data是json格式
import json #第一種使用data參數 然后使用json.dumps()進行轉換成json格式 url = 'https://api.github.com/some/endpoint' formdata = {'some': 'data'} response = requests.post(url, data=json.dumps(formdata)) print(response.text) #第二種 使用 json 參數直接傳遞,然后它就會被自動編碼 response = requests.post(url, json=formdata) print(response.text)
3)參數data是文件格式
url = 'http://httpbin.org/post' files = {'file': open('report.xls', 'rb')} response = requests.post(url, files=files) print(response.text) #執行結果: { ... "files": { "file": "<censored...binary...data>" }, ... }
4)參數data為XML格式
headers = {'Content-type': 'text/xml'}
XML = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><Request xmlns="http://tempuri.org/"><jme><JobClassFullName>WeChatJSTicket.JobWS.Job.JobRefreshTicket,WeChatJSTicket.JobWS</JobClassFullName><Action>RUN</Action><Param>1</Param><HostIP>127.0.0.1</HostIP><JobInfo>1</JobInfo><NeedParallel>false</NeedParallel></jme></Request></soap:Body></soap:Envelope>'
url = 'http://jobws.push.mobile.xxxxxxxx.com/RefreshWeiXInTokenJob/RefreshService.asmx'
response = requests.post(url, headers=headers, data=XML)
print(response.text)
5)參數data為form-data
會將表單的數據處理為一條消息,以標簽為單元,用分隔符分開。既可以上傳鍵值對,也可以上傳文件。當上傳的字段是文件時,會有Content-Type來說明文件類型;content-disposition,用來說明字段的一些信息

問題:
對接接口,發現對方的接口使用form-data進行數據提交,直接使用requests庫的data參數對接,會報參數錯誤:
params = { 'timestamp':timestamp, 'nonce':nonce, 'apikey':APIKEY, 'signature': signature } data = { 'name': name, 'phone': phone, 'idnum': idnum, 'products': [201,] } resp = requests.post(URL, data=data, params=params,verify=False, timeout=10)
執行結果:

解決方案:
這一塊Requests包做的不是很好,做法具體如下:
一種是手動組建form-data並加上headers;
另一種是通過files參數傳遞form-datal;
# 方案一: params = { 'timestamp':timestamp, 'nonce':nonce, 'apikey':APIKEY, 'signature': signature } payload = """------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"phone\"\n\n{}\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"idnum\"\n\n{}\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\n{}\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"products\"\r\n\r\n {}\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--""".format(phone, idnum, name, [201,]) headers = { "content-type": "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW" } resp = requests.post(URL, data=payload, params=params, verify=False, timeout=10, headers=headers) # 方案二(推薦使用): import json params = { 'timestamp':timestamp, 'nonce':nonce, 'apikey':APIKEY, 'signature': signature } data = { 'name':(None, name), 'phone': (None, str(phone)), 'idnum': (None, idnum), 'products': (None, json.dumps([201,])) } resp = requests.post(URL, files=data, params=params, verify=False, timeout=10) print resp.status_code print resp.request.url print resp.request.body print resp.text
2.4 重定向和請求歷史
默認情況下,除了 HEAD, Requests 會自動處理所有重定向。可以使用響應對象的 history 方法來追蹤重定向。
Response.history是一個 Response對象的列表,為了完成請求而創建了這些對象。這個對象列表按照從最老到最近的請求進行排序。
2.4.1 allow_redirects 參數
#allow_redirects =False 禁止重定向 response = requests.get('http://github.com', allow_redirects=False) print(response.url) http://github.com print(response.status_code) 301 print(response.history) [] #allow_redirects =True 開啟重定向(默認是開啟的) response = requests.get('http://github.com', allow_redirects=False) print(response.url) https://github.com/ print(response.status_code) 200 print(response.history) [<Response [301]>]
2.5 代理(proxies參數)
如果需要使用代理,你可以通過為任意請求方法提供 proxies 參數來配置單個請求:
import requests # 根據協議類型,選擇不同的代理 proxies = { "http": "http://12.34.56.79:9527", "https": "http://12.34.56.79:9527", } response = requests.get("http://www.baidu.com", proxies = proxies) print(response.text) # 如果代理需要使用HTTP Basic Auth,可以使用下面這種格式: proxy = { "http": "mr_mao_hacker:sffqry9r@61.158.163.130:16816" } response = requests.get("http://www.baidu.com", proxies = proxy) print(response.text)
2.6 Cookies和Session
2.6.1 Cookies
1)傳入cookies參數
url = 'http://httpbin.org/cookies' #傳入cookies類型為字典類型 cookies = dict(cookies_are='working') response= requests.get(url, cookies=cookies) print(response.text) #執行結果 '{"cookies": {"cookies_are": "working"}}' #傳入cookies的類型為CookieJar jar = requests.cookies.RequestsCookieJar() jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies') url = 'http://httpbin.org/cookies' response = requests.get(url, cookies=jar) print(response.text) #執行結果: {"cookies": {"tasty_cookie": "yum"}}'
2)獲取返回的cookies
import requests response = requests.get("http://www.baidu.com/") # 1. 返回CookieJar對象: cookiejar = response.cookies # 2. 將CookieJar轉為字典: cookiedict = requests.utils.dict_from_cookiejar(cookiejar) print(cookiejar) #<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]> print(cookiedict) #{'BDORZ': '27315'}
2.6.2 Session
在 requests 里,session對象是一個非常常用的對象,這個對象代表一次用戶會話:從客戶端瀏覽器連接服務器開始,到客戶端瀏覽器與服務器斷開。
會話能讓我們在跨請求時候保持某些參數,比如在同一個 Session 實例發出的所有請求之間保持 cookie 。
import requests # 1. 創建session對象,可以保存Cookie值 ssion = requests.session() # 2. 處理 headers headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"}
ssion.headers.update(headers)#更新頭部信息
# 3. 需要登錄的用戶名和密碼 data = {"email":"mr_mao_hacker@163.com", "password":"alarmchime"} # 4. 發送附帶用戶名和密碼的請求,並獲取登錄后的Cookie值,保存在ssion里 ssion.post("http://www.renren.com/PLogin.do", data = data) # 5. ssion包含用戶登錄后的Cookie值,可以直接訪問那些登錄后才可以訪問的頁面 response = ssion.get("http://www.renren.com/410043129/profile") # 6. 打印響應內容 print(response.text)
執行結果:

2.7 SSL證書驗證
2.7.1 HTTPS 請求驗證 SSL 證書
Requests 可以為 HTTPS 請求驗證 SSL 證書,就像 web 瀏覽器一樣。SSL 驗證默認是開啟的,如果證書驗證失敗,Requests 會拋出 SSLError:
verify 默認是為 True,SSL 驗證默認是開啟的
import requests response = requests.get("https://www.baidu.com/", verify=True) # 也可以省略不寫 # response = requests.get("https://www.baidu.com/") print(response.text)
執行結果:
<!DOCTYPE html> <!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge>百度一下,你就知道 ....
可以為 verify 傳入 CA_BUNDLE 文件的路徑,或者包含可信任 CA 證書文件的文件夾路徑:
#第一種寫法 requests.get('https://github.com', verify='/path/to/certfile') #第二種寫法 sess = requests.Session() sess.verify = '/path/to/certfile' 注解 如果 verify 設為文件夾路徑,文件夾必須通過 OpenSSL 提供的 c_rehash 工具處理。
verify 設置為 False,Requests 也能忽略對 SSL 證書的驗證
response = requests.get('https://kennethreitz.org', verify=False) print(response.status_code) <Response [200]>
2.7.2客戶端證書
你也可以指定一個本地證書用作客戶端證書,可以是單個文件(包含密鑰和證書)或一個包含兩個文件路徑的元組
#第一種寫法 response = requests.get('https://kennethreitz.org', cert=('/path/client.cert', '/path/client.key')) print(response.status_code)#<Response [200]> #第二種寫法; s = requests.Session() s.cert = '/path/client.cert' 警告: 本地證書的私有 key 必須是解密狀態。目前,Requests 不支持使用加密的 key。
參考;
https://blog.csdn.net/qq_37616069/article/details/80376776
