#python #api #rest #web
Вопрос:
Текущая проблема:
- Пользователь может войти в https://<ПОЛНОЕ доменное имя>/Пользовательский интерфейс с помощью веб-браузера, затем щелкнуть где-нибудь и загрузить файл, например, файл размером 2,5 G. Все эти операции(вход,…, загрузка) являются реальными вызовами API.
- Кроме того, пользователь также может напрямую выполнять вызовы Rest API с помощью приложений Java или Python. Итак, я пишу фрагмент кода Python, чтобы сделать это. К сожалению, в результате успешного вызова API «https://<ПОЛНОЕ доменное имя>/api/логин», следующий вызов API «https://<ПОЛНОЕ ДОМЕННОЕ ИМЯ><ПОЛНОЕ доменное ИМЯ>/api/v1.0/Файлы обновления/загрузка» имеет проблемы. Он может загружать только небольшие файлы. Для больших файлов, таких как 2,5 Г, это не удается.
- Когда я возвращаюсь в веб-браузер и пытаюсь загрузить большой файл с окном отладки, открытым F12, я вижу, что он выполняет несколько запросов, и в каждом заголовке запроса он содержит, как показано ниже:
content-length : 5000464 sec-ch-ua : " Not A;Brand";v="99", "Chromium";v="90", "Microsoft Edge";v="90" sec-ch-ua-mobile : ?0 user-agent : Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36 Edg/90.0.818.46 content-type : multipart/form-data; boundary=----WebKitFormBoundaryPuIjpBG8n874gC29 content-range : bytes 0-4999999/2684354560 accept : application/json x-requested-with : XMLHttpRequest content-disposition : attachment; filename="b86aee78-56db-4398-8cd0-69b156740a2a"
Похоже, что он разделяет весь файл, устанавливает «диапазон содержимого» и выполняет вызовы API.
- Я хочу смоделировать поведение веб-браузера, поэтому я пишу фрагмент кода Python, как показано ниже:
#_*_ coding:utf-8 _*_ import requests import time import random import string from requests_toolbelt.multipart import encoder datas = {'userName':'<Username>','<Password>'} header = {'accept':'application/json', 'Content-Type':'application/json'} r = requests.post('https://<FQDN>/api/login', headers=header, data=datas) #print(r.content) print(r.status_code) if r.status_code == 200: print("Login is successful") responseBody = r.json() sessionId = responseBody['sessionId'] print(sessionId) url = "https://<FQDN>/api/v1.0/updateFiles/upload" fields = { 'Content-Dispostion':'attachment; filename="3rdParty1.tgz"', 'file': ('1.tar.gz', open('C:/Users/Jie2/Downloads/1.tar.gz', 'rb'), 'application/zip') } boundary = '----WebKitFormBoundary' ''.join(random.sample(string.ascii_letters string.digits,16)) multipart_encoder = encoder.MultipartEncoder(fields=fields,boundary=boundary) headers = { 'accept':'application/json', 'sessionId':sessionId, 'Referer':'https://<FQDN>/UI/', 'Content-Type': 'multipart/form-data; boundary={}'.format(boundary), } response = requests.post(url=url, headers=headers, data=multipart_encoder, cookies=r.cookies) print(response)
Но приведенный выше код может загружать только небольшие файлы, такие как кбайты. Для больших файлов, таких как 2,5 Г, это не удается.
Приведенный выше код принимает https://toolbelt.readthedocs.io/en/latest/uploading-data.html в качестве ссылки. - Я также попытался отказаться от requests_toolbelt и использовать только модуль запросов, а также использовать цикл для ручного чтения файла по разделам и ручной настройки «диапазона содержимого». К сожалению, это тоже не работает.
def mutiple_upload(str,f,str1): # m1 = md5() # m1.update(Bfile) hx = { "Host": "<FQDN>", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36", "Accept": "application/json", "Accept-Language": "en-US,en;q=0.9", "Accept-Encoding": "gzip, deflate, br", "Referer": "https://<FQDN>/ui", "X-Requested-With": "XMLHttpRequest", "Content-Length": "75023", "Connection": "keep-alive", "Transfer-Encoding": 'chunked', "sessionId": sessionId, "timestamp": now2, "Content-MD5": str1, "Content-Range": str } resp=requests.post(url, headers=hx, files=f) # print(resp.json()) for x in range(0,t): m = md5() if ((x x*chunk_size chunk_size) < fLen): crf= "bytes " str(x x*chunk_size) "-" str(x x*chunk_size chunk_size) "/" str(fLen) f = open('<FileName>', 'rb') f.seek((x x*chunk_size),0) fs = f.read(chunk_size) fx = { 'name': (None, '<FileName>'), 'file': ('<FileName>',fs)} m.update(fs) mutiUpload = mutiple_upload(crf, fx, str(m.hexdigest())) else: crf = "bytes " str(x x * chunk_size) "-" str(fLen - 1) "/" str(fLen) f = open('<FileName>', 'rb') f.seek((x x*chunk_size),0) fs = f.read(chunk_size - 1) fx = { 'name': (None, '<FileName>'), 'file': ('<FileName>',fs)} m.update(fs) mutiUpload = mutiple_upload(crf,fx, str(m.hexdigest()))
Does anybody know if there is a python module that can help me to implement this requirement — automatically read the large file section by section, and automatically set the header like «content-range» to make it work? Or, I do not find a correct way to use requests_toolbelt.