python實現接口自動化1

1、總述javascript

Postman:功能強大,界面好看響應格式自主選擇,缺點支持的協議單一且不能數據分離,比較麻煩的還有不是全部的公司都能上谷歌
SoupUI:支持多協議(http\soup\rest等),能實現功能和性能測試的開源接口測試工具,靈活性高可在此基礎上開發腳本,缺點上手比較難
Jmeter:Java御用的接口壓力測試工具,作接口功能測試有點大材小用,缺點不能生成可視化的接口測試報告html

python+requests+untest
python+requests+pytest
python+HttpRunnerjava

HttpRunner 是一款面向 HTTP(S) 協議的通用測試框架,只需編寫維護一份 YAML/JSON腳本,便可實現自動化測試、性能測試、線上監控、持續集成等多種測試需求。
Requests是一個Python HTTP 庫,它容許你發送純自然的HTTP/1.1請求無需手工設置。你不須要手動爲 URL 添加查詢字串,也不須要對 POST 數據進行表單編碼。Keep-alive 和 HTTP 鏈接池的功能是 100% 自動化的,一切動力都來自於根植在 Requests 內部的 urllib3。python

 

#響應內容
r.encoding                       #獲取當前的編碼
r.encoding = 'utf-8'             #設置編碼
r.text                           #以encoding解析返回內容。字符串方式的響應體,會自動根據響應頭部的字符編碼進行解碼。
r.content                        #以字節形式(二進制)返回。字節方式的響應體,會自動爲你解碼 gzip 和 deflate 壓縮。

r.headers                        #以字典對象存儲服務器響應頭,可是這個字典比較特殊,字典鍵不區分大小寫,若鍵不存在則返回None

r.status_code                     #響應狀態碼
r.raw                             #返回原始響應體,也就是 urllib 的 response 對象,使用 r.raw.read()   
r.ok                              # 查看r.ok的布爾值即可以知道是否登錄成功
 #*特殊方法*#
r.json()                         #Requests中內置的JSON解碼器,以json形式返回,前提返回的內容確保是json格式的,否則解析出錯會拋異常
r.raise_for_status()             #失敗請求(非200響應)拋出異常

 

get(url, params=None, **kwargs)
post(url, data=None, json=None, **kwargs)
request(method, url, **kwargs)git

 

 

2、requests庫的用法--getgithub

一、基本的get請求web

import requests

response = requests.get('http://httpbin.org/get')
print(response.text)         #以文本形式打印網頁源碼
# print(response.status_code)  # 打印狀態碼
# print(response.url)          # 打印請求url
# print(response.headers)      # 打印頭信息
# print(response.cookies)      # 打印cookie信息
# print(response.content)      #以二進制形式打印網頁源碼

結果shell

 

二、帶參數的GET請求(直接將參數放在url內):數據庫

import requests

response = requests.get('http://httpbin.org/get?name=gemey&age=22')
print(response.text)

結果json

三、帶參數的GET請求(先將參數填寫在dict中,發起請求時params參數指定爲dict):

import requests

data = {
    'name': 'tom',
    'age': 20
}

response = requests.get('http://httpbin.org/get', params=data)
print(response.text)

四、json格式保存結果

import requests

response = requests.get('http://httpbin.org/get')
print(response.text)
print(response.json())  #response.json()方法同json.loads(response.text)
print(type(response.json()))

結果

五、二進制保存結果:

import requests

response = requests.get('http://img.ivsky.com/img/tupian/pre/201708/30/kekeersitao-002.jpg')
b = response.content
with open('F://fengjing.jpg','wb') as f:
    f.write(b)

六、爲請求添加頭信息:

import requests
heads = {'User-Agent':"'Mozilla/5.0 ' '(Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 ' '(KHTML, like Gecko) Version/5.1 Safari/534.50'"}
response = requests.get('http://www.baidu.com',headers=heads)

七、使用代理

代理參數也要是一個dict,這裏使用requests庫爬取了IP代理網站的IP與端口和類型。由於是免費的,使用的代理地址很快就失效了。

import requests
import re

def get_html(url):
    proxy = {
        'http': '120.25.253.234:812',
        'https': '163.125.222.244:8123'
    }
    heads = {}
    heads['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0'
    req = requests.get(url, headers=heads,proxies=proxy)
    html = req.text
    return html

def get_ipport(html):
    regex = r'<td data-title="IP">(.+)</td>'
    iplist = re.findall(regex, html)
    regex2 = '<td data-title="PORT">(.+)</td>'
    portlist = re.findall(regex2, html)
    regex3 = r'<td data-title="類型">(.+)</td>'
    typelist = re.findall(regex3, html)
    sumray = []
    for i in iplist:
        for p in portlist:
            for t in typelist:
                pass
            pass
        a = t+','+i + ':' + p
        sumray.append(a)
    print('高匿代理')
    print(sumray)


if __name__ == '__main__':
    url = 'http://www.kuaidaili.com/free/'
    get_ipport(get_html(url))

結果:

 八、獲取cookie

#獲取cookie
import requests

response = requests.get('http://www.baidu.com')

print(response.cookies)
for k,v in response.cookies.items():
    print(k+':'+v)

結果:

 

九、證書驗證設置

import requests
from requests.packages import urllib3

urllib3.disable_warnings()  #從urllib3中消除警告
response = requests.get('https://www.12306.cn',verify=False)  #證書驗證設爲FALSE
print(response.status_code)

打印結果:200

十、 發送cookies到服務器

要想發送你的cookies到服務器,可使用 cookies 參數:

import requests
 
url = 'http://httpbin.org/cookies'
cookies = {'testCookies_1': 'Hello_Python3', 'testCookies_2': 'Hello_Requests'}# 規定空格、方括號、圓括號、等於號、逗號、雙引號、斜槓、問號、@,冒號,分號等特殊符號都不能做爲Cookie的內容。
r = requests.get(url, cookies=cookies)
print(r.json())

十一、超時異常捕獲

import requests
from requests.exceptions import ReadTimeout

try:
    res = requests.get('http://httpbin.org', timeout=0.1)
    print(res.status_code)
except ReadTimeout:
    print(timeout)

十二、異常處理

在你不肯定會發生什麼錯誤時,儘可能使用try...except來捕獲異常

import requests
from requests.exceptions import ReadTimeout,HTTPError,RequestException

try:
    response = requests.get('http://www.baidu.com',timeout=0.5)
    print(response.status_code)
except ReadTimeout:
    print('timeout')
except HTTPError:
    print('httperror')
except RequestException:
    print('reqerror')
全部的requests exception:

exception requests.RequestException(*args, **kwargs)
There was an ambiguous exception that occurred while handling your request.

exception requests.ConnectionError(*args, **kwargs)
A Connection error occurred.

exception requests.HTTPError(*args, **kwargs)
An HTTP error occurred.

exception requests.URLRequired(*args, **kwargs)
A valid URL is required to make a request.

exception requests.TooManyRedirects(*args, **kwargs)
Too many redirects.

exception requests.ConnectTimeout(*args, **kwargs)
The request timed out while trying to connect to the remote server.

Requests that produced this error are safe to retry.

exception requests.ReadTimeout(*args, **kwargs)
The server did not send any data in the allotted amount of time.

exception requests.Timeout(*args, **kwargs)
The request timed out.

Catching this error will catch both ConnectTimeout and ReadTimeout errors.

 

3、requests庫的用法--post

一、基本POST實例
import requests
  
payload = {'key1': 'value1', 'key2': 'value2'}
ret = requests.post("http://httpbin.org/post", data=payload)
  
print(ret.text)
二、發送請求頭和數據
import requests
import json
  
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
headers = {'content-type': 'application/json'}
  
ret = requests.post(url, data=json.dumps(payload), headers=headers)
  
print(ret.text)
print(ret.cookies)

三、json格式請求:

import requests
import json

class url_request():
    def __init__(self):
        ''' init '''

if __name__ == '__main__':
    heard = {'Content-Type': 'application/json'}
    payload = {'CountryName': '中國',
               'ProvinceName': '四川省',
               'L1CityName': 'chengdu',
               'L2CityName': 'yibing',
               'TownName': '',
               'Longitude': '107.33393',
               'Latitude': '33.157131',
               'Language': 'CN'}
    r = requests.post("http://www.xxxxxx.com/CityLocation/json/LBSLocateCity", heards=heard, data=payload)
    data_r = r.json()
    if r.status_code!=200:
        print('LBSLocateCity API Error' + str(r.status_code))
    print(data_r['CityEntities'][0]['CityID'])  # 打印返回json中的某個key的value
    print(data_r['ResponseStatus']['Ack'])
    print(json.dump(data, indent=4, sort_keys=True, ensure_ascii=False))  # 樹形打印json,ensure_ascii必須設爲False不然中文會顯示爲unicode

四、Xml請求:

import requests

class url_request():
    def __init__(self):
        """init"""

if __name__ == '__main__':
    heards = {'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'
    r = requests.post(url=url, heards=heards, data=XML)
    data_r = r.text
    print(data_r)

五、上傳文件

使用request模塊,也能夠上傳文件,文件的類型會自動進行處理:

複製代碼
import requests
 
url = 'http://127.0.0.1:8080/upload'
files = {'file': open('/home/rxf/test.jpg', 'rb')}
#files = {'file': ('report.jpg', open('/home/lyb/sjzl.mpg', 'rb'))}     #顯式的設置文件名
 
r = requests.post(url, files=files)
print(r.text)
複製代碼

request更加方便的是,能夠把字符串看成文件進行上傳:

複製代碼
import requests
 
url = 'http://127.0.0.1:8080/upload'
files = {'file': ('test.txt', b'Hello Requests.')}     #必需顯式的設置文件名
 
r = requests.post(url, files=files)
print(r.text)
複製代碼

六、定製頭和cookie信息

header = {'user-agent': 'my-app/0.0.1''}
cookie = {'key':'value'}
 r = requests.post('your url',headers=header,cookies=cookie) 
複製代碼
import requests
import json
 
data = {'some': 'data'}
headers = {'content-type': 'application/json','User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:22.0) Gecko/20100101 Firefox/22.0'}
 
r = requests.post('https://api.github.com/some/endpoint', data=data, headers=headers)
print(r.text)
複製代碼

 

4、綜合

一、方法彙總

# HTTP請求類型
# get類型
r = requests.get('https://github.com/timeline.json')
# post類型
r = requests.post("http://m.ctrip.com/post")
# put類型
r = requests.put("http://m.ctrip.com/put")
# delete類型
r = requests.delete("http://m.ctrip.com/delete")
# head類型
r = requests.head("http://m.ctrip.com/head")
# options類型
r = requests.options("http://m.ctrip.com/get")

# 獲取響應內容
print(r.content) #以字節的方式去顯示,中文顯示爲字符
print(r.text) #以文本的方式去顯示

#URL傳遞參數
payload = {'keyword': '香港', 'salecityid': '2'}
r = requests.get("http://m.ctrip.com/webapp/tourvisa/visa_list", params=payload) 
print(r.url) #示例爲http://m.ctrip.com/webapp/tourvisa/visa_list?salecityid=2&keyword=香港

#獲取/修改網頁編碼
r = requests.get('https://github.com/timeline.json')
print (r.encoding)


#json處理
r = requests.get('https://github.com/timeline.json')
print(r.json()) # 須要先import json    

# 定製請求頭
url = 'http://m.ctrip.com'
headers = {'User-Agent' : 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 4 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19'}
r = requests.post(url, headers=headers)
print (r.request.headers)

#複雜post請求
url = 'http://m.ctrip.com'
payload = {'some': 'data'}
r = requests.post(url, data=json.dumps(payload)) #若是傳遞的payload是string而不是dict,須要先調用dumps方法格式化一下

# post多部分編碼文件
url = 'http://m.ctrip.com'
files = {'file': open('report.xls', 'rb')}
r = requests.post(url, files=files)

# 響應狀態碼
r = requests.get('http://m.ctrip.com')
print(r.status_code)
    
# 響應頭
r = requests.get('http://m.ctrip.com')
print (r.headers)
print (r.headers['Content-Type'])
print (r.headers.get('content-type')) #訪問響應頭部份內容的兩種方式
    
# Cookies
url = 'http://example.com/some/cookie/setting/url'
r = requests.get(url)
r.cookies['example_cookie_name']    #讀取cookies
    
url = 'http://m.ctrip.com/cookies'
cookies = dict(cookies_are='working')
r = requests.get(url, cookies=cookies) #發送cookies

#設置超時時間
r = requests.get('http://m.ctrip.com', timeout=0.001)

#設置訪問代理
proxies = {
           "http": "http://10.10.1.10:3128",
           "https": "http://10.10.1.100:4444",
          }
r = requests.get('http://m.ctrip.com', proxies=proxies)


#若是代理須要用戶名和密碼,則須要這樣:
proxies = {
    "http": "http://user:pass@10.10.1.10:3128/",
}

 

二、自動登陸示例:

requests模擬登錄GitHub

import requests
from bs4 import BeautifulSoup


def login_github():
    """
    經過requests模塊模擬瀏覽器登錄GitHub
    :return: 
    """
     # 獲取csrf_token
     r1 = requests.get('https://github.com/login')   # 得到get請求的對象
     s1 = BeautifulSoup(r1.text, 'html.parser')      # 使用bs4解析HTML對象
     token = s1.find('input', attrs={'name': 'authenticity_token'}).get('value')     # 獲取登錄受權碼,即csrf_token
     get_cookies = r1.cookies.get_dict()     # 獲取get請求的cookies,post請求時必須攜帶
     
     # 發送post登錄請求
     '''
     post登錄參數
     commit    Sign+in
     utf8    ✓
     authenticity_token    E961jQMIyC9NPwL54YPj70gv2hbXWJ…fTUd+e4lT5RAizKbfzQo4eRHsfg==
     login    JackUpDown(用戶名)
     password    **********(密碼)
     '''
     r2 = requests.post(
         'https://github.com/session',
         data={
             'commit': 'Sign+in',
             'utf8': '',
             'authenticity_token': token,
             'login': 'JackUpDown',
             'password': '**********'
         },
         cookies=get_cookies     # 攜帶get請求的cookies
                        )
     login_cookies = r2.cookies.get_dict()   # 得到登錄成功的cookies,攜帶此cookies就能夠訪問任意GitHub頁面
 
     # 攜帶post cookies跳轉任意頁面
     r3 = requests.get('https://github.com/settings/emails', cookies=login_cookies)
     print(r3.text)
 
登陸知乎
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import time

import requests
from bs4 import BeautifulSoup

session = requests.Session()

i1 = session.get(
    url='https://www.zhihu.com/#signin',
    headers={
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
    }
)

soup1 = BeautifulSoup(i1.text, 'lxml')
xsrf_tag = soup1.find(name='input', attrs={'name': '_xsrf'})
xsrf = xsrf_tag.get('value')

current_time = time.time()
i2 = session.get(
    url='https://www.zhihu.com/captcha.gif',
    params={'r': current_time, 'type': 'login'},
    headers={
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
    })

with open('zhihu.gif', 'wb') as f:
    f.write(i2.content)

captcha = input('請打開zhihu.gif文件,查看並輸入驗證碼:')
form_data = {
    "_xsrf": xsrf,
    'password': 'xxooxxoo',
    "captcha": 'captcha',
    'email': '424662508@qq.com'
}
i3 = session.post(
    url='https://www.zhihu.com/login/email',
    data=form_data,
    headers={
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
    }
)

i4 = session.get(
    url='https://www.zhihu.com/settings/profile',
    headers={
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
    }
)

soup4 = BeautifulSoup(i4.text, 'lxml')
tag = soup4.find(id='rename-section')
nick_name = tag.find('span',class_='name').string
print(nick_name)

 

 登陸百度並返回登陸後的首要天氣數據
import requests, time, random, rsa, base64, re
from bs4 import BeautifulSoup as BS
import http.cookiejar as HC
from subprocess import Popen  # 打開圖片

home_url = "https://www.baidu.com/"
login_url = "https://passport.baidu.com/v2/api/?login"

headers = {
    "Host": "passport.baidu.com",
    "Referer": "https://www.baidu.com/",
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36"
}

# 獲取當前時間戳
def get_tt():
    return str(int(time.time() * 1000))

# 隨機生成callback
def get_callback():
    prefix = "bd__cbs__"  # callback 前綴
    char = "0123456789abcdefghijklmnopqrstuvwxyz"
    n = random.randint(0, 2147483648)
    suffix = []
    while n != 0:
        suffix.append(char[n % 36])
        n = n // 36
    suffix.reverse()
    print("callback: " + (prefix + ''.join(suffix)))
    return prefix + ''.join(suffix)

# 隨機生成gid
def get_gid():
    gid = list("xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")
    for x in range(len(gid)):
        r = int(random.random() * 16)
        if gid[x] == "x":  # 若是當前值爲x
            gid[x] = hex(r).replace("0x", "").upper()
    print("gid: " + "".join(gid))
    return "".join(gid)

def get_token():
    global token_time
    token_time = get_tt()
    call_back = get_callback()
    token_url = "https://passport.baidu.com/v2/api/?getapi&tpl=mn&apiver=v3&tt={}&class=login&gid={}&logintype=dialogLogin&callback={}".format(
        token_time, gid, call_back)
    response = session.get(token_url, headers=headers)
    token_all = response.text.replace(call_back, "")
    token_all = eval(token_all)
    print(token_all)
    return token_all["data"]["token"]

def get_pubkey():
    pubkey_callback = get_callback()
    pubkey_url = "https://passport.baidu.com/v2/getpublickey?token={}&tpl=mn&apiver=v3&tt={}&gid={}&callback={}".format(
        token, get_tt(), gid, pubkey_callback)
    response = session.get(pubkey_url, headers=headers)
    pubkey_all = eval(response.text.replace(pubkey_callback, ""))
    print(pubkey_all["pubkey"], pubkey_all["key"])
    return pubkey_all["pubkey"], pubkey_all["key"]

# 密碼rsa加密
def get_rsa_password(psw, pk):
    pub = rsa.PublicKey.load_pkcs1_openssl_pem(pk.encode("utf-8"))
    psw = psw.encode("utf-8")
    passwd = rsa.encrypt(psw, pub)
    passwd = base64.b64encode(passwd)
    print(passwd.decode("utf-8"))
    return passwd.decode("utf-8")

session = requests.session()
session.cookies = HC.LWPCookieJar(filename="BaiDuCookies")
try:
    session.cookies.load(ignore_discard=True)  # 加d載cookies文件
except:
    print("cookie未保存或cookie已過時")
    gid = get_gid()
    session.get("https://passport.baidu.com/v2/?login", headers=headers)
    token = get_token()
    pubkey, key = get_pubkey()
    account = input("請輸入您的帳號:")
    password = input("請輸入您的密碼:")

    postData = {
        'staticpage': 'https://www.baidu.com/cache/user/html/v3Jump.html',
        'charset': 'UTF-8',
        'tpl': 'mn',
        'subpro': '',
        'apiver': 'v3',
        'safeflg': '0',
        'u': 'https://www.baidu.com/',
        'isPhone': 'false',
        'detect': '1',
        'quick_user': '0',
        'logintype': 'dialogLogin',
        'logLoginType': 'pc_loginDialog',
        'idc': '',
        'loginmerge': 'true',
        'splogin': 'rate',
        'mem_pass': 'on',
        'crypttype': '12',
        'countrycode': '',
        'codestring': '',
        'verifycode': '',
        'token': token,
        'tt': get_tt(),
        'gid': gid,
        'username': account,
        'password': get_rsa_password(password, pubkey),  # 通過加密
        'rsakey': key,
        'ppui_logintime': str(int(get_tt()) - int(token_time)),
        'callback': get_callback()
    }

    response = session.post(login_url, postData, headers=headers)
    # 若是存在codeString則獲取驗證碼圖片,再次請求
    codeString = re.findall(r'codeString=(.*?)&userName', response.text)[0]
    while codeString:
        # 獲取圖片,保存圖片,輸入圖片驗證碼
        gif_url = "https://passport.baidu.com/cgi-bin/genimage?{}".format(codeString)
        gif = session.get(gif_url, headers=headers)
        with open("baidu.gif", "wb") as f:
            f.write(gif.content)
        Popen("baidu.gif", shell=True)
        verifycode = input("驗證碼:")
        postData["verifycode"] = verifycode
        postData["codestring"] = codeString

        # 再次登陸
        relogin = session.post(login_url, postData, headers=headers)
        codeString = re.findall(r'codeString=(.*?)&userName', relogin.text)[0]

headers["Host"] = "www.baidu.com"
re = session.get(home_url, headers=headers)
# 保存cookies信息,以備下次直接訪問首頁
session.cookies.save()
# 獲取首頁天氣信息
print("城市: " + BS(re.text, 'lxml').find("em", {"class": "show-city-name"})["data-key"])
print("氣溫: " + BS(re.text, 'lxml').find("em", {"class": "show-icon-temp"}).string)

 

5、重點

 一、認證機制

HTTP Basic Auth
HTTP Basic Auth簡單點說明就是每次請求API時都提供用戶的username和password,簡言之,Basic Auth是配合RESTful API使用的最簡單的認證方式,只需提供用戶名密碼便可,但因爲有把用戶名密碼暴露給第三方客戶端的風險,在生產環境下被使用的愈來愈少。所以,在開發對外開放的RESTful API時,儘可能避免採用HTTP Basic Auth(事實上,很難找到用http基自己份認證方式的網站了)

import requests
r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
print(r.status_code)

digest auth(摘要式身份認證)
digest auth在HTTP 1.1提出,目的是替代http 1.0提出的基本認證方式服務器收到客戶端請求後返回401 UNAUTHORIZED,同時在WWW-Authenticate字段說明認證方式是Digest,其餘信息還有realm域信息、nonce隨機字符串、opaque透傳字段(客戶端會原樣返回)等

import requests
r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
print(r.status_code)

Cookie Auth
Cookie認證機制就是爲一次請求認證在服務端建立一個Session對象,同時在客戶端的瀏覽器端建立了一個Cookie對象;經過客戶端帶上來Cookie對象來與服務器端的session對象匹配來實現狀態管理的。默認的,當咱們關閉瀏覽器的時候,cookie會被刪除。但能夠經過修改cookie 的expire time使cookie在必定時間內有效;


OAuth(OAuth 1.0、OAuth 2.0)
OAuth(開放受權)是一個開放的受權標準,容許用戶讓第三方應用訪問該用戶在某一web服務上存儲的私密的資源(如照片,視頻,聯繫人列表),而無需將用戶名和密碼提供給第三方應用。
OAuth容許用戶提供一個令牌,而不是用戶名和密碼來訪問他們存放在特定服務提供者的數據。每個令牌受權一個特定的第三方系統(例如,視頻編輯網站)在特定的時段(例如,接下來的2小時內)內訪問特定的資源(例如僅僅是某一相冊中的視頻)。這樣,OAuth讓用戶能夠受權第三方網站訪問他們存儲在另外服務提供者的某些特定信息,而非全部內容,這種基於OAuth的認證機制適用於我的消費者類的互聯網產品,如社交類APP等應用,可是不太適合擁有自有認證權限管理的企業應用。
python處理OAuth1.0/2.0須要第三方庫requests-oauthlib。

TokenAuth
使用基於 Token 的身份驗證方法,在服務端不須要存儲用戶的登陸記錄。大概的流程是這樣的:
一、客戶端使用用戶名跟密碼請求登陸
二、服務端收到請求,去驗證用戶名與密碼
三、驗證成功後,服務端會簽發一個Token,再把這個Token發送給客戶端
四、客戶端收到Token之後能夠把它存儲起來,好比放在Cookie裏
五、客戶端每次向服務端請求資源的時候須要帶着服務端簽發的Token
六、服務端收到請求,而後去驗證客戶端請求裏面帶着的Token,若是驗證成功,就向
七、客戶端返回請求的數據

二、cookie
 
獲取cookie
import requests

url = "http://www.baidu.com"
response = requests.get(url)
#方法一
print(response.headers['Set-Cookie'])

#方法二
print(response.cookies)
print(response.cookies.items())
print(response.cookies.items()[0][1])

#方法三
for k,v in response.cookies.items():
    print(k+':'+v)

#方法四
print(requests.utils.dict_from_cookiejar(response.cookies))
結果:
BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
<RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>]> [('BDORZ', '27315')] 27315 BDORZ:27315 {'BDORZ': '27315'}

 

設置cookie

#方法一: 
# cookies是字典格式,這種cookie不能放在headers裏
cookies = {
      name1 :value1,
      name2:value2
}
response = request.post(url, data=data, cookies=cookies)


#方法二:使用requests.session, 經過CookieJar來處理cookie。
#將字典類型的cookie轉換成cookiejar,將cookiesJar賦值給會話,cookie處理,由session自動處理cookie,報文請求的時候就不須要再加上cookie了。
cookiesJar = requests.utils.cookiejar_from_dict(manual_cookies, cookiejar=None,overwrite=True)
session = requests.session()
session.cookies=cookiesJar


#方法三,headers中加cookie。
headers ='User-Agent':'Apache-HttpClient/4.5.2 (Java/1.8.0_66)',
'cookie':'_zap=191e4816-acf0-41ab-85ca-c54c2ff9ca1f; d_c0="ABCsEEAYPQ2PTofKIlzwxMJDdb8R-_6iVQA=|'
}

response = requests.post(url,data=data,headers=headers)

 
#方法四:
#若是須要在請求中添加cookie,能夠實例化一個RequestCookieJar的類,而後把值set進去,最後在get,post方法裏面指定cookies參數就好了

import requests
from requests.cookies import RequestsCookieJar

url = "http://fanyi.baidu.com/v2transapi"
 
cookie_jar = RequestsCookieJar()
cookie_jar.set("BAIDUID", "B1CCDD4B4BC886BF99364C72C8AE1C01:FG=1", domain="baidu.com")
 
res = requests.get(url, cookies=cookie_jar)
print res.status_code

 

三、會話維持
好比須要查看或提交我的信息,這個必須得在登陸以後,所以須要登陸後系統返回的cookie信息。所以:一、須要先定義登陸操做,並返回登陸後的cookie或token信息二、進行查看我的信息或提交我的信息,可是在參數中必須得有cookies這個。
 
方式一:
用requests中的Session實例化,能夠在同一session實例發出的全部請求之間保持cookie,由於底層的TCP鏈接 會重用。因此不用像第一種那樣,每一次登陸後的請求參數都要加上cookie或token。會話對象讓你可以跨請求保持某些參數,最方便的是在同一個Session實例發出的全部請求之間保持cookies,且這些都是自動處理的。
requests對session、cookie和token的處理
 
方式二:不使用seeion,方法是取出前一次正常訪問時的cookie或token,第二次訪問時將cookie或token寫入放入頭中。
import requests

def reg():
    host = "http://10.70.18.33:8083/"
    url1 = host + "shopxx-mobile/register.jhtml"
    r = requests.get(url1)
    token = r.cookies.items()[0][1]

    url2 = host + "shopxx-mobile/register/send.jhtml"
    headers = {
            "token": token,
            "Host": "10.70.18.33:8083",
            "User-Agent":" Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:46.0) Gecko/20100101 Firefox/46.0",
            "Accept": "application/json, text/javascript, */*; q=0.01",
            "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
            "Accept-Encoding": "gzip, deflate",
            "Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",
            "X-Requested-With": "XMLHttpRequest",
            "Connection":"keep-alive",
            "Content-Length": "18",
            "charset":"UTF-8",
            "cookie":"token=" + token
            }

    data = {'mobile':'1851174****'}
    s = requests.post(url2,data,headers=headers)

    print(s.status_code,s.text)

if __name__ == '__main__':
    reg()

 

四、經過cookie繞過驗證碼登陸

爲了繞過登陸驗證碼,先手動成功登陸,並抓包獲取登陸成功的cookie值。在代碼中以保持會話的方式訪問登陸界面(不須要真的登陸),獲取cookie,而後將抓包獲取到的cookie值添加到代碼中的cookie裏(亦即添加到session中),以後再去訪問須要訪問的內容。

# coding:utf-8
import requests
# 先打開登陸首頁,獲取部分cookie
url = "https://passport.cnblogs.com/user/signin"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0"}  # get方法加個ser-Agent就能夠了
s = requests.session()
r = s.get(url, headers=headers,verify=False) #獲取登陸頁面的cookie,不須要去登錄,只要登陸界面。
print(s.cookies)
# 添加登陸須要的兩個cookie
c = requests.cookies.RequestsCookieJar()

c.set('.CNBlogsCookie', 'xxx')  # 填入抓包獲取的cookie
c.set('.Cnblogs.AspNetCore.Cookies','xxx')  # 填入抓包獲取的cookie
s.cookies.update(c)
print(s.cookies)

# 登陸成功後保存編輯內容
url2= "https://i.cnblogs.com/EditPosts.aspx?opt=1"
body = {"__VIEWSTATE": "",
        "__VIEWSTATEGENERATOR":"FE27D343",
        "Editor$Edit$txbTitle":"這是繞過登陸的標題:北京-宏哥",
        "Editor$Edit$EditorBody":"<p>這裏是中文內容:http://www.cnblogs.com/duhong/</p>",
        "Editor$Edit$Advanced$ckbPublished":"on",
        "Editor$Edit$Advanced$chkDisplayHomePage":"on",
        "Editor$Edit$Advanced$chkComments":"on",
        "Editor$Edit$Advanced$chkMainSyndication":"on",
        "Editor$Edit$lkbDraft":"存爲草稿",
         }
r2 = s.post(url2, data=body, verify=False)
print(r.content)

 

五、API複雜場景舉例

經過使用基礎的測試工具,能夠作簡單場景的API測試;而項目進行過程當中,爲了解決實際的一些問題,咱們會設計更加複雜的測試場景,下面列舉幾個實際項目中的典型場景。

場景一:API串聯調用
以協議支付爲例,咱們知道,三方公司接入網聯後,用協議支付取代代扣,而協議支付的流程中須要用戶輸入銀行返回的驗證碼完成綁卡。從接口層面上看,順序是先調用協議簽約API,返回狀態成功且獲取到短信驗證碼後,再使用此短信驗證碼做爲輸入參數調用代扣API。協議簽約和代扣兩個API是順序調用,並且在兩次調用中間有獲取手機上的短信驗證碼,這些過程都須要經過程序自動化實現以提升效率。

場景二:API接口加密
爲保證API接口安全,系統間和系統內模塊間互相訪問須要進行加密處理,經常使用的加密方式有DES、AES、RSA、MD5等,各系統的加密方式並不同(接口調用方和接口提供方約定好便可),意味着API測試須要支持多種自動化加密方式程。某些系統還會返回加密的響應報文,也須要識別並解密。

場景三:異步API測試
異步API指請求發出後後收到一個同步響應,但並非最終處理結果,最終結果經過回調或者主動查詢得到。對於這樣的API,同步響應的驗證只是第一步,後續還得繼續驗證DB中的值、MQ中的值、以及異步回調是否成功等。對於異步回調,咱們能夠模擬回調地址來驗證成功與否;而對於主動查詢,咱們就得經過查看DB中的狀態值來驗證了,可是查詢到結果的時間點不肯定,幾分鐘到幾小時都有可能,這就得有一個定時DB查詢任務去驗證。

場景四:API測試中的外部依賴APIA調用APIB且B不可用,此時如何測試APIA須要考慮。好比支付系統對三方支付通道、對銀行的依賴,並非全部的三方都支持測試環境,解決此問題的核心思路是搭建MockServer,並且儘可能作到通用性,咱們開發了一套Mock系統 -aMock,經過頁面錄入接口信息,保存在數據庫內,經過Nginx訪問配置好的Mock接口,後臺統一處理請求信息,而後經過URL和報文特性去匹配特定的響應信息。

相關文章
相關標籤/搜索