返回介绍

13.4 实现随机代理

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

本章开始部分曾提到,某些网站为防止爬虫爬取会对接收到的请求进行监测,如果在短时间内接收到了来自同一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 技术交流群。

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

发布评论

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