Python urllib.request.Request параметр 'data' тип объекта

Я пытаюсь использовать urllib.request.Request (Python 3.6.7), чтобы вызвать API для внутренних веб-сервисов, чтобы получить некоторые результаты JSON. Мне нужно отправить некоторые данные и заголовки на сервер, поэтому я использую класс urllib.request.Request для этого. Для ввода данных я стараюсь выяснить, в каком формате он будет принимать. Из документов Python сказано:

Поддерживаемые типы объектов включают байты, файловые объекты и итерации.

Поэтому я использую тип данных словаря для данных этого параметра. Вот мой код:

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

Затем я следую примеру на этой странице документации и изменяю свой код на:

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)

тогда это работает.

У меня такой вопрос, не указано ли в документации, что этот класс принимаетитерируемые типы данных? почему мой параметр в dict неверен? Мой окончательный результат - использование метода str.encode(), который возвращает байтовый объект, и кажется, что этот класс должен принимать байтовый объект, а не итерируемый объект.

Я пытаюсь использовать документы стандартной библиотеки Python в качестве основного источника ссылки на код в Python, однако мне трудно его использовать, надеюсь, кто-нибудь сможет пролить свет на то, чтобы помочь мне понять больше о том, как работает библиотека документов, или, если есть какой-то другой учебник, мне нужно пройти, прежде чем я смогу использовать его лучше. Благодарю.

1 ответ

Я согласен с вами, документ не является явным. Подразумевается, что если data Параметр является итерируемым, он должен быть итерируемым из байтов. Когда я попытался передать строку как данные, я получил явное сообщение об ошибке:

Ошибка TypeEr: данные POST должны быть байтами, итерируемыми байтами или файловым объектом. Это не может быть типа ул.

По этой причине повторяемое не может быть словарем. В качестве примера действительного итерируемого объекта, который не является байтовым объектом (хорошо, просто пример, нет причин использовать это в реальном коде...):

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)
Другие вопросы по тегам