【问题标题】:Making post request using urllib使用 urllib 发出 post 请求
【发布时间】:2023-11-15 12:03:01
【问题描述】:

我正在尝试向 API 提供者提出请求

curl "https://api.infermedica.com/dev/parse" \
  -X "POST" \
  -H "App_Id: 4c177c" -H "App_Key: 6852599182ba85d70066986ca2b3" \
  -H "Content-Type: application/json" \
  -d '{"text": "i feel smoach pain but no couoghing today"}'    

此 curl 请求给出响应。

但是当我尝试在代码中提出同样的要求时

self.headers = { "App_Id": "4c177c", "App_Key": "6852599182ba85d70066986ca2b3", "Content-Type": "application/json", "User-Agent": "M$

self.url = "https://api.infermedica.com/dev/parse"

data = { "text": text }
json_data = json.dumps(data)
req = urllib2.Request(self.url, json_data.replace(r"\n", "").replace(r"\r", ""), self.headers)
response = urllib2.urlopen(req).read()

它给了

Traceback (most recent call last):
  File "symptoms_infermedia_api.py", line 68, in <module>
    SymptomsInfermedia().getResponse(raw_input("Enter comment"))
  File "symptoms_infermedia_api.py", line 39, in getResponse
    response = urllib2.urlopen(req).read()
  File "/usr/lib/python2.7/urllib2.py", line 127, in urlopen
    return _opener.open(url, data, timeout)
  File "/usr/lib/python2.7/urllib2.py", line 410, in open
    response = meth(req, response)
  File "/usr/lib/python2.7/urllib2.py", line 523, in http_response
    'http', request, response, code, msg, hdrs)
  File "/usr/lib/python2.7/urllib2.py", line 448, in error
    return self._call_chain(*args)
  File "/usr/lib/python2.7/urllib2.py", line 382, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.7/urllib2.py", line 531, in http_error_default
    raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
urllib2.HTTPError: HTTP Error 403: Forbidden

【问题讨论】:

  • 你对使用urllib2 已经死心了吗?因为requests 有一个更好的http 请求接口。
  • 我足够灵活,可以尝试请求
  • @BrendanAbel: r = requests.post("https://api.infermedica.com/dev/parse",json = { "App_Id": "7247c", "App_Key": "68599182ba85d70066986ca2b3", "Content-Type": "application/json"}) 也给出了同样的错误信息

标签: python curl request urllib2


【解决方案1】:

这将是使用 python requests 库的等效请求。

url = "https://api.infermedica.com/dev/parse"
headers = {
    'App_Id': '4c177c',
    'App_Key': '6852599182ba85d70066986ca2b3',
    'Content-Type': 'application/json',
}
data = {'text': 'i feel stomach pain but no coughing today'}

r = requests.post(url, headers=headers, data=json.dumps(data))
print r.status_code
print r.json()

但你真正的问题是你为他们的 api 使用了错误的标题键。这是App-IdApp-key,而不是App_IdApp_key。它看起来像这样:

headers = {
    'App-Id': 'xx', 
    'App-key': 'xxxx', 
    'Accept': 'application/json', 
    'Content-Type': 'application/json',
    'Dev-Mode': 'true'}

data = {'text': 'i feel stomach pain but no coughing today'}
r = requests.post(url, headers=headers, data=json.dumps(data))

另外值得注意的是,他们有一个 python api 可以为您完成所有这些工作。

【讨论】:

  • @Brendam:感谢您如此敏锐的观察。这种问题我以后会处理的
【解决方案2】:

json_data = json.dumps(data) 不是准备 POST 数据的正确方法。

您应该使用urllib.urlencode() 来完成这项工作:

import urllib
data = { "text": text }
req = urllib2.Request(self.url, urllib.urlencode(data), self.headers)
response = urllib2.urlopen(req).read()

Docs

class urllib2.Request(url[, data][, headers][, origin_req_host][, unverifiable]) 此类是 URL 请求的抽象。

data 可以是一个字符串,指定要发送到服务器的附加数据, 如果不需要此类数据,则为 None。目前 HTTP 请求是 只有那些使用数据的人; HTTP 请求将是 POST 而不是 提供数据参数时获取。数据应该是一个缓冲区 标准的应用程序/x-www-form-urlencoded 格式。 该 urllib.urlencode() 函数采用 2 元组的映射或序列 并以这种格式返回一个字符串。

【讨论】:

  • 您是否仔细检查了headers 中的这些参数?我猜服务器端有一些限制。
  • 如果还是不行,可以使用本地代理(例如fiddler)调试这个请求,看看curl和python请求的区别