Мне пришлось сделать нечто подобное, используя базовую аутентификацию, так как пример кода для запроса аутентификации не работал, вот версия, которая работает:
import base64
from twisted.internet import defer, reactor
from twisted.web import client, error, http
from ubuntuone.devtools.testcases.squid import SquidTestCase
# ignore common twisted lint errors
# pylint: disable=C0103, W0212
class ProxyClientFactory(client.HTTPClientFactory):
"""Factory that supports proxy."""
def __init__(self, proxy_url, proxy_port, url, headers=None):
self.proxy_url = proxy_url
self.proxy_port = proxy_port
client.HTTPClientFactory.__init__(self, url, headers=headers)
def setURL(self, url):
self.host = self.proxy_url
self.port = self.proxy_port
self.url = url
self.path = url
class ProxyWebClient(object):
"""Provide useful web methods with proxy."""
def __init__(self, proxy_url=None, proxy_port=None, username=None,
password=None):
"""Create a new instance with the proxy settings."""
self.proxy_url = proxy_url
self.proxy_port = proxy_port
self.username = username
self.password = password
def _process_auth_error(self, failure, url, contextFactory):
"""Process an auth failure."""
# we try to get the page using the basic auth
failure.trap(error.Error)
if failure.value.status == str(http.PROXY_AUTH_REQUIRED):
auth = base64.b64encode('%s:%s' % (self.username, self.password))
auth_header = 'Basic ' + auth.strip()
factory = ProxyClientFactory(self.proxy_url, self.proxy_port, url,
headers={'Proxy-Authorization': auth_header})
# pylint: disable=E1101
reactor.connectTCP(self.proxy_url, self.proxy_port, factory)
# pylint: enable=E1101
return factory.deferred
else:
return failure
def get_page(self, url, contextFactory=None, *args, **kwargs):
"""Download a webpage as a string.
This method relies on the twisted.web.client.getPage but adds and extra
step. If there is an auth error the method will perform a second try
so that the username and password are used.
"""
scheme, _, _, _ = client._parse(url)
factory = ProxyClientFactory(self.proxy_url, self.proxy_port, url)
if scheme == 'https':
from twisted.internet import ssl
if contextFactory is None:
contextFactory = ssl.ClientContextFactory()
# pylint: disable=E1101
reactor.connectSSL(self.proxy_url, self.proxy_port,
factory, contextFactory)
# pylint: enable=E1101
else:
# pylint: disable=E1101
reactor.connectTCP(self.proxy_url, self.proxy_port, factory)
# pylint: enable=E1101
factory.deferred.addErrback(self._process_auth_error, url,
contextFactory)
return factory.deferred