python程序使用代理IP,出现407错误如何解决

134 篇文章 0 订阅
87 篇文章 0 订阅

python(版本2.23.0)爬虫程序使用代理IP,代理服务器返回407错误,这种情况下一般是认证信息传递失败导致,是因为httplib(python2)/http.client(python3) 模块的函数中,如果连接尝试不成功,它会引发 OSError , 需要进行方法封装专门对代理服务器的请求进行处理,用于设置认证信息传递,如下所示:

import re
import requests
from requests.utils import get_auth_from_url
from requests.auth import HTTPDigestAuth
from requests.utils import parse_dict_header
from urllib3.util import parse_url

def get_proxy_autorization_header(proxy, method):
    username, password = get_auth_from_url(proxy)
    auth = HTTPProxyDigestAuth(username, password)
    proxy_url = parse_url(proxy)
    proxy_response = requests.request(method, proxy_url, auth=auth)
    return proxy_response.request.headers['Proxy-Authorization']


class HTTPSAdapterWithProxyDigestAuth(requests.adapters.HTTPAdapter):
    def proxy_headers(self, proxy):
        headers = {}
        proxy_auth_header = get_proxy_autorization_header(proxy, 'CONNECT')
        headers['Proxy-Authorization'] = proxy_auth_header
        return headers


class HTTPAdapterWithProxyDigestAuth(requests.adapters.HTTPAdapter):
    def proxy_headers(self, proxy):
        return {}

    def add_headers(self, request, **kwargs):
        proxy = kwargs['proxies'].get('http', '')
        if proxy:
            proxy_auth_header = get_proxy_autorization_header(proxy, request.method)
            request.headers['Proxy-Authorization'] = proxy_auth_header



class HTTPProxyDigestAuth(requests.auth.HTTPDigestAuth):

    def init_per_thread_state(self):
        # Ensure state is initialized just once per-thread
        if not hasattr(self._thread_local, 'init'):
            self._thread_local.init = True
            self._thread_local.last_nonce = ''
            self._thread_local.nonce_count = 0
            self._thread_local.chal = {}
            self._thread_local.pos = None
            self._thread_local.num_407_calls = None

    def handle_407(self, r, **kwargs):
        """
        Takes the given response and tries digest-auth, if needed.
        :rtype: requests.Response
        """

        # If response is not 407, do not auth
        if r.status_code != 407:
            self._thread_local.num_407_calls = 1
            return r

        s_auth = r.headers.get('proxy-authenticate', '')

        if 'digest' in s_auth.lower() and self._thread_local.num_407_calls < 2:
            self._thread_local.num_407_calls += 1
            pat = re.compile(r'digest ', flags=re.IGNORECASE)
            self._thread_local.chal = requests.utils.parse_dict_header(
                    pat.sub('', s_auth, count=1))

            # Consume content and release the original connection
            # to allow our new request to reuse the same one.
            r.content
            r.close()
            prep = r.request.copy()
            requests.cookies.extract_cookies_to_jar(prep._cookies, r.request, r.raw)
            prep.prepare_cookies(prep._cookies)

            prep.headers['Proxy-Authorization'] = self.build_digest_header(prep.method, prep.url)
            _r = r.connection.send(prep, **kwargs)
            _r.history.append(r)
            _r.request = prep

            return _r

        self._thread_local.num_407_calls = 1
        return r

session = requests.Session()
    def __call__(self, r):
        # Initialize per-thread state, if needed
        self.init_per_thread_state()
        # If we have a saved nonce, skip the 407
        if self._thread_local.last_nonce:
            r.headers['Proxy-Authorization'] = self.build_digest_header(r.method, r.url)

        r.register_hook('response', self.handle_407)
        self._thread_local.num_407_calls = 1

        return r
        
# 代理服务器(产品官网 www.16yun.cn)
proxyHost = "t.16yun.cn"
proxyPort = "31111"

# 代理验证信息
proxyUser = "username"
proxyPass = "password"

proxyMeta = "http://%(user)s:%(pass)s@%(host)s:%(port)s" % {
        "host" : proxyHost,
        "port" : proxyPort,
        "user" : proxyUser,
        "pass" : proxyPass,
}

session.proxies = {
    'http': proxyMeta,
    'https':proxyMeta,
}
session.trust_env = False

session.mount('http://', HTTPAdapterWithProxyDigestAuth())
session.mount('https://', HTTPSAdapterWithProxyDigestAuth())

response_http = session.get("http://www.baidu.com/")
print(response_http.status_code)

response_https = session.get("https://www.baidu.com")
print(response_https.status_code)

上面代码这段代码定义了一系列用于HTTP 代理服务器进行身份验证的类。例如,它定义了 HTTPSAdapterWithProxyDigestAuth 类,该类可用于代理服务器进行 HTTPS 请求的身份验证。它还定义了 HTTPAdapterWithProxyDigestAuth 类,该类可用于代理服务器进行 HTTP 请求的身份验证。此外,它还定义了 HTTPProxyDigestAuth 类,该类继承自 requests.auth.HTTPDigestAuth 类,并扩展了它,以便支持在处理 407 错误响应时进行多次身份验证。
欢迎私信联系索取更多资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
出现-352错误通常是由于Python爬虫程序在请求网页时遇到了错误或异常。具体的错误信息可能会有所不同,需要查看具体的错误提示来确定问题的原因。以下是一些常见的导致-352错误的可能原因和解决方法: 1. 网络连接问题:-352错误可能是由于网络连接问题导致的。可以尝试检查网络连接是否正常,或者尝试使用其他网络环境进行测试。 2. 请求被拒绝:有些网站会对爬虫程序进行限制,可能会拒绝爬虫程序的请求。可以尝试使用代理IP或者设置合适的请求头信息来规避这种限制。 3. 验证码或人机验证:有些网站为了防止爬虫程序的访问,会设置验证码或人机验证。如果遇到这种情况,可以尝试使用自动识别验证码的库或者手动输入验证码来解决。 4. 网站反爬虫策略:一些网站会采取反爬虫策略,如设置访问频率限制、IP封禁等。如果遇到这种情况,可以尝试降低请求频率、使用代理IP或者模拟真实用户行为来规避反爬虫策略。 5. 网页结构变化:有些网站的网页结构可能会发生变化,导致爬虫程序无法正确解析网页内容。可以尝试更新爬虫程序的解析逻辑,适应网页结构的变化。 以上是一些常见的导致-352错误的原因和解决方法,具体的解决方法需要根据具体的情况来确定。如果你能提供更多的错误信息或代码片段,我可以给出更具体的帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值