【问题标题】:Python requests dict as form-dataPython 请求 dict 作为表单数据
【发布时间】:2017-11-10 05:15:30
【问题描述】:

我有一个 python 字典

x = {'id': 123, 'data': {'param1': 'hello', 'param2': 'world'}}

我正在尝试让我的表单数据成为

id=123
data[param1]=hello
data[param2]=world

不能将它作为 json 传递,因为接收它的 API 不会接受 json 对象

我试过这样传递

requests​.post(url, data=x, headers={'content-type': 'application/x-www-form-urlencoded'})

请求发出的表单数据如下所示

id=123
data=param1
data=param2

有没有办法解决这个问题?

【问题讨论】:

  • @Tomalak 不,请再读一遍问题
  • 你试过data = x['data']吗?
  • 发送的数据中 hello 和 world 去哪了?
  • @zipa 我不能这样做,因为我在顶层有额外的参数

标签: python python-requests


【解决方案1】:

您应该发布data=x['data'],而不是发布data = x。这应该可以解决您的问题。

requests​.post(url, data=x['data'], headers={'content-type': 'application/x-www-form-urlencoded'})

或者更好的方法是从您的字典中删除 data 键并直接创建字典为

x = {'param1': 'hello', 'param2': 'world'}

然后你可以像这样发帖:

requests​.post(url, data=x['data'], headers={'content-type': 'application/x-www-form-urlencoded'})

选择最适合你的..

希望这会有所帮助:)

【讨论】:

  • 我应该澄清一下,我的实际数据在顶层包含其他值,所以我不能这样做
  • 你能更清楚你的数据结构是什么吗?
【解决方案2】:

您可以将第一层展平:

x = {'data': {'param1': 'hello', 'param2': 'world'}}

x_flattened = {"{}[{}]".format(e, s) if type(: x[e][s] for e in x for s in x[e]}

requests​.post(url, data=x_flattened)

编辑 - 同时您已向原始对象添加了更多信息。如果您还想保留顶级奇异参数,您可以分两步完成(您可以在单个 dict 理解中完成,但它很快就会变得丑陋):

x_flattened = {}
for e in x:
    if isinstance(x[e], (list, dict)):
        x_flattened.update({"{}[{}]".format(e, s): x[e][s] for s in x[e]})
    else:
        x_flattened[e] = x[e]

requests​.post(url, data=x_flattened)

【讨论】:

  • 那是……不明智的。数据序列化并不是一点点字符串插值那么简单。如果数据包含引号或括号/大括号,这将中断。最重要的是,正如请求的内容类型所暗示的那样,OP 实际上是在寻找标准的 URL 编码的键/值对。
  • 我没有说这是明智的...requests 模块没有为由于某些深不可测的原因需要一些特殊数据打包的低能 API 提供解决方法。这是实现 OP 想要的最基本的方法,所以它让他开始......他必须处理边缘情况,或者找到他试图与之通信的 API 的编写者并告诉他修复期望接收方。
  • “特殊数据打包”和application/x-www-form-urlencoded 在术语上几乎是矛盾的。没有什么比 URL 编码更不特别的了。除此之外,“边缘情况”并不是对错误代码的良好防御。
  • application/x-www-form-urlencoded 没有说明 OP 想要打包的嵌套数据(因此 Python 的 x["data"]["param1"] = "foo" 在发布时变为 data[param1]=foo)。单层打包部分将由requests 模块正确处理,但如果他想像他展示的那样发送数据,OP 将需要展平嵌套层。上面的代码是朝着这个方向迈出的一步,并且很可能在大多数情况下都可以工作。
  • 很公平,但是如果没有适当的规范,做 something 并将其余的作为“边缘情况”手动挥动是没有用的。如果 OP 想要展平嵌套结构,那么这是一个递归操作,需要一些拼写规则并生成一个平面 dict,然后需要通过正确的 URL 编码。
【解决方案3】:

也许你可以做得很好。让我们试试吧

x = {
   'id': 123,
   'data[param1]': 'hello',
   'data[param2]': 'world',
}

https://github.com/requests/requests/issues/2885

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-17
    • 2021-08-12
    相关资源
    最近更新 更多