Как сохранить куки для xmlrpc.client в Python 3?
Python по умолчанию xmlrpc.client.Transport
(может использоваться с xmlrpc.client.ServerProxy
) не сохраняет файлы cookie, которые иногда необходимы для входа на основе файлов cookie.
Например, следующий прокси-сервер при использовании с API-интерфейсом TapaTalk (для которого login
метод использует куки для аутентификации), выдаст ошибку разрешения при попытке изменить посты.
proxy = xmlrpc.client.ServerProxy(URL, xmlrpc.client.Transport())
В сети есть несколько решений для Python 2, но они не совместимы с Python 3.
Как я могу использовать Transport
что сохраняет куки?
2 ответа
Это простой Transport
подкласс, который сохранит все куки:
class CookiesTransport(xmlrpc.client.Transport):
"""A Transport subclass that retains cookies over its lifetime."""
def __init__(self):
super().__init__()
self._cookies = []
def send_headers(self, connection, headers):
if self._cookies:
connection.putheader("Cookie", "; ".join(self._cookies))
super().send_headers(connection, headers)
def parse_response(self, response):
for header in response.msg.get_all("Set-Cookie"):
cookie = header.split(";", 1)[0]
self._cookies.append(cookie)
return super().parse_response(response)
Использование:
proxy = xmlrpc.client.ServerProxy(URL, CookiesTransport())
поскольку xmlrpc.client
в Python 3 для этого лучше подходят ловушки, это намного проще, чем в эквивалентной версии Python 2.
Существующий ответ от GermainZ работает только для HTTP. После большого количества времени, борющегося с этим, есть адаптация HTTPS. Обратите внимание context
вариант, который имеет решающее значение.
class CookiesTransport(xmlrpc.client.SafeTransport):
"""A SafeTransport (HTTPS) subclass that retains cookies over its lifetime."""
# Note context option - it's required for success
def __init__(self, context=None):
super().__init__(context=context)
self._cookies = []
def send_headers(self, connection, headers):
if self._cookies:
connection.putheader("Cookie", "; ".join(self._cookies))
super().send_headers(connection, headers)
def parse_response(self, response):
# This check is required if in some responses we receive no cookies at all
if response.msg.get_all("Set-Cookie"):
for header in response.msg.get_all("Set-Cookie"):
cookie = header.split(";", 1)[0]
self._cookies.append(cookie)
return super().parse_response(response)
Причина в том, что ServerProxy не уважает context
Опция относится к транспорту, если указан транспорт, поэтому нам нужно использовать его непосредственно в конструкторе транспорта.
Использование:
import xmlrpc.client
import ssl
transport = CookiesTransport(context=ssl._create_unverified_context())
# Note the closing slash in address as well, very important
server = xmlrpc.client.ServerProxy("https://<api_link>/", transport=transport)
# do stuff with server
server.myApiFunc({'param1': 'x', 'param2': 'y'})