我尝试使用 urllib.request.Request (Python 3.6.7)对内部Web服务进行API调用以获得一些json结果。我需要将一些数据和标头发送到服务器,因此我使用 urllib.request.Request 类来执行此操作。对于数据的输入,我尝试找出它将接受的格式。在Python docs中,它表示:
受支持的对象类型包括字节,类文件对象和 Iterables 。
因此,我将 dictionary 数据类型用于此参数 data 。这是我的代码:
import urllib
my_url = "https://httpbin.org/post"
my_headers = { "Content-Type" : "application/x-www-form-urlencoded" }
my_data = {
"client_id" : "ppp",
"client_secret" : "000",
"grant_type" : "client_credentials" }
req = urllib.request.Request(url=my_url, data=my_data, headers=my_headers)
response = urllib.request.urlopen(req)
html = response.read()
print(html)
然后我得到这样的错误:
Traceback (most recent call last):
File "./callapi.py", line 23, in <module>
response = urllib.request.urlopen(req)
File "/usr/lib64/python3.6/urllib/request.py", line 223, in urlopen
return opener.open(url, data, timeout)
File "/usr/lib64/python3.6/urllib/request.py", line 526, in open
response = self._open(req, data)
File "/usr/lib64/python3.6/urllib/request.py", line 544, in _open
'_open', req)
File "/usr/lib64/python3.6/urllib/request.py", line 504, in _call_chain
result = func(*args)
File "/usr/lib64/python3.6/urllib/request.py", line 1361, in https_open
context=self._context, check_hostname=self._check_hostname)
File "/usr/lib64/python3.6/urllib/request.py", line 1318, in do_open
encode_chunked=req.has_header('Transfer-encoding'))
File "/usr/lib64/python3.6/http/client.py", line 1239, in request
self._send_request(method, url, body, headers, encode_chunked)
File "/usr/lib64/python3.6/http/client.py", line 1285, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "/usr/lib64/python3.6/http/client.py", line 1234, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "/usr/lib64/python3.6/http/client.py", line 1064, in _send_output
+ b'\r\n'
TypeError: can't concat str to bytes
然后,我按照此docs页中的示例,并将代码更改为:
import urllib
my_url = "https://httpbin.org/post"
my_headers = { "Content-Type" : "application/x-www-form-urlencoded" }
my_data = {
"client_id" : "ppp",
"client_secret" : "000",
"grant_type" : "client_credentials" }
my_uedata = urllib.parse.urlencode(my_data)
my_edata = my_uedata.encode('ascii')
req = urllib.request.Request(url=my_url, data=my_edata,headers=my_headers)
response = urllib.request.urlopen(req)
html = response.read()
print(html)
然后工作。
我的问题是,不是在说该类接受数据类型 iterables 的文档中吗?为什么我的 dict 中的参数错误?我的最终结果正在工作,使用 str.encode()方法,该方法返回一个byte object,并且该类似乎必须使用字节对象而不是Iterables对象。
我正在尝试使用Python标准库文档作为Python代码参考的主要来源,但是我很难使用它,希望任何人都可以为我提供一些帮助,以帮助我更多地了解库docs可以正常工作,或者是否需要其他教程才能更好地使用它。谢谢。
答案 0 :(得分:1)
我同意你的要求,该文件并不明确。隐含的是,如果data
参数是可迭代的,则它必须是字节的可迭代。当我尝试将字符串作为数据传递时,我收到一条明确的错误消息:
TypeError:POST数据应为字节,字节可迭代或文件对象。不能是str类型。
因此,由于这个原因,可迭代对象不能是字典。作为有效可迭代的一个示例,它不是一个字节对象(好的,只是一个例子,没有理由在实际代码中使用它……):
def dict_iter(d):
for i in d.items():
yield(str(i).encode())
您可以将该生成器用于data
参数:
req = urllib.request.Request(url=my_url, data=dict_iter(my_data), headers=my_headers)