Я не смог понять все детали вашей конкретной проблемы, но я вполне уверен, что коренная причина заключается в следующем:
Python 3 различает два типа строк, str
и bytes
, которые похожи, но несовместимы.
Как только вы поймете, что это означает, что каждый из них может / не может делать и как переходить от одного к другому, я уверен, что вы сможете понять, как правильно построить URL для вызова API.
Различные типы, несовместимые:
>>> type('abc'), type(b'abc')
(<class 'str'>, <class 'bytes'>)
>>> 'abc' + b'abc'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be str, not bytes
>>> b'abc' + 'abc'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't concat str to bytes
Если вы хотите объединить их, вам нужно преобразовать все в один и тот же тип.
Для преобразования кодируйте str
в bytes
, декодируйте bytes
в str
:
>>> 'abc'.encode()
b'abc'
>>> b'abc'.decode()
'abc'
Методы str.encode
и bytes.decode
принимают необязательный параметр encoding=
, который по умолчанию равен UTF-8.
Этот параметр определяет отображение между символами в str
и октетами в bytes
объекте.
Если существует проблема с отображением символов в байты с заданной кодировкой, вы увидите UnicodeEncodeError
.
Это происходит, если вы используете символ, который не определен в данном отображении:
>>> '5 £'.encode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character '\xa3' in position 2: ordinal not in range(128)
Аналогично, если какой-то текст был закодирован с кодировкой X, но вы пытаетесь декодировать его с кодировкой Y, вы можете увидеть UnicodeDecodeError
:
>>> b = '5 £'.encode('utf8')
>>> b
b'5 \xc2\xa3'
>>> b.decode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 2: ordinal not in range(128)
Вы можете избежать исключения с помощью стратегии errors="ignore"
, но вы потеряете информацию таким образом:
>>> '5 £'.encode('ascii', errors='ignore')
b'5 '
Как правило, если вы работаете с текстом, вы используете str
везде.
Вам также не нужно часто использовать .encode/.decode
напрямую; часто обработчики файлов и т. д. принимают str
и преобразуют их в bytes
за сценой.
В вашем случае вам нужно выяснить, где и почему у вас есть смесь str
и bytes
, а затем убедиться, что все имеют один и тот же тип, прежде чем объединять.