Форум сайта python.su
Добрый день.
Писал тут асинхронный торрент-клиент полностью на asyncio и aiohttp и внезапно столкнулся с проблемой. Кратко введу в курс дела: информация о торренте хранится в специальном .torrent файле, который внутри себя содержит utf-8 текст с незатейливо закодированным словарём. Для того, чтобы идентифицировать торрент, клиенты и трекеры берут sha1-хэш от определённой части этого словаря, я это делаю примерно так:
info_dict = {} # какой-то словарь hash = hashlib.sha1(bencoding.encode(info_dict)).digest() # bytes, длиной 20
# составляем словарь с аргументами для запроса - Dict[str, Any] params = { 'info_hash': hash, 'compact': 1, # ... и т.д. } # открываем (или берём уже имеющуюся) сессию session = aiohttp.ClientSession(loop=asyncio.get_event_loop()) # делаем запрос async with session.get(announcer, params=params) as response: return await response.read()
>>>str(hash) # конечно, нет "b'Y;o]G\xd7gb[\x8e\xe7\x1a...'" >>>hashlib.sha1(bencoding.encode(info_dict)).hexdigest() # нет '593b6f5d47d767625....' >>>urllib.parse.quote(hash) # опять нет 'Y%3Bo%5DG%D7gb%5B%8E%E7%...' >>>urllib.parse.quote(str(hash)[2:-1]) # не-а >>>hash.decode(????) >>>yarl.quote(hash) # нет такого торрента!
Офлайн
greeblieНе понял, где “тут”, полный трейсбек выложи.
И вот тут возникает ошибка:
greeblieВот это (эти дебри) надо выкладывать, а не перессказывать словами.
Которая ведёт куда-то в дебри
Отредактировано py.user.next (Янв. 5, 2017 02:29:47)
Офлайн
Пересказывал словами я исключительно для того, чтобы было понятно, что и зачем я вообще делаю)
А вопрос заключался в том, как правильно закодировать байты для передачи через get. Неприятно, конечно, что серьёзная библиотека вдруг перестала принимать bytes в качестве аргументов без каких-либо указаний на то в документации, но, кажется, с этим без модификации её кода ничего не поделать.
Вот трейсбек, тем не менее:
future: <Task finished coro=<BaseTrackerClient.query() done, defined at D:\Files\BitTorrent\modules\tracker\base_tracker.py:52> exception=TypeError("Invalid variable type: mapping value should be str or int, got b'Y;o]G\\xd7gb[\\x8e\\xe7\\x1a\\xa03\\x92\\x9fuv'",)> Traceback (most recent call last): File "D:\Files\Python\3.5\lib\asyncio\tasks.py", line 239, in _step result = coro.send(None) File "D:\Files\BitTorrent\modules\tracker\base_tracker.py", line 57, in query timeout=timeout) File "D:\Files\Python\3.5\lib\asyncio\tasks.py", line 392, in wait_for return fut.result() File "D:\Files\Python\3.5\lib\asyncio\futures.py", line 274, in result raise self._exception File "D:\Files\Python\3.5\lib\asyncio\tasks.py", line 239, in _step result = coro.send(None) File "D:\Files\BitTorrent\modules\tracker\http_tracker.py", line 26, in _make_request async with self._session.get(self.announcer, params=data) as response: File "D:\Files\Python\3.5\lib\site-packages\aiohttp\client.py", line 540, in __aenter__ self._resp = yield from self._coro File "D:\Files\Python\3.5\lib\site-packages\aiohttp\client.py", line 173, in _request proxy=proxy, proxy_auth=proxy_auth, timeout=timeout) File "D:\Files\Python\3.5\lib\site-packages\aiohttp\client_reqrep.py", line 79, in __init__ url2 = url.with_query(params) File "D:\Files\Python\3.5\lib\site-packages\yarl\__init__.py", line 678, in with_query "should be str or int, got {!r}".format(v)) TypeError: Invalid variable type: mapping value should be str or int, got b'Y;o]G\xd7gb[\x8e\xe7\x1a\xa03\x92\x9fuv'
Офлайн
Раскодировать из байтов в строку можешь так
>>> b'Y;o]G\xd7gb[\x8e\xe7\x1a\xa03\x92\x9fuv'.decode('latin1') 'Y;o]G×gb[\x8eç\x1a\xa03\x92\x9fuv' >>>
Офлайн
Да, действительно, не догадался использовать именно latin1. Тем не менее, трекер всё равно возвращает ошибку, жалуясь на неправильный хэш. Изменение кодировки http запроса со стандартной utf-8 на latin1
async with session.get(announcer, params=params, encoding='latin1') as response: ...
Офлайн
Requests, кстати, справляется с без проблем и принимает байты, жаль только, что не асинхронный.
А вот urllib.parse.quote_from_bytes() никакого эффекта не даёт. Ничего уже не понимаю.
UPD:
справился с проблемой с помощью urllib.parse.urlencode(), который кодирует так, как надо.
Отредактировано greeblie (Янв. 5, 2017 18:28:41)
Офлайн