如何使用Python的requests库进行POST请求?

10
我正在使用Postman中的以下过滤器在Web API中进行POST请求,但是我无法使用requests库在Python中进行简单的POST请求。 首先,我正在向此URL(http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets)发送POST请求,并将下列过滤器应用于Body,选择原始和JSON(application/json)选项。请注意保留HTML标签。
Filters in Postman

{
  "filter": {
    "filters": [
      {
        "field": "RCA_Assigned_Date",
        "operator": "gte",
        "value": "2017-05-31 00:00:00"
      },
      {
        "field": "RCA_Assigned_Date",
        "operator": "lte",
        "value": "2017-06-04 00:00:00"
      },
      {
        "field": "T_Subcategory",
        "operator": "neq",
        "value": "Temporary Degradation"
      },
      {
        "field": "Issue_Status",
        "operator": "neq",
        "value": "Queued"
      }],
     "logic": "and"
    }
}

数据库中存储数据的是Cassandra,根据以下链接Cassandra不等运算符Cassandra OR运算符Cassandra Between order by运算符,Cassandra不支持不等于或者介于这些操作符,所以除了使用AND之外,我无法使用这些操作符过滤URL。

其次,我正在使用以下代码使用requests库应用简单的过滤器。

import requests
payload = {'field':'T_Subcategory','operator':'neq','value':'Temporary Degradation'}
url = requests.post("http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets",data=payload)

但是我拥有的是全部票务数据,而不仅仅是那些没有临时降级的数据。

第三点,系统实际上是在工作的,但我们需要延迟2-3分钟才能看到数据。逻辑如下:我们有8个用户,想要查看每个用户不是临时降级的所有票务信息,然后我们执行以下操作:

def get_json():
    if user_name == "user 001":
        with urllib.request.urlopen(
    "http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets?user_name=user&001",timeout=15) as url:
            complete_data = json.loads(url.read().decode())

    elif user_name == "user 002":
        with urllib.request.urlopen(             
    "http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets?user_name=user&002",timeout=15) as url:
            complete_data = json.loads(url.read().decode())
    return complete_data

def get_tickets_not_temp_degradation(start_date,end_date,complete_):
    return Counter([k['user_name'] for k in complete_data if start_date < dateutil.parser.parse(k.get('DateTime')) < end_date and k['T_subcategory'] != 'Temporary Degradation'])

基本上,我们从当前和去年得到了整套门票,然后让Python通过用户来过滤完整的集合,目前只有10个用户,这意味着这个过程重复了10次,也就不足为奇为什么会出现延迟问题...
我的问题是如何解决requests库的问题?我正在使用以下链接作为教程Requests library documentation让它工作,但似乎我的有效载荷没有被读取。

当使用类JSON数据时,我曾经成功地使用json关键字参数代替data - wbadart
1
data=payload替换为json=payload - Burhan Khalid
我尝试将data=payload更改为json=payload,但是没有成功。:( - abautista
Postman 过滤器起作用了,这表明查询之间的不等操作或操作是有效的。 - abautista
@AlejandroRamos:此外,urllib.requests.urlopen的URL看起来格式不正确;user_name=user&001是两个单独的字段。你确定这不应该是user_name=user+001吗? - Martijn Pieters
显示剩余6条评论
4个回答

12

您的Postman请求是一个JSON主体。只需在Python中复制相同的主体即可。您的Python代码既没有发送JSON,也没有发送与您的Postman示例相同的数据。

首先,通过data参数发送字典会将该字典编码为application/x-www-form-urlencoded格式,而不是JSON。其次,您似乎正在发送单个过滤器。

以下代码完全复制了您的Postman帖子:

import requests

filters = {"filter": {
    "filters": [{
        "field": "RCA_Assigned_Date",
        "operator": "gte",
        "value": "2017-05-31 00:00:00"
    }, {
        "field": "RCA_Assigned_Date",
        "operator": "lte",
        "value": "2017-06-04 00:00:00"
    }, {
        "field": "T_Subcategory",
        "operator": "neq",
        "value": "Temporary Degradation"
    }, {
        "field": "Issue_Status",
        "operator": "neq",
        "value": "Queued"
    }],
    "logic": "and"
}}

url = "http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets"
response = requests.post(url, json=filters)

请注意,这里的filters是一个Python数据结构,并且它被传递给json关键字参数。使用后者会做两件事情:
  • 将Python数据结构编码为JSON(生成与原始Postman正文值完全相同的JSON值)。
  • Content-Type标头设置为application/json(就像在Postman配置中选择raw正文后,在下拉菜单中选择JSON选项一样)。

requests本质上只是一个HTTP API,它不能让Cassandra做任何其他HTTP库无法做到的事情。 urllib.request.urlopen代码发送GET请求,并且可以通过以下方式轻松转换为requests

def get_json():
    url = "http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets"
    response = requests.get(url, params={'user_name': user}, timeout=15)    
    return response.json()

我移除了if分支,使用params参数替换它,这将字典中的键值对正确编码为URL查询(将用户名作为user_name键传递)。

请注意响应中的json()调用;这将处理从服务器返回的JSON数据的解码。但是这仍然需要很长时间,你没有在这里对Cassandra数据进行过滤。


7

我建议使用json属性而不是data。它会自动处理转储。

import requests

data = {'user_name':'user&001'}
headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
url = "http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets/"
r = requests.post(url, headers=headers, json=data)

更新,回答第3个问题。您为什么要使用urllib?我也会在此请求中使用Python requests。

import requests

def get_json():
    r = requests.get("http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets”, params={"user_name": user_name.replace(" ", "&")})

    return r.json

# not sure what you’re doing here, more context/code example would help
def get_tickets_not_temp_degradation(start_date, end_date, complete_):
    return Counter([k['user_name'] for k in complete_data if start_date < dateutil.parser.parse(k.get('DateTime')) < end_date and k['T_subcategory'] != 'Temporary Degradation'])

此外,用户名是否应该是user+001而不是user&001user 001

0

我认为,您可以按照以下方式使用requests库:

import requests
import json

payload = {'field':'T_Subcategory','operator':'neq','value':'Temporary Degradation'}
url = requests.post("http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets",data=json.dumps(payload))

我这里有一条新消息:消息:请求包含实体主体,但没有Content-Type头。 推断的媒体类型“application / octet-stream”不支持此资源。 - abautista
我通过使用以下方法解决了这个问题:headers = {'Content-type': 'application/json', 'Accept':'text/plain'} 然后 r = requests.post(url,data=json.dumps(payload),headers=headers),但似乎 post 请求检索到了所有数据。 - abautista
你实际上可以只指定 json={"whoami": "I'm a python dict"} 而不是 data=json.dumps... - teewuane

0

你正在通过URL发送用户信息,需要使用POST方法,但这取决于终端点的实现方式。你可以尝试以下代码:

import requests
from json import dumps

data = {'user_name':'user&001'}
headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
url = "http://10.61.202.98:8081/T/a/api/rows/cat/ect/tickets/"
r = requests.post(url, headers=headers, data=dumps(data))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接