Python相当于curls --form:使用" form"中的数据创建多部分表单数据发布请求参数

时间:2014-07-18 22:50:49

标签: python post curl python-requests multipartform-data

我正在寻找与此curl命令相当的python:

 curl --referer "https://myreferer" --insecure --form "myparam=1234" https://myurl

导致以下请求(取自httpbin.org/post):

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "myparam": "1234"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Connection": "close", 
    "Content-Length": "142", 
    "Content-Type": "multipart/form-data; boundary=----------------------------29a1ce32cc53", 
    "Host": "httpbin.org", 
    "Referer": "https://speedport.ip/hcti_start_passwort.stm", 
    "User-Agent": "curl/7.22.0 (x86_64-pc-linux-gnu) libcurl/7.22.0 OpenSSL/1.0.1 zlib/1.2.3.4 libidn/1.23 librtmp/2.3", 
    "X-Request-Id": "c67c4461-89d2-4c9f-a9f4-ebfe312c026c"
  }, 
...

正如您所看到的,数据" myparam"以“#34;形式”交付参数。

我试图通过pythons requests模块构建这样的请求,并接近这段代码:

import requests
payload={'myparam':'1234'}
url="http://httpbin.org/post"
headers={'User-Agent': 'Mozilla 5.0','referer':'https://myreferer'}
r = requests.post(url, files=payload, headers=headers,verify=False)

但是请求库将数据放入"文件"参数。因此生成的请求如下所示:

{
  "args": {}, 
  "data": "", 
  "files": {
    "pws": "1234"
  }, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Connection": "close", 
    "Content-Length": "143", 
    "Content-Type": "multipart/form-data; boundary=a878ad29e28d47ffb00e0631319ed0e2", 
    "Host": "httpbin.org", 
    "Referer": "https://myreferer", 
    "User-Agent": "Mozilla 5.0", 
    "X-Request-Id": "60f5d65e-789a-47fe-bba3-dab88f9bbb65"
...

所以数据是在错误的地方传递的,即在"文件中#34;参数,这使得Apache阻塞了" 501未实现"响应。

有人可以建议如何在Python中执行此类请求吗? (我知道我可以将curl称为子进程,但由于我想做很多这些请求,我想要一个只有python的解决方案(希望更高效))。

而且,正如您可能已经注意到的那样,我还需要接受自签名证书并发送引用标题。

如果有人能提出一个解决这个问题的简单方法,我会很高兴。

谢谢!

编辑:我已尝试使用requests.post命令的" data" -param,但这会产生不同的内容类型标题(application / x-www-form -urlencoded)。请注意curl请求的内容类型标题。

编辑:我可能需要的是通过requests.post命令的headers param简单地发送正确的Content-Type标头,multipart / form-data。但我还必须计算multipart / form-data标头字符串的"边界" -part。我认为必须有一种更简单的方法,而不是手动构建标题和计算边界。

2 个答案:

答案 0 :(得分:3)

使用file-like object files会产生multipart/form-data内容类型

让我们准备好所有我们需要的电话,从“通常”的东西开始:

>>> import requests
>>> data = {"myparam": "1234"}
>>> headers = {'User-Agent': 'Mozilla 5.0','referer':'https://myreferer'}

强制requests使用“multipart / form-data”的诀窍是给它一个像文件一样的文件 对象

>>> from StringIO import StringIO
>>> buff = StringIO("")

buff现在是我们可以作为files参数值传入的类文件对象。

>>> req = requests.post(url, data=data, headers=headers, stream=True, files=buff)
>>> print req.text
{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "myparam": "1234"
  }, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate", 
    "Connection": "close", 
    "Content-Length": "130", 
    "Content-Type": "multipart/form-data; boundary=0b3bbec1f5c844a1b7377aacfe701f02", 
    "Host": "httpbin.org", 
    "Referer": "https://myreferer", 
    "User-Agent": "Mozilla 5.0", 
    "X-Request-Id": "988a0467-1c32-45aa-a75c-fba5aa8d632e"
  }, 
  "json": null, 
  "origin": "85.160.45.204", 
  "url": "http://httpbin.org/post"
}

如果您要使用自签名证书与https进行通信,请使用verify=False

>>> req = requests.post(url, data=data, headers=headers, stream=True, files=buff, verify=False)

requests.request的帮助还指出,verify的值可能是“CA_BUNDLE路径”,所以你 可以明确确定服务器正在使用您期望的自签名证书。但 有了这个,我从来没有尝试过。

答案 1 :(得分:2)

很遗憾,如果您不想将数据作为文件发送,则必须使用第三方库 - requests_toolbelt。一旦pip install requests-toolbelt,您就可以

from requests_toolbelt import MultipartEncoder
import requests

payload = MultipartEncoder({'myparam': '1234'})
r = requests.post(url, data=payload, headers={'Content-Type': payload.content_type})

当然,您也可以设置其他标题,这只是使用工具带满足您需求的快速示例。

如果要验证证书,可以将带有完整路径的字符串传递给PEM文件,例如,

r = requests.get('https://somesite.com', verify='/Users/mhelwig/certificate.pem')