返回介绍

13.1 HttpProxyMiddleware

发布于 2024-02-05 21:13:20 字数 4159 浏览 0 评论 0 收藏 0

Scrapy内部提供了一个下载中间件HttpProxyMiddleware,专门用于给Scrapy爬虫设置代理。

13.1.1 使用简介

HttpProxyMiddleware默认便是启用的,它会在系统环境变量中搜索当前系统代理(名字格式为xxx_proxy的环境变量),作为Scrapy爬虫使用的代理。

假设我们现在有两台在云上搭建好的代理服务器:

http://116.29.35.201:8118

http://197.10.171.143:8118

为本机的Scrapy爬虫分别设置发送HTTP和HTTPS请求时所使用的代理,只需在bash中添加环境变量:

$ export http_proxy="http://116.29.35.201:8118"  # 为HTTP请求设置代理
$ export https_proxy="http://197.10.171.143:8118" # 为HTTPS请求设置代理

配置完成后,Scrapy爬虫将会使用上面指定的代理下载页面,我们可以通过以下实验进行验证。

利用网站http://httpbin.org提供的服务可以窥视我们所发送的HTTP(S)请求,如请求源IP地址、请求头部、Cookie信息等。图13-2展示了该网站各种服务的API地址。

访问http(s)://httpbin.org/ip将返回一个包含请求源IP地址信息的json串,在scrapy shell中访问该url,查看请求源IP地址:

图13-2

$ scrapy shell
...
>>> import json
>>> fetch(scrapy.Request('http://httpbin.org/ip')) # 发送HTTP请求
[scrapy] DEBUG: Crawled (200)  (referer: None)
>>> json.loads(response.text)
{'origin': '116.29.35.201'}
>>> fetch(scrapy.Request('https://httpbin.org/ip')) # 发送HTTPS请求
[scrapy] DEBUG: Crawled (200)  (referer: None)
>>> json.loads(response.text)
{'origin': '197.10.171.143'}

在上述实验中,分别以HTTP和HTTPS发送请求,使用json模块对响应结果进行解析,读取请求源IP地址(origin字段),其值正是代理服务器的IP。由此证明,Scrapy爬虫使用了我们指定的代理。

上面我们使用的是无须身份验证的代理服务器,还有一些代理服务器需要用户提供账号、密码进行身份验证,验证成功后才提供代理服务,使用此类代理时,可按以下格式配置:

$ export http_proxy="http://liushuo:12345678@113.24.36.24:7777"

13.1.2 源码分析

虽然使用HttpProxyMiddleware很简单,但大家最好对其工作原理有所了解,以下是HttpProxyMiddleware的源码:

import base64
from six.moves.urllib.request import getproxies, proxy_bypass
from six.moves.urllib.parse import unquote
try:
 from urllib2 import _parse_proxy
except ImportError:
 from urllib.request import _parse_proxy
from six.moves.urllib.parse import urlunparse
from scrapy.utils.httpobj import urlparse_cached
from scrapy.exceptions import NotConfigured
from scrapy.utils.python import to_bytes

class HttpProxyMiddleware(object):

 def __init__(self, auth_encoding='latin-1'):
   self.auth_encoding = auth_encoding
   self.proxies = {}
   for type, url in getproxies().items():
    self.proxies[type] = self._get_proxy(url, type)

   if not self.proxies:
    raise NotConfigured

 @classmethod
 def from_crawler(cls, crawler):
   auth_encoding = crawler.settings.get('HTTPPROXY_AUTH_ENCODING')
   return cls(auth_encoding)
 def _get_proxy(self, url, orig_type):
   proxy_type, user, password, hostport = _parse_proxy(url)
   proxy_url = urlunparse((proxy_type or orig_type, hostport, '', '', '', ''))
   if user:
    user_pass = to_bytes(
    '%s:%s' % (unquote(user), unquote(password)),
    encoding=self.auth_encoding)
  creds = base64.b64encode(user_pass).strip()
 else:
  creds = None

 return creds, proxy_url

def process_request(self, request, spider):
 # ignore if proxy is already set
 if 'proxy' in request.meta:
  return

 parsed = urlparse_cached(request)
 scheme = parsed.scheme

 # 'no_proxy' is only supported by http schemes
 if scheme in ('http', 'https') and proxy_bypass(parsed.hostname):
  return

 if scheme in self.proxies:
  self._set_proxy(request, scheme)

def _set_proxy(self, request, scheme):
 creds, proxy = self.proxies[scheme]
 request.meta['proxy'] = proxy
 if creds:
  request.headers['Proxy-Authorization'] = b'Basic ' + creds

分析代码如下:

__init__方法

在HttpProxyMiddleware的构造器中,使用Python标准库urllib中的getproxies函数在系统环境变量中搜索系统代理的相关配置(变量名格式为[协议]_proxy的变量),调用self._get_proxy方法解析代理配置信息,并将其返回结果保存到self.proxies字典中,如果没有找到任何代理配置,就抛出NotConfigured异常,HttpProxyMiddleware被弃用。

_get_proxy方法

解析代理配置信息,返回身份验证信息(后面讲解)以及代理服务器url。

process_request方法

处理每一个待发送的请求,为没有设置过代理的请求(meta属性不包含proxy字段的请求)调用self._set_proxy方法设置代理。

_set_proxy方法

为一个请求设置代理,以请求的协议(HTTP或HTTPS)作为键,从代理服务器信息字典self.proxies中选择代理,赋给request.meta的proxy字段。对于需要身份验证的代理服务器,添加HTTP头部Proxy-Authorization,其值是在_get_proxy方法中计算得到的。

经分析得知,在Scrapy中为一个请求设置代理的本质就是将代理服务器的url填写到request.meta['proxy']。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文