Python urllib.request.Request параметр 'data' тип объекта - PullRequest
0 голосов
/ 21 февраля 2019

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

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

Поэтому для этого параметра я использую словарь тип данных 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 и меняю свой кодto:

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 () , который возвращает объект байта , и кажется, что этот класс должен принимать объект байта, а не объект итерируемых объектов.

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

1 Ответ

0 голосов
/ 21 февраля 2019

Я согласен с вами, документ не является явным.Неявным является то, что если параметр 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)
...