2012-09-25 20 views
5

Me preguntaba cómo traducir algo como esto usando Python Requests? En urllib2, puede manipular manualmente los datos que se envían a través del cable al servicio API, pero las solicitudes hacen que las cargas de archivos múltiples sean fáciles. Sin embargo, cuando trato de enviar la misma solicitud usando la biblioteca de Solicitudes, creo que no está especificando algunos parámetros clave en el tipo de contenido para cada una de las dos partes correctamente. Por favor, alguien puede arrojar algo de luz sobre este asunto. ¡Gracias de antemano!Peticiones de Python HTTP de varias partes POST

def upload_creative(self, account_id, file_path): 
    """""" 
    boundary = '-----------------------------' + str(int(random.random()*1e10)) 
    parts = [] 

    # Set account ID part. 
    parts.append('--' + boundary) 
    parts.append('Content-Disposition: form-data; name="account_id"') 
    parts.append('') 
    parts.append(str(account_id)) 

    # Set creative contents part. 
    parts.append('--' + boundary) 
    parts.append('Content-Disposition: form-data; name="userfile"; filename="%s"' % file_path) 
    parts.append('Content-Type: %s' % mimetypes.guess_type(file_path)[0] or 'application/octet-stream') 
    parts.append('') 
    # TODO: catch errors with opening file. 
    parts.append(open(file_path, 'r').read()) 

    parts.append('--' + boundary + '--') 
    parts.append('') 

    body = '\r\n'.join(parts) 

    headers = {'content-type': 'multipart/form-data; boundary=' + boundary} 
    url = self._resolve_url('/a/creative/uploadcreative') 
    req = urllib2.Request(url, headers=headers, data=body) 
    res = urllib2.urlopen(req) 

    return json.loads(res.read()) 

Cuando examino firebug desde la interfaz de usuario, obtengo lo siguiente en la fuente POST.

-----------------------------662549079759661058833120391 
Content-Disposition: form-data; name="userfile"; filename="IMG_1377.jpg" Content-Type: image/jpeg 

ÿØÿáÃExif��MM�*���� �������ª���� ���°���������������������º�������Â(�������1�������Ê2�������Ú<�������î�������i�������þ%������p��Apple�iPhone 4���H������H�����QuickTime 7.7.1�2012:08:17 11:47:11�Mac OS X 10.7.4�������������� "�������'�����P�������0220������(������<������ �����P������X������� ����� �� ������`������h �����0100 ������� ������ ������¢�������¤��������¤��������¤��������¤ ����������������������2011:10:01 17:19:23�2011:10:01 17:19:23���4��Á��¹��¡���M���Ç»¸������N����������Ê�����W����������â�������ú�����M�����������������!�����S���d����������T�����ÿ���d���������������������Ú����%Á��r��������������t������|(�������������������7������������H������H�����ÿØÿà�JFIF��H�H��ÿþ�AppleMark ÿÛ�� % #!,!#'(***.1-)1%)*((((((((((((((((((((((((((((((((((((((((((((((((((((ÿÄ¢���������� ������� ���}�!1AQa"q2¡#B±ÁRÑð$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖ×ØÙÚáâãäåæçèéêñòóôõö÷øùú��w�!1AQaq"2B¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz¢£¤¥¦§¨©ª²³´µ¶·¸¹ð.¥ÛWíÇLòV³FcaoæÂÒ8§É¸(è3E¢"Ú×S^+yj�!òû0Oüµn- yè){[oÝ/¸?ÃÔMY¡ÃgÔò4êò4n͸í¶={ÔM¤¸m¯K&ñæ«,©ù»zTÝ=öØô×6¶Ö:MÑi�,Û$Oö[ª÷ª©ÆiîỤJAxj>ÞAõúu¥}lIf÷û^Â)#´y^)Ô"/·v>n~4ººµ­¬æ}FURì·Î 3¿Ãèh»ÐµÈÿ�·|Gu:ß²<ëlWäG·^+¡Ó¼gâ.-Þè|ϸ*ª® }é?Ú=(i:2½Ïg!ʵÑi¤¼eþ!÷³ÍC'æCqv®ÖÊÕiçCë·øsQy#K_B´þ0s'¦|¿Þ²lò¼?½ÿ�]rZ¶¨ø·6ñÆØ·mvV;þÿ�þ=ôª¿»r\zPñtHö÷>Ù¤R#+ Á òBôR;ú²¾)!àËn<.ÁÔlÏcRäÂ&§­eX´fTóLžQßt§Zµ{â t·pK]ÈL1²îýúEüxþ÷j\î×-jÏÂ>!û:^,E­,>^ýêßwû+Ópæ»?i÷û5kéá¹^ 6Ddq°öÁ¯Rù¨¦yãjòÿÙ 
-----------------------------662549079759661058833120391 
Content-Disposition: form-data; name="account_id" 

69574 
-----------------------------662549079759661058833120391-- 

Las cabeceras en Firebug son los siguientes:

Request Headersview source 
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Encoding gzip, deflate 
Accept-Language en-us,en;q=0.5 
Cache-Control no-cache 
Connection keep-alive 
Content-Length 1713991 
Content-Type multipart/form-data; boundary=---------------------------662549079759661058833120391 
Cookie instance_defaults=%7C%20%7Cen_US; access_token=75c48e 
Host ui.host.com 
Pragma no-cache 
Referer http://ui.host.com/ 
User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:14.0) Gecko/20100101 Firefox/14.0.1 

Creo que mi pregunta es ¿hay alguna manera a través de la biblioteca de solicitudes para ajustar los datos para que el:

Content-Disposition: form-data; name="userfile"; filename="IMG_1377.jpg" Content-Type: image/jpeg 

y el

Content-Disposition: form-data; name="account_id" 

69574 

sta los tements están ambos presentes. Siento que tengo que hacer algo como tienen archivos de datos tengan un diccionario de

files = {'file': open('image.jpg', 'rb'), 'account_id': 12345} 

pero de algún modo editar los metadatos de Content-Disposición de cada una de estas partes por separado

+0

lo has intentado con 'requests'? –

+0

Estoy intentando editar los metadatos de disposición de contenido de cada parte de la solicitud POST de carga de archivos múltiples. Por ejemplo, en mi edición, necesito tener name = "userfile"; filename = "IMG_1377.jpg" Content-Type: image/jpeg para la primera parte que es el archivo de imagen, y luego para la segunda parte, necesito tener Content-Disposition: form-data; name = "account_id" Espero que esto aclare la pregunta. Por favor, avíseme si algo como esto es posible con la biblioteca python-requests. Muchas gracias – user1698138

Respuesta

8

con requests, creo que usted don' t tiene que ser tan manual, simplemente:

import requests 

# ... 
url = self._resolve_url('/a/creative/uploadcreative') 
files = {'file': ('userfile', open(filepath, 'rb'))} 
data = {'account_id': account_id} 
headers = {'content-type': 'multipart/form-data'} 
res = requests.post(url, files=files, data=data, headers=headers) 
return res.json 

supongo que su preocupación se encuentra con su:

parts.append('Content-Type: %s' % mimetypes.guess_type(file_path)[0] or 'application/octet-stream') 

No me lo he demostrado más allá de la sombra de una duda. Pero, creo que está integrado en las solicitudes here.

Edit: looks like que puede tener los campos normales en los archivos dict, como usted propone:

files = {'file': open('image.jpg', 'rb'), 'account_id': 12345} 

y podría nombrar el nombre de archivo que desea:

files = {'file': ('userfile', open('image.jpg', 'rb')), 'account_id': 12345} 

pero, si fuera obtenga un body.write(b'Content-Type: text/plain\r\n\r\n') en el campo account_id que probablemente no sea el que desea y no tenga forma de personalizar la disposición del contenido para cada campo (todavía no estoy seguro de por qué lo necesitaría); para el archivo y el campo obtendrá: Content-Disposition: form-data - que es lo que muestra para ambos.

No estoy seguro de que pueda hacer exactamente lo que quiere con requests, tal vez debería intentar una solicitud de función.

+1

Para ser exactos, a veces aún necesita especificar el encabezado debido a algunas restricciones. request usa 'urlib3', así que es bastante bueno. – CppLearner

+0

Entonces, ¿puede especificar manualmente el tipo de contenido del archivo con 'requests'? parece que utiliza la misma heurística que la pregunta, pero no parece proporcionar una forma de especificar manualmente el CT del archivo. –

+0

Entiendo, sin embargo, no creo que esta sea la respuesta a mi pregunta. He editado mi pregunta con más aclaraciones con la esperanza de que alguien tenga la respuesta que estoy buscando. Muchas gracias a todos – user1698138

-3

Descubrí que en la biblioteca python-requests (v.0.13.3), sus datos serán eliminados si incluye el campo "datos" antes del campo "archivos" en la llamada de solicitud.

Por ejemplo,

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

rendirá forma de datos vacío. Sin embargo, lo siguiente será enviar el diccionario de datos como form-data

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

Gracias a todos por sus respuestas

+0

El orden de los argumentos con nombre no importa en Python; estas dos llamadas son exactamente iguales. El comportamiento que observas se debe a que probablemente envíes un tipo de valor diferente en el argumento 'datos'; consulta [this] (http://stackoverflow.com/a/12385661/95735) answer. –

0
import requests 

import urllib 

def upload_creative(self, account_id, file_path): 

    files = [('userfile', (file_path, open(file_path, 'rb'), "image/jpeg"))] 

    url = self._resolve_url('/a/creative/uploadcreative') 

    url = url + "?" + urlib.urlencode(account_id=account_id) 

    reuests.post(url, files=files) 
Cuestiones relacionadas