使用HTTP代理
HTTP代理服务器可以比作客户端与Web服务器网站之间的一个信息中转站,客户端发送的HTTP请求和Web服务器返回的HTTP响应通过代理服务器转发给对方,
爬虫程序在爬取某些网站的时候也需要使用代理,例如
- 由于网络环境因素,直接爬取的速度太慢了,使用代理提高爬取的速度
- 某些网站读用户的访问速度进行限制,爬取过快会被封禁IP,使用代理防止被封禁
- 由于地方法律或者政治的原因,某些网站是无法直接进行访问的,使用代理可以绕过访问的限制
在scrapy中专门提供了HttpProxyMiddleware来给scrapy爬虫设置代理
HttpProxyMiddleware默认就是开启的,它会在系统环境变量中搜索当前系统代理,作为scrapy爬虫使用的代理
源码解析:
__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']中
使用多个代理:
利用HttpProxyMiddleware为爬虫设置代理的时候,对于一种协议(HTTPShuozheHTTP)的所有请求只能使用一个代理,如果想使用多个代理,可以在构造每一个Request对象的时候,通过meta参数的proxy字段手动进行设置
import scrapy from scrapy import Request import json class XiciSpider(scrapy.Spider): name = "xici_proxy" allowed_domains = ["www.xicidaili.com"] def start_requests(self): #爬取http://www.xicidaili.com/nn/前3 页 foriin range(1, 4): yield Request('http://www.xicidaili.com/nn/%s' % i) def parse(self, response): for sel in response.xpath('//table[@id="ip_list"]/tr[pos # 提取代理的IP、port、scheme(http or https) ip = sel.css('td:nth-child(2)::text').extract_first()
port = sel.css('td:nth-child(3)::text').extract_first()
scheme = sel.css('td:nth-child(6)::text').extract_first() # 使用爬取到的代理再次发送请求到http(s)://httpbin.org/ip url = '%s://httpbin.org/ip' % scheme proxy = '%s://%s:%s' % (scheme, ip, port) meta = { 'proxy': proxy,
'dont_retry': True,
'download_timeout': 10, # 以下两个字段是传递给check_available 方法的信息,方便 '_proxy_scheme': scheme, '_proxy_ip': ip, } yield Request(url, callback=self.check_available, meta=meta, dont_filter=True) def check_available(self, response): proxy_ip = response.meta['_proxy_ip'] # 判断代理是否具有隐藏IP 功能 if proxy_ip == json.loads(response.text)['origin']: yield { 'proxy_scheme': response.meta['_proxy_scheme'], 'proxy': response.meta['proxy'], }
- 在start_requests中请求网站下的前三页,用parse方法作为页面解析的函数
- 在parse方法中提取一个页面中的所有的代理服务器信息,由于这些代理未必都是可用的,所以使用采集到的代理发送请求http(s)://httpbin.org/ip验证其是否可用,用check_acailable方法作为页面的解析函数
- 要是能够执行到check_available方法,那么也就意味着response中对应的请求所使用的代理都是可用的,在check_available方法中,通过响应json字符串中的origin字段可以判断代理是否是匿名的(隐藏IP),返回匿名代理。