Python接口測試實戰2 - 使用Python發送請求

課程目錄

Python接口測試實戰1(上)- 接口測試理論 Python接口測試實戰1(下)- 接口測試工具的使用 Python接口測試實戰2 - 使用Python發送請求 Python接口測試實戰3(上)- Python操做數據庫 Python接口測試實戰3(下)- unittest測試框架 Python接口測試實戰4(上) - 接口測試框架實戰 Python接口測試實戰4(下) - 框架完善:用例基類,用例標籤,從新運行上次失敗用例 Python接口測試實戰5(上) - Git及Jenkins持續集成 Python接口測試實戰5(下) - RESTful、Web Service及Mock Serverjavascript

更多學習資料請加添加做者微信:lockingfree獲取html

本節內容

  • requests安裝
  • requests使用
  • JSON類型解析
  • requests庫詳解
  • 帶安全認證的請求

序言

上節課咱們學習了接口測試的理論,抓包工具及使用Postman手工測試各類接口,這節課咱們主要講解使用Python語言來發送接口請求,實現接口測試自動化。java

發送請求,咱們這裏主要使用Python的一個第三方包(須要先安裝):requests。 Python3自帶的http.client和urllib.request都能發送http請求,不過相對來講使用較麻煩,第三方庫requests讓發送請求更簡單,支持自動編碼解碼,會話保持,長連等python

參考: requests官方文檔git

requests安裝

  • Windows: 打開cmd命令行,輸入pip install requests,等待安裝完成便可
  • Linux: (建議使用Python3),終端中輸入pip3 install requests,等待安裝完成便可
  • Mac: (建議使用Python3), sudo python3 -m pip install requests,等待安裝完成便可

驗證是否安裝成功:github

打開命令行,輸入python,在python shell環境下輸入import requests沒有報錯即安裝成功算法

requests的使用

一個最簡單的GET請求

發送一個請求分3步:shell

  1. 組裝請求: 請求可能包含url,params(url參數),data(請求數據),headers(請求頭),cookies等,最少必須有url
  2. 發送請求,獲取響應:支持get,post等各類方法發送,返回的是一個響應對象
  3. 解析響應: 輸出響應文本

打開Pycharm,新建一個demo項目,項目下新建一個Python文件,輸入如下內容:數據庫

# 導入requests包
import requests 

# 1. 組裝請求
url = "http://httpbin.org/get"  # 這裏只有url,字符串格式
# 2. 發送請求,獲取響應
res = requests.get(url) # res即返回的響應對象
# 3. 解析響應
print(res.text)  # 輸出響應的文本

帶參數的GET請求

import requests 

url = "http://www.tuling123.com/openapi/api?key=ec961279f453459b9248f0aeb6600bbe&info=你好"  # 參數能夠寫到url裏
res = requests.get(url=url) # 第一個url指get方法的參數,第二個url指上一行咱們定義的接口地址
print(res.text)

json

import requests 

url = "http://www.tuling123.com/openapi/api"
params = {"key":"ec961279f453459b9248f0aeb6600bbe","info":"你好"} # 字典格式,單獨提出來,方便參數的添加修改等操做
res = requests.get(url=url, params=params) 
print(res.text)

傳統表單類POST請求(x-www-form-urlencoded)

import requests 

url = "http://httpbin.org/post"
data = {"name": "hanzhichao", "age": 18} # Post請求發送的數據,字典格式
res = requests.post(url=url, data=data) # 這裏使用post方法,參數和get方法同樣
print(res.text)

JSON類型的POST請求(application/json)

import requests 

url = "http://httpbin.org/post"
data = '''{
        "name": "hanzhichao",
        "age": 18
        }''' # 多行文本, 字符串格式,也能夠單行(注意外層有引號,爲字符串) data = '{"name": "hanzhichao", "age": 18}'
res = requests.post(url=url, data=data) #  data支持字典或字符串
print(res.text)

data參數支持字典格式也支持字符串格式,若是是字典格式,requests方法會將其按照默認表單urlencoded格式轉換爲字符串,若是是字符串則不轉化 若是data以字符串格式傳輸須要遵循如下幾點:

  • 必須是嚴格的JSON格式字符串,裏面必須用雙引號,k-v之間必須有逗號,布爾值必須是小寫的true/false等等
  • 不能有中文,直接傳字符串不會自動編碼

通常來講,建議將data聲明爲字典格式(方便數據添加修改),而後再用json.dumps()方法把data轉換爲合法的JSON字符串格式

import requests 
import json # 使用到JSON中的方法,須要提早導入

url = "http://httpbin.org/post"
data = {
        "name": "hanzhichao",
        "age": 18
        }  # 字典格式,方便添加
headers = {"Content-Type":"application/json"} # 嚴格來講,咱們須要在請求頭裏聲明咱們發送的格式
res = requests.post(url=url, data=json.dumps(data), headers=headers) #  將字典格式的data變量轉換爲合法的JSON字符串傳給post的data參數
print(res.text)

或直接將字典格式的data數據賦給post方法的JSON參數(會自動將字典格式轉爲合法的JSON文本並添加headers)

import requests 

url = "http://openapi.tuling123.com/openapi/api/v2"
data = {
	"reqType":0,
    "perception": {
        "inputText": {
            "text": "附近的酒店"
        },
        "inputImage": {
            "url": "imageUrl"
        },
        "selfInfo": {
            "location": {
                "city": "北京",
                "province": "北京",
                "street": "信息路"
            }
        }
    },
    "userInfo": {
        "apiKey": "ec961279f453459b9248f0aeb6600bbe",
        "userId": "206379"
    }
} 
res = requests.post(url=url, json=data) # JSON格式的請求,將數據賦給json參數
print(res.text)

練習:

  1. 利用圖靈聊天接口(GET) http://www.tuling123.com/openapi/api?key=ec961279f453459b9248f0aeb6600bbe&info=你好,結合Python的input編寫一個機器人聊天室
  2. 利用圖靈查詢接口(POST)http://openapi.tuling123.com/openapi/api/v2,封裝一個實用的查詢方法,查詢你附近的美食等等

JSON類型解析

序列化和反序列化

程序中的對象,如Python中的字典、列表、函數、類等,都是存在內存中的,一旦斷電就會消失,不方便傳遞或存儲,因此咱們須要將內存中的對象轉化爲文本或者文件格式,來知足傳輸和持久化(存儲)需求

  • 序列化: 內存對象 -> 文本/文件
  • 反序列化: 文本 -> 內存對象

對象在HTTP中的傳輸過程 HTTP協議是超文本傳輸協議,是經過文本或二進制進行傳輸的,因此咱們發送的請求要轉化成文本進行傳輸,收到的響應也是文本格式,若是是JSON,通常還須要將文本格式從新轉化爲對象

JSON對象(Python字典) -> 轉爲文本請求 -> 發送請求 -> 服務器收到文本請求 -> 將文本請求轉化爲對象,獲取其中的參數,處理業務 -> 返回文本格式的響應 -> 客戶端轉爲對象格式來從響應中取值

JSON對象與Python字典的區別

JSON對象是javascript object即javascript中的對象,是一種通用的格式,格式嚴格,不支持備註。

JSON文本和JSON對象的區別:

  • JSON文本是符合JSON格式的文本,其實是一個字符串
  • JSON對象是內存中一個對象,擁有屬性和方法,能夠經過對象獲取其中的參數信息

Python中咱們通常提到JSON對象指的是字典

Python的字典的格式和JSON格式,稍有不一樣:

  • 字典中的引號支持單引號和雙引號,JSON格式只支持雙引號
  • 字典中的True/False首字母大寫,JSON格式爲true/false
  • 字典中的空值爲None, JSON格式爲null

JSON格式操做方法

  • 序列化(字典 -> 文本/文件句柄): json.dumps()/json.dump()
  • 反序列化(文本/文件句柄 -> 字典) : json.loads()/json.load()
import json # 須要導入JSON包

data = {'name': '張三', 'password': '123456', "male": True, "money": None} # 字典格式
str_data = json.dumps(data) # 序列化,轉化爲合法的JSON文本(方便HTTP傳輸)
print(str_data)

輸出:{"name": "\u5f20\u4e09", "password": "123456", "male": true, "money": null}

json.dumps()支持將json文本格式化輸出

import requests 
import json

res = requests.post("http://www.tuling123.com/openapi/api?key=ec961279f453459b9248f0aeb6600bbe&info=怎麼又是你") 
print(res.text) # 輸出爲一行文本
res_dict = res.json() # 將響應轉爲json對象(字典)等同於`json.loads(res.text)`
print(json.dumps(res_dict, indent=2, sort_keys=True, ensure_ascii=False)) # 從新轉爲文本

看一下輸出結果對比:

{"code":100000,"text":"我纔要說怎麼又是你"}  # res.text,有些接口中文會返回爲\u..
{
  "code": 100000,
  "text": "我纔要說怎麼又是你"  # 樹狀格式,比較清晰,顯示中文
}
  • indent: 縮進空格數,indent=0輸出爲一行
  • sork_keys=True: 將json結果的key按ascii碼排序
  • ensure_ascii=Fasle: 不確保ascii碼,若是返回格式爲utf-8包含中文,不轉化爲\u...

反序列化

import json

res_text = {"name": "\u5f20\u4e09", "password": "123456", "male": true, "money": null}  # JSON文本格式的響應信息
res_dict = json.loads(res_text) # 轉化爲字典 
print(res_dict['name'])  # 方便獲取其中的參數值

輸出:張三

文件的序列化與反序列化

  1. 序列化:字典 -> 文件句柄
import json

res_dict = {'name': '張三', 'password': '123456', "male": True, "money": None} # 字典格式
f = open("demo1.json","w")
json.dump(res_dict, f)

查看同級目錄,增長了一個demo1.json文件,內容爲:

{"name": "\u5f20\u4e09", "password": "123456", "male": true, "money": null}
  1. 序列化: 文件句柄 -> 字典

在項目中(和下面腳本文件同一路徑下)新建demo2.json文件,內容以下,保存

{
  "name": "張三",
  "password": "123456",
  "male": true,
  "money": null
}

新建Python文件

import json

f = open("demo.JSON","r", encoding="utf-8")  # 文件中有中文須要指定編碼
f_dict = json.load(f) # 反序列化將文件句柄轉化爲字典
print(f['name']) # 讀取其中參數
f.close()

何時使用JSON對象(字典)何時使用JSON文本? 通常在組裝data參數時,建議使用字典格式,發送請求時用json.dumps(data)轉化爲文本發送,收到請求後使用json.loads(res.text)轉化爲字典,方便咱們獲取其中的參數信息 練習:

  1. 解析如下json格式文件,發送請求並打印響應

注: method支持get和post,若是沒有method,有data默認發post請求,沒有data默認發get請求,type支持:form或json,沒有默認發form格式 demo1.json

{
  "url": "http://www.tuling123.com/openapi/api",
  "method": "get",
  "params": {
    "key": "ec961279f453459b9248f0aeb6600bbe",
    "info": "你好"
  }
}

demo2.json

{
  "url": "http://openapi.tuling123.com/openapi/api/v2",
  "method": "post",
  "type": "json",
  "data": {
    "reqType": 0,
    "perception": {
      "inputText": {
        "text": "附近的酒店"
      },
      "inputImage": {
        "url": "imageUrl"
      },
      "selfInfo": {
        "location": {
          "city": "北京",
          "province": "北京",
          "street": "信息路"
        }
      }
    },
    "userInfo": {
      "apiKey": "ec961279f453459b9248f0aeb6600bbe",
      "userId": "206379"
    }
  }
}

requests庫詳解

請求方法

  • requests.get()
  • requests.post()
  • requests.put() ...
  • requests.session(): 用於保持會話(session) 除了requests.session()外,其餘請求方法的參數都差很少,都包含url,params, data, headers, cookies, files, auth, timeout等等

請求參數

  • url: 字符串格式,參數也能夠直接寫到url中
  • params:url參數,字典格式
  • data: 請求數據,字典或字符串格式
  • headers: 請求頭,字典格式
  • cookies: 字典格式,能夠經過攜帶cookies繞過登陸
  • files: 字典格式,用於混合表單(form-data)中上傳文件
  • auth: Basic Auth受權,數組格式 auth=(user,password)
  • timeout: 超時時間(防止請求一直沒有響應,最長等待時間),數字格式,單位爲秒

響應解析

  • res.status_code: 響應的HTTP狀態碼
  • res.reason: 響應的狀態碼含義
  • req.text:響應的文本格式,按req.encoding解碼
  • req.content: 響應的二進制格式
  • req.encoding: 解碼格式,能夠經過修改req.encoding='utf-8'來解決一部分中文亂碼問題
  • req.apparent_encoding:真實編碼,由chardet庫提供的明顯編碼
  • req.json(): (注意,有括號),響應的json對象(字典)格式,慎用!若是響應文本不是合法的json文本,或報錯
  • req.headers: 響應頭
  • req.cookies: 響應的cookieJar對象,能夠經過req.cookies.get(key)來獲取響應cookies中某個key對應的值 ... 示例:
import requests 

res = requests.get("https://www.baidu.com") 
print(res.status_code, res.reason) # 200 OK
print(res.text) # 文本格式,有亂碼
print(res.content) # 二進制格式
print(res.encoding) # 查看解碼格式 ISO-8859-1
print(res.apparent_encoding) # utf-8
res.encoding='utf-8' # 手動設置解碼格式爲utf-8
print(res.text) # 亂碼問題被解決
print(res.cookies.items()) # cookies中的全部的項 [('BDORZ', '27315')]
print(res.cookies.get("BDORZ")) # 獲取cookies中BDORZ所對應的值 27315

詳情參考:Py.qi: python3之requests

帶安全認證的請求

須要登陸的請求(Cookie/Session認證)

例如: 直接訪問: https://demo.fastadmin.net/admin/dashboard?ref=addtabs 頁面(頁面能夠看作一個返回html代碼的GET請求)會提示請登陸後操做 登陸頁面:https://demo.fastadmin.net/admin/index/login.html 用戶名/密碼:admin/123456(POST表單請求) 未登陸訪問接口

  1. 使用會話保持
import requests

s = requests.session() # 新建一個會話
s.post(url="https://demo.fastadmin.net/admin/index/login.html",data={"username":"admin","password":"123456"}) # 發送登陸請求
res = s.get("https://demo.fastadmin.net/admin/dashboard?ref=addtabs") # 使用同一個會話發送get請求,能夠保持登陸狀態
print(res.text)

若是不使用session()而單獨發一個post登陸請求一個get請求是否能夠呢?你能夠本身試一下(requests.get()或post()每次都會創建一個新會話)

  1. 抓取cookies
    1. 使用Chrome瀏覽器訪問https://demo.fastadmin.net/admin/index/login.html,登陸
    2. 打開開發者工具刷新當前頁面(https://demo.fastadmin.net/admin/index/login.html)
    3. Network麪包查看當前請求,將cookie後面的值複製出來,組裝成字典格式

抓取cookies

import requests

url = "https://demo.fastadmin.net/admin/dashboard?ref=addtabs"
cookies = {"PHPSESSID":"9bf6b19ddb09938cf73d55a094b36726"}
res = requests.get(url=url, cookies=cookies) # 攜帶cookies發送請求
print(res.text)

兩種方式的對比

  • 使用session方式:每次都要發送兩次請求,效率較低
  • 使用攜帶cookies方式:須要手動抓包,提取組裝,cookies中是session有必定有效期,過時以後要從新抓取和更換cookies
  • 若是不少或全部請求都須要登陸,能夠發一次請求,保持該session爲全局變量,其餘接口都使用該session發送請求(一樣要注意登陸過時時間) 練習
  1. 抓包並用腳本發一條微博或一篇博客

appid或token方式

  • appid: 系統爲合法用戶賦予的訪問id,固定的字符串,通常通過加密以確保HTTP傳輸中的安全
  • token: 即令牌,固定或須要動態申請(有必定有效期),通常由用戶信息及申請時間計算加密而成,用於驗證接口訪問的權限

token與session的區別

建立應用

獲取token

通用文字接口

  • 從網絡上找一張帶文字的圖片,右鍵,複製圖片地址(注意不支持https地址的圖片)

帶文字的圖片

請求結果

import requests
import json

app_key = 'kPoFYw85FXsnojsy5bB9hu6x'
secret_key = 'l7SuGBkDQHkjiTPU3m6NaNddD6SCvDMC'
img_url = 'http://upload-images.jianshu.io/upload_images/7575721-40c847532432e852.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240'
# 獲取token
get_token_url = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={}&client_secret={}'.format(app_key,secret_key)
token = requests.get(url=get_token_url).json().get("access_token")  # 從獲取token接口的響應中取得token值
# 識別圖片文字
orc_url = 'https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token={}'.format(token)
data = {"url": img_url}
res = requests.post(url=orc_url, data=data)
print(json.dumps(res.json(), indent=2, ensure_ascii=False)) # 格式化輸出

顯示結果:

{
  "log_id": 4745549456768330559,
  "words_result_num": 6,
  "words_result": [
    {
      "words": "我又問:那麼什麼時候,你帶我回去?"
    },
    {
      "words": "蓮師言:你是你,我是我。你若不肯流連凡塵,自會回去。"
    },
    {
      "words": "我問蓮師:我從哪裏來,要到哪裏去?"
    },
    {
      "words": "蓮師言:世間種種變相,皆有起源。來與去皆是命中定數,不可參度。"
    },
    {
      "words": "我再問:我是否還會再見到你?"
    },
    {
      "words": "蓮師言:你若心中有我,天然會再見。"
    }
  ]
}

練習:

  1. 本身註冊任意一個開發者平臺(微信開發者平臺,百度開發者平臺,餓了麼開發者平臺),建立應用,根據相應的受權方式獲取token,並使用token正常訪問一個接口

開放協議受權

reqeusts支持Basic Auth(基本受權)和Digist Auth(摘要受權)

Oauth1.0 Oauth2.0 參考: requests官方文檔 Basic Auth

import requests
import json

# 基本受權能夠直接在請求方法中使用`auth = (user,password)`
res = requests.get("https://api.github.com/user", auth=("hanzhichao", "hanzhichao123"))
print(json.dumps(res.json(), indent=2, ensure_ascii=False))  # 格式化輸出

數字簽名

不管是cookie/session仍是appid/token方式,只用來驗證請求者身份而不驗證參數,所以沒法防止請求參數被抓包攔截後篡改(仍攜帶合法的cookie或token) 數字簽名(sign或sig)是用來對原始參數總體進行加密後生成的一個字符串,請求時參數和簽名一期發送,服務器收到請求後對參數再次計算簽名覈對和所攜帶的簽名是否一致。 例如: 原始簽名{}

此爲北京龍騰育才 Python高級自動化(接口測試部分)授課筆記 課程介紹 想要參加現場(北京)/網絡課程的能夠聯繫做者微信:lockingfree

  1. 高效學習,快速掌握Python自動化全部領域技能
  2. 同步快速解決各類問題
  3. 配套實戰項目練習

原文出處:https://www.cnblogs.com/superhin/p/10338930.html

相關文章
相關標籤/搜索