13.4 实现随机代理
本章开始部分曾提到,某些网站为防止爬虫爬取会对接收到的请求进行监测,如果在短时间内接收到了来自同一IP的大量请求,就判定该IP的主机在使用爬虫程序爬取网站,因而将该IP封禁(拒绝请求)。爬虫程序可以使用多个代理对此类网站进行爬取,此时单位时间的访问量会被多个代理分摊,从而避免封禁IP。
下面我们基于HttpProxyMiddleware实现一个随机代理下载中间件。
在middlewares.py中实现RandomHttpProxyMiddleware,代码如下:
from scrapy.downloadermiddlewares.httpproxy import HttpProxyMiddleware from collections import defaultdict import json import random class RandomHttpProxyMiddleware(HttpProxyMiddleware): def __init__(self, auth_encoding='latin-1', proxy_list_file=None): if not proxy_list_file: raise NotConfigured self.auth_encoding = auth_encoding # 分别用两个列表维护HTTP和HTTPS的代理,{'http': [...], 'https': [...]} self.proxies = defaultdict(list) # 从json文件中读取代理服务器信息,填入self.proxies with open(proxy_list_file) as f: proxy_list = json.load(f) for proxy in proxy_list: scheme = proxy['proxy_scheme'] url = proxy['proxy'] self.proxies[scheme].append(self._get_proxy(url, scheme)) @classmethod def from_crawler(cls, crawler): # 从配置文件中读取用户验证信息的编码 auth_encoding = crawler.settings.get('HTTPPROXY_AUTH_ENCODING', 'latain-1') # 从配置文件中读取代理服务器列表文件(json)的路径 proxy_list_file = crawler.settings.get('HTTPPROXY_PROXY_LIST_FILE') return cls(auth_encoding, proxy_list_file) def _set_proxy(self, request, scheme): # 随机选择一个代理 creds, proxy = random.choice(self.proxies[scheme]) request.meta['proxy'] = proxy if creds: request.headers['Proxy-Authorization'] = b'Basic ' + creds
解释上述代码如下:
仿照HttpProxyMiddleware构造器实现RandomHttpProxyMiddleware构造器,首先从代理服务器列表文件(配置文件中指定)中读取代理服务器信息,然后将它们按协议(HTTP或HTTPS)分别存入不同列表,由self.proxis字典维护。
_set_proxy方法负责为每一个Request请求设置代理,覆写_set_proxy方法(覆盖基类方法)。对于每一个request,根据请求协议获取self.proxis中的代理服务器列表,然后从中随机抽取一个代理,赋值给request.meta['proxy']。
在配置文件settings.py中启用RandomHttpProxyMiddleware,并指定所要使用的代理服务器列表文件(json文件),添加代码如下:
DOWNLOADER_MIDDLEWARES = { # 置于HttpProxyMiddleware(750)之前 'proxy_example.middlewares.RandomHttpProxyMiddleware': 745, } # 使用之前在http://www.xicidaili.com/网站爬取到的代理 HTTPPROXY_PROXY_LIST_FILE='proxy_list.json'
最后编写一个TestRandomProxySpider测试该中间件,重复向http(s)://httpbin.org/ip发送请求,根据响应中的请求源IP地址信息判断代理使用情况:
# -*- coding: utf-8 -*- import scrapy from scrapy import Request import json class TestRandomProxySpider(scrapy.Spider): name = "test_random_proxy" def start_requests(self): for _ in range(100): yield Request('http://httpbin.org/ip', dont_filter=True) yield Request('https://httpbin.org/ip', dont_filter=True) def parse(self, response): print(json.loads(response.text))
运行爬虫,观察输出:
$ scrapy crawl test_random_proxy [scrapy] DEBUG: Crawled (200) <GET https://httpbin.org/ip> (referer: None) {'origin': '171.38.130.188'} [scrapy] DEBUG: Crawled (200) <GET http://httpbin.org/ip> (referer: None) {'origin': '182.90.83.104'} [scrapy] DEBUG: Crawled (200) <GET https://httpbin.org/ip> (referer: None) {'origin': '171.38.130.188'} [scrapy] DEBUG: Crawled (200) <GET http://httpbin.org/ip> (referer: None) {'origin': '203.88.210.121'} [scrapy] DEBUG: Crawled (200) <GET http://httpbin.org/ip> (referer: None) {'origin': '203.88.210.121'} ...
结果表明,RandomHttpProxyMiddleware工作良好,Scrapy爬虫随机地使用了多个代理。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论