Имеет ли Python витая структура HttpClient для доступа к прокси? - PullRequest
3 голосов
/ 30 октября 2009

Мне нужно получить доступ к веб-странице, используя

twisted.web.client.getPage()

или аналогичный метод для загрузки веб-страницы с известного адреса (например, www.google.com), проблема заключается в следующем: я нахожусь за прокси-сервером и нигде не могу найти объяснения о том, как настроить витую или фабрики использовать мой прокси, есть идеи?

Имейте в виду, я должен указать пользователя, пароль, хост и порт. На моем компьютере с Linux я устанавливаю http_proxy и https_proxy на http://user:pwd@ip:port

Спасибо заранее.

Ответы [ 4 ]

3 голосов
/ 31 октября 2009
from twisted.internet import reactor
from twisted.web import client

def processResult(page):
    print "I got some data", repr(page)
    reactor.callLater(0.1, reactor.stop)
def dealWithError(err):
    print err.getErrorMessage()
    reactor.callLater(0.1, reactor.stop)

class ProxyClientFactory(client.HTTPClientFactory):
    def setURL(self, url):
        client.HTTPClientFactory.setURL(self, url)
        self.path = url

factory = ProxyClientFactory('http://url_you_want')
factory.deferred.addCallbacks(processResult, dealWithError)

reactor.connectTCP('proxy_address', 3142, factory)
reactor.run()
1 голос
/ 15 декабря 2011

Мне пришлось сделать нечто подобное, используя базовую аутентификацию, так как пример кода для запроса аутентификации не работал, вот версия, которая работает:

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
1 голос
/ 09 ноября 2009

Чтобы заставить работать решение nosklo, вам нужно создать еще один обработчик для '401', который указывает, что требуется аутентификация. Попробуйте что-то вроде этого

def checkAuthError(self,failure,url):
    failure.trap(error.Error)
    if failure.value.status == '401':
        username = raw_input("User name: ")
        password = getpass.getpass("Password: ")
        auth = base64.encodestring("%s:%s" %(username, password))
        header = "Basic " + auth.strip()
        return client.getPage(
            url, headers={"Authorization": header})
    else:
        return failure

Это побудит оператора предоставить информацию в командной строке, иначе вы можете ввести имя пользователя и пароль другим способом по вашему выбору. Убедитесь, что это первый обработчик, добавленный как Errback, перед добавлением любых других обработчиков, даже Callback. Это также требует еще немного импорта; 'base64', 'getpass' и 'error' для работы с приглашениями командной строки.

0 голосов
/ 04 ноября 2011

Мы решили использовать переменную окружения http_proxy. У нас были проблемы с перенаправлениями, которые не всегда были подобраны, или, скорее, правильно подобраны. Тем не менее, ответ nosklo действительно помог!

import os
from twisted.web import client

class ProxyClientFactory(client.HTTPClientFactory):
    def setURL(self, url):
        '''More sensitive to redirects that can happen, that
        may or may not be proxied / have different proxy settings.'''
        scheme, host, port, path = client._parse(url)
        proxy = os.environ.get('%s_proxy' % scheme)
        if proxy:
            scheme, host, port, path = client._parse(proxy)
            self.scheme = scheme
            self.host = host
            self.port = port
            self.path = url
            self.url = url
        else:
            client.HTTPClientFactory.setURL(self, url)

factory = ProxyClientFactory(url)
# Callback configuration
# If http_proxy or https_proxy, or whatever appropriate proxy
# is set, then we should try to honor that. We do so simply 
# by overriding the host/port we'll connect to. The client
# factory, BaseRequestServicer takes care of the rest
scheme, host, port, path = client._parse(url)
proxy = os.environ.get('%s_proxy' % scheme)
if proxy:
    scheme, host, port, path = client._parse(proxy)
reactor.connectTCP(host, port, factory)
...