python request模塊學習使用


一: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

https://www.cnblogs.com/lanyinhao/p/9634742.html

https://zhuanlan.zhihu.com/p/137649301


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM