Python请求多部分HTTP POST

Python请求多部分HTTP POST,python,urllib2,multipartform-data,python-requests,Python,Urllib2,Multipartform Data,Python Requests,我想知道如何使用Python请求翻译类似的内容?在urllib2中,您可以手动操作通过线路发送到API服务的数据,但请求声称多部分文件上传很容易。但是,当尝试使用Requests库发送相同的请求时,我认为它没有在内容类型中为这两部分中的每一部分正确指定一些关键参数。有人能解释一下这件事吗。提前谢谢你 def upload_creative(self, account_id, file_path): """""" boundary = '----------------------

我想知道如何使用Python请求翻译类似的内容?在urllib2中,您可以手动操作通过线路发送到API服务的数据,但请求声称多部分文件上传很容易。但是,当尝试使用Requests库发送相同的请求时,我认为它没有在内容类型中为这两部分中的每一部分正确指定一些关键参数。有人能解释一下这件事吗。提前谢谢你

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())
当我从UI检查firebug时,我在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--
我想我的问题是,是否可以通过请求库调整数据,以便:

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

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

69574
两份声明都有。我觉得我必须做一些事情,比如让文件成为一本字典

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

但是,通过
请求
,以某种方式分别编辑这些部分的内容配置元数据

,我相信您不必如此手动,只需:

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
我想你关心的是你的:

parts.append('Content-Type: %s' % mimetypes.guess_type(file_path)[0] or 'application/octet-stream')
毫无疑问,我还没有向自己证明这一点。但是,我认为这是内置于请求中的

编辑:如您所建议的,您可以在文件dict中使用普通字段:

files = {'file': open('image.jpg', 'rb'), 'account_id': 12345}
并且可以根据需要命名文件名:

files = {'file': ('userfile', open('image.jpg', 'rb')), 'account_id': 12345}
但是,您将在
帐户id
字段上获得一个
body.write(b'Content-Type:text/plain\r\n\r\n')
,该字段可能不是您想要的,并且无法自定义每个字段的内容配置(仍然不确定为什么需要);对于文件和字段,您将获得:
Content-Disposition:form-data
——这是您为两者显示的内容


我不确定您是否可以对
请求执行您想要的操作,也许您应该尝试一个功能请求。

我发现在python请求库(v.0.13.3)中,如果在请求调用本身的“文件”字段之前包含“数据”字段,您的数据将被擦除

比如说,

requests.post(url, headers=headers, data=data, files=files) 
将生成空表单数据。但是,以下内容将数据字典作为表单数据发送

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

感谢大家的回答

您对
请求尝试了什么
?我正在尝试编辑多部分文件上载POST请求的每个部分的内容处置元数据。例如,在我的编辑中,我需要name=“userfile”;filename=“IMG_1377.jpg”内容类型:图像/jpeg对于第一部分是图像文件,然后对于第二部分,我需要有内容配置:表单数据;name=“account\u id”我希望这能让问题变得更清楚。请告诉我python请求库是否可以实现类似的功能。非常感谢确切地说,由于某些限制,有时您仍然需要指定标题。requests使用
urlib3
,所以它非常好。那么,您可以使用
requests
手动指定文件的内容类型吗?它似乎使用了与问题相同的启发式,但似乎没有提供手动指定文件CT的方法。我理解,但是,我不认为这是我问题的答案。我编辑了我的问题,希望有人能得到我正在寻找的答案。非常感谢大家在Python中命名参数的顺序并不重要-这两个调用完全相同。您观察到的行为是因为您可能在
数据
参数中发送不同类型的值-请参阅答案。
 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)
 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)