• Scrapy 2.6.2 代理设置,Proxy-Authorization 安全漏洞修复


    Scrapy 2.6.2

    在最新版本的 Scrapy 2.6.2 (2022-07-25) 中,更新了 Proxy-Authorization 的处理逻辑,代理的设置方式也需进行相应的更改:

    官方文档:Release notes — Scrapy 2.6.2 documentation

    httpproxy 源码:scrapy.downloadermiddlewares.httpproxy — Scrapy 2.6.2 documentation

    根据官方描述,相关逻辑编写在 HttpProxyMiddleware 类中,源码文件在本地的路径为:

    Python 安装路径\Lib\site-packages\scrapy\downloadermiddlewares\httpproxy.py,相关代码位置:

    1. def process_request(self, request, spider):
    2.    creds, proxy_url = None, None
    3.    if 'proxy' in request.meta:
    4.        if request.meta['proxy'] is not None:
    5.            creds, proxy_url = self._get_proxy(request.meta['proxy'], '')
    6.    elif self.proxies:
    7.        parsed = urlparse_cached(request)
    8.        scheme = parsed.scheme
    9.        if (
    10.           (
    11.                # 'no_proxy' is only supported by http schemes
    12.                scheme not in ('http', 'https')
    13.                or not proxy_bypass(parsed.hostname)
    14.           )
    15.            and scheme in self.proxies
    16.       ):
    17.            creds, proxy_url = self.proxies[scheme]
    18.    self._set_proxy_and_creds(request, proxy_url, creds)
    19.    
    20. def _set_proxy_and_creds(self, request, proxy_url, creds):
    21.    if proxy_url:
    22.        request.meta['proxy'] = proxy_url
    23.    elif request.meta.get('proxy') is not None:
    24.        request.meta['proxy'] = None
    25.    if creds:
    26.        request.headers[b'Proxy-Authorization'] = b'Basic ' + creds
    27.        request.meta['_auth_proxy'] = proxy_url
    28.    elif '_auth_proxy' in request.meta:
    29.        if proxy_url != request.meta['_auth_proxy']:
    30.            if b'Proxy-Authorization' in request.headers:
    31.                del request.headers[b'Proxy-Authorization']
    32.            del request.meta['_auth_proxy']
    33.    elif b'Proxy-Authorization' in request.headers:
    34.        del request.headers[b'Proxy-Authorization']

    要想在保留代理的条件下删除代理凭据,需要删除 Proxy-Authorization,若一开始在请求中定义了 proxy,例如 request.meta['proxy'] = “http://username:password@some_proxy_server:port,Scrapy 会自动在请求头中设置 Proxy-Authorization,若请求头中已经设置了 Proxy-Authorization,则会导致其被删除掉,所以如果同时定义了 proxy 和 Proxy-Authorization,代码就会报错,例如:scrapy.core.downloader.handlers.http11.TunnelError: Could not open CONNECT tunnel with proxy XXXXXX:XXX [{'status': 407, 'reason': b'XXXXXXX'}]

    以往在 scrapy 中设置代理的方法

    1. 在 middlewares.py 中配置

    方法一:

    1. class ProxyDownloaderMiddleware:
    2.    def process_request(self, request, spider):
    3.        proxy = "some_proxy_server:port"
    4.        request.meta['proxy'] = "http://%(proxy)s" % {'proxy': proxy}
    5.        # 用户名密码认证
    6.        request.headers['Proxy-Authorization'] = basic_auth_header('username', 'password')
    7.        request.headers["Connection"] = "close"
    8.        return None

    方法二:

    1. class ProxyDownloaderMiddleware:
    2.    def process_request(self, request, spider):
    3.        request.meta['proxy'] = "http://some_proxy_server:port"
    4.        proxy_user_pass = "username:password"
    5.        encoded_user_pass = base64.encodestring(proxy_user_pass)
    6.        request.headers['Proxy-Authorization'] = 'Basic ' + encoded_user_pass
    7.        request.headers["Connection"] = "close"
    8.        return None

    上述两种方法还需要在 settings.py 中进行如下配置:

    1. DOWNLOADER_MIDDLEWARES = {
    2.   'dltest.middlewares.ProxyDownloaderMiddleware': 100,
    3. }
    4. ROBOTSTXT_OBEY = False

    2. 在 spider.py 中配置

    1.    def start_requests(self):
    2.        url = "代理测试网址"
    3.        proxy = {'proxy': 'https://username:password@some_proxy_server:port'}
    4.        yield scrapy.Request(url, callback=self.parse, meta=proxy)
    5.    def parse(self, response):
    6.        print(response.text)

    Scrapy 2.6.2 中设置代理的方法

    在 Scrapy 2.6.2 中前两个方法都会报错,可以改为以下方式,HttpProxyMiddleware 会自动在请求头中添加 Proxy-Authorization:

    1. class ProxyDownloaderMiddleware:
    2.    def process_request(self, request, spider):
    3.        proxy = "username:password@some_proxy_server:port"
    4.        request.meta['proxy'] = "http://%s" % proxy
    5.        request.headers["Connection"] = "close"
    6.        return None

    跟之前一样直接在 spider.py 中配置也是可以的,还有一种方式就是将 httpproxy.py 文件中的最后两行代码注释掉也能正常运行,但是不建议使用这种方式,因为官方这么更改是为了防止代理凭据的意外泄漏,肯定是做过大量调研后决定的方案,详细安全漏洞修复说明可以阅读官方文档:

    1. # elif b'Proxy-Authorization' in request.headers:
    2. #   del request.headers[b'Proxy-Authorization']

  • 相关阅读:
    基于PHP+MySQL毕业设计选题管理系统(含论文)
    【R语言】【3】apply,tapply,lapply,sapply,mapply与par函数相关参数
    qrcode.min.js下载
    vue监听浏览器网页关闭和网页刷新
    基于springcloud+web实现智慧养老平台系统项目【项目源码+论文说明】计算机毕业设计
    做SEO为什么有的网站收录很难做?
    CV计算机视觉每日开源代码Paper with code速览-2023.10.12
    C++编程规范总结
    AI赋能药物研发的偶然与必然
    算法对树进行广度优先算法
  • 原文地址:https://blog.csdn.net/Yy_Rose/article/details/126500936