13.1 HttpProxyMiddleware
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论