前言
接口測試中,上傳文件的測試場景非常常見。例如:上傳頭像(圖片)、上傳文件、上傳視頻等。
下面以一個上傳圖片的例子為大家講解如何通過 python 測試上傳文件接口。
①首先通過抓包分析上傳文件接口的請求參數:
②下面是上傳文件接口腳本。
把目標文件以open打開,然后存儲到變量file。並且使用 files參數指明請求的參數名稱、上傳文件的類型、以及上傳文件的路徑。
注意
content-type參數,如果我們通過form-data的方式上傳文件,我們發送post請求的時候,headers這個參數中一定不能要包括這個值;
即不需要包括 {"Content-Type":"multipart/form-data"} ,例如:
requests庫會自動添加這個元素 {"Content-Type":"multipart/form-data"} ;加了反而會報錯,從而導致請求不成功。
在前端允許和支持上傳的所有格式文件中,當選擇不同格式文件時對接口發起請求時,Form Data會自動識別文件的Content-Type【根據傳入的文件格式自動解析為headers中的Content-Type】以及Content-Disposition【該字段中包括接口的傳參類型(例如下圖的form-data),傳入文件名(例如下圖的filename)等】。
例如:
示例
requests請求接口上傳文件代碼示例:
import requests from utils.LogUtil import my_log from faker import Faker log=my_log() faker = Faker('zh_CN') class marketCreate(): def loginToken(self,mobile,code): ''' 登陸、注冊接口 :param mobile: 手機號 :param code: 驗證碼 :return: ''' url='http://api.xxxxxx.net/v1/user/loginOrRegister' #登陸接口請求地址 headers={'Content-Type': 'application/json'} #請求頭信息,json數據類型 json={"code":code,"deviceId":"5de548ad0e268bc0","deviceName":"HWNXT","mobile":mobile,"mobilePrefix":"63","version":"39"} #請求數據 r=requests.post(url,headers=headers,json=json) #發送請求 token=r.json()['data']['userVO']['token'] #獲取token log.info('手機號'+mobile+'的token值為:'+token) #打印日志 return token #將token返回出去 def uploadimages(self,mobile,file_path,filename): ''' 上傳圖片接口 :param mobile: 手機號 :param file_path: 文件路徑 :param filename: 文件名稱 :return: ''' token = self.loginToken(mobile=mobile, code='789789') #請求登陸接口,獲取token url='http://api.xxxxxx.net/v1/upload/images' #上傳文件接口請求地址 headers={'token': token} #請求頭信息關聯token。不需要賦值Content-Type,requests庫會幫忙添加這個元素,加了可能會報錯。 file_data={'file':(filename,open(file_path,'rb'),'image/jpeg')} #重點:上傳文件請求數據。 r=requests.post(url=url,headers=headers,files=file_data) #發送請求 print(r.json()) #打印響應結果 if __name__ == '__main__': m=marketCreate() # 測試,輸入手機號、文件地址、文件名稱信息; m.uploadimages(mobile='639266558329',file_path='D:pyCharm_workcmkjProjectdatamarket.jpg',filename='123456.jpg')
執行結果:
C:Python38python.exe D:/pyCharm_work/cmkjProject/page/marketPage.py 2020-01-02 13:48:09,580-D:pyCharm_workcmkjProjectutilsLogUtil.py-INFO-手機號639266558329的token值為:ba9b4f622fa4d6461523870c0d00df46 {'code': 0, 'data': '/group1/M00/00/00/rBDKPF4NhE-ABIFmAAGhT9tm-NA158.jpg', 'success': True} Process finished with exit code 0
總結:
如果需要發送文件到服務器,比如上傳圖片、視頻等,就需要發送二進制數據。
一般上傳文件接口的請求頭中定義傳入參數數據的媒體類型使用的都是
Content-Type: multipart/form-data;
數據類型,可以發送文件,也可以發送相關的消息體數據。
POST一個多部分編碼(Multipart-Encoded)的文件
使用 requests 上傳文件的基本步驟
- 構造文件數據,通過 open 函數以二進制方式打開文件
- 構造相關數據
- 發送請求,將文件數據以files參數傳入,其他消息體數據通過data、json、headers、cookies傳入
url = 'http://httpbin.org/post' # 上傳文件接口 files = { 'file': ('test.png', # 文件名稱 open('../file/test.png', 'rb'), # 文件路徑 'image/png', # 文件類型 {'Expires': '0'} # 其他參數,非必傳 ) } # => 打開上傳文件並且加入文件相關參數 data = { "name": "test" } # data傳入請求參數dict,files傳入待上傳文件參數dict r = requests.post(url, data=data, files=files) print(r.json())
注意
files參數字典里的file鍵名稱是根據上傳組件的name屬性來改變的,不一定是file。【抓包時可以通過請求體中的 binary行的參數名獲取name屬性】
如下圖上傳組件,當你上傳一張圖片時,抓包可以發現會傳兩個值,一個是fileField,一個是type,所以你的文件數據dict要包含 ‘fileField’和‘type’兩個key
files = { 'fileField': ('test.png', # 文件名稱 open('../file/test.png', 'rb'), # 文件路徑 'image/png', # 文件類型 {'Expires': '0'} # 其他參數,非必傳 ), 'type': 1 } # => 打開上傳文件並且加入文件相關參數
Python使用requests庫發送上傳zip類型文件的post請求
第一步,通過chrome瀏覽器的開發者工具,獲得發送的參數。
第二步,編寫python代碼
使用request庫的post方法。注意的是要添加files參數,例如:
files ={'app_filename':open('portal-1.0-SNAPSHOT-fat.jar.zip','rb')}
zip壓縮包的content-type是application/x-zip-compressed,其他的文件的content-type是application/octet-stream。
其中:
① app_filename是F12工具里抓出來的from data里的標有{binary}這一行的參數名【可以理解為name屬性】。
② portal-1.0-SNAPSHOT-fat.jar.zip是本地電腦zip文件名。(需要請求接口的文件)
③ rb是讀取二進制文件。因為form data媒體類型表示文件是以二進制形式上傳。
④其余的常規參數,放到data參數里。例如上圖的 image_name:fff就是常規參數。
⑤在接口請求的請求頭里注意添加cookies或者 Authorization,(這里測試的網站用的是Authorization驗證用戶身份。如果沒有該參數或者該參數錯誤或過期,會返回401)。
⑥完整代碼如下:
path = os.path.split(os.path.realpath(__file__))[0]
url = host + '/dashboard/cicd/images'
headers = { 'Authorization':'6bae7b70-8dae-4f74-9631-680b9501b52', 'cookie': "_ga=GA1.3.733851079.1534745675; Hm_lvt_dde6ba2851f3db0ddc415ce0f895822e=1537859803; _ga=GA1.3.733851079.1534745675; Hm_lvt_dde6ba2851f3db0ddc415ce0f895822e=1537859803", }
datat = {'image_name': 'abcd', 'image_description': 'ccccvcc', 'image_label': '1cc1fcc', 'basic_image': 'openjdk:10', 'store_path': '/opt/app/lzw/'}
files = {'app_filename': ( 'portal-1.0-SNAPSHOT-fat.jar.zip', open(os.path.join(path, 'portal-1.0-SNAPSHOT-fat.jar.zip'), 'rb'), 'application/x-zip-compressed')}
# files ={'app_filename':open('portal-1.0-SNAPSHOT-fat.jar.zip','rb')} 和上面的功能一樣 result = requests.post(url, files=files, data=datat, headers=headers)
r1 = result.text print(result.text)
Python使用requests庫發送上傳excel文件的post請求
【注意】
zip壓縮包的 content-type 是 application/x-zip-compressed ;
其他的文件的 content-type 是 application/octet-stream 。如上圖二【直接點擊(view source)】(圖一是點擊(view parsed即解析后的表單內容)
添加files參數:
files = {'files': (file_name, open(get_file_path(filename=file_name), 'rb'))}
① files是F12工具里抓出來的from data表單數據請求體里的標有 binary 這一行的參數名【可以理解為name屬性】。【如圖一中的粗紅線框出來的文件參數】
② file_name 對應需要上傳文件的文件名。
③ open 函數是為了獲取需要上傳的文件的流。
④ rb是讀二進制文件。因為請求頭中的 content_type字段標識 form data 數據媒體類型即表示文件是以二進制形式上傳。
⑤其余的常規參數,放到data參數里。【如上圖中的細紅線框出的常規參數,即作為同文件上傳時還有需要一起上傳的body體數據】
代碼如下:
def clue_add(): file_name = 'create_club.xls'
files = {'files': (file_name, open(get_file_path(filename=file_name), 'rb'))}
url_upload = 'http://gasst-uat.test.geely.com/cafe.portal-service/frame_center/common/attachmentChunkUpload'
headers = {'Cookie': ReadConfig().read_config('project_GHelper', 'token')}
data_upload = { 'fileName': 'create_club.xls', 'chunkCount': 1, 'chunkIndex': 1 }
r_upload = requests.post(url=url_upload, files=files, headers=headers, data=data_upload)