学科分类
目录
网络爬虫

Downloader Middlewares——防止反爬虫

Downloader Middlewares(下载中间件)是处于引擎和下载器之间的一层组件,多个下载中间件可以被同时加载运行。

在引擎传递请求给下载器的过程中,下载中间件可以对请求进行处理 (例如增加http header信息,增加proxy信息等)。在下载器完成网络请求,传递响应给引擎的过程中,下载中间件可以对响应进行处理(例如进行gzip的解压等)。

编写下载器中间件十分简单。每个中间件组件都是一个Python类,其中定义了process_request方法和process_response方法中的某一个或全部。这两个方法的介绍如下。

1. process_request(self, request, spider)

用于对请求进行处理,在每个request通过下载中间件时被调用。

该方法的参数包括:

  • request:要处理的Request对象。

  • spider:该request对应的Spider对象。

该方法可能返回None,一个Response对象,或者一个Request对象,也可能抛出 IgnoreRequest异常。针对这4种情况,Scrapy有不同的处理方式,分别介绍如下。

(1)如果返回None,Scrapy将继续处理该request,执行其他的间件的相应方法,直到合适的下载器处理函数(download handler)被调用,该request被执行(即其response被下载)。

(2)如果返回Response对象,Scrapy将不会调用任何其他的 process_request()方法,process_exception()方法,或相应的下载函数,而是返回该response。 已安装的中间件的process_response()方法则会在每个response返回时被调用。

(3)如果返回Request对象,Scrapy将停止调用process_request方法并重新调度返回的request。当新返回的request被执行后,相应的中间件链将会根据下载的response被调用。

(4)如果抛出一个IgnoreRequest异常,则安装的下载中间件的 process_exception() 方法会被调用。如果没有任何一个方法处理该异常, 则request的errback(Request.errback)方法会被调用。如果没有代码处理抛出的异常,则该异常被忽略且不记录(不同于其他异常的处理方式)。

2. process_response(self, request, response, spider)

用于对response进行处理,当下载器完成http请求,传递响应给引擎的时候调用。

该方法有3个参数,分别介绍如下:

  • request:是一个Request对象,表示response所对应的request。

  • response:是一个Response对象,表示被处理的response。

  • spider:是一个 Spider 对象,表示response所对应的spider。

该方法有3种执行结果,分别是:返回一个Response对象,返回一个Request对象或抛出一个IgnoreRequest异常。针对这3种结果,Scrapy有不同的处理方式,分别介绍如下。

(1)如果返回一个Response 对象(可以与传入的response相同,也可以是全新的对象), 该response会被处于链中的其他中间件的 process_response() 方法处理。

(2)如果返回一个Request对象,则中间件链停止,返回的request会被重新调度下载。处理方式类似 process_request() 返回request所做的操作。

(3)如果抛出一个IgnoreRequest异常,则调用request的errback(Request.errback)方法。如果没有代码处理抛出的异常,则该异常被忽略且不记录(不同于其他异常的处理方式)。

接下来就使用一个案例为大家介绍下载中间件的具体使用。步骤如下。

1. 创建middlewares.py文件

Scrapy的代理IP、Uesr-Agent的切换都是通过下载中间件进行控制。我们在settings.py同级目录下创建middlewares.py文件,用于对网络请求进行包装。代码如下。

 1  import random
 2  import base64
 3  from settings import USER_AGENTS
 4  from settings import PROXIES
 5  # 随机的User-Agent
 6  class RandomUserAgent(object):
 7    def process_request(self, request, spider):
 8      useragent = random.choice(USER_AGENTS)
 9      request.headers.setdefault("User-Agent", useragent)
 10 # 随机的代理IP
 11 class RandomProxy(object):
 12   def process_request(self, request, spider):
 13     proxy = random.choice(PROXIES)
 14     if proxy['user_passwd'] is None:
 15       # 没有代理账户验证的代理使用方式
 16       request.meta['proxy'] = "http://" + proxy['ip_port']
 17     else:
 18       # 对账户密码进行base64编码转换
 19       base64_userpasswd = base64.b64encode(proxy['user_passwd'])
 20       # 对应到代理服务器的信令格式里
 21       request.headers['Proxy-Authorization'] = 'Basic ' + base64_userpasswd
 22       request.meta['proxy'] = "http://" + proxy['ip_port']

上述代码中第6~9行定义了RandomUserAgent方法,用于从配置文件中获取User-Agent列表,从中随机选择一个并交给当前的request对象使用。

第11~22行定义了RandomProxy方法,用于从配置文件中获取Proxy列表,从中随机选择一个并交给当前的request对象使用。

2. 修改settings.py配置USER_AGENTS和PROXIES

接下来在配置文件中添加可用的USER_AGENTS和PROXIES列表,以及一些其他设置。

(1)添加USER_AGENTS,代码如下。

USER_AGENTS = [
  "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
  "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
  "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
  "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
  "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
  "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
  "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
  "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5"
]

(2)添加代理IP,设置PROXIES,代码如下。

PROXIES = [
  {'ip_port': '111.8.60.9:8123', 'user_passwd': 'user1:pass1'},
  {'ip_port': '101.71.27.120:80', 'user_passwd': 'user2:pass2'},
  {'ip_port': '122.96.59.104:80', 'user_passwd': 'user3:pass3'},
  {'ip_port': '122.224.249.122:8088', 'user_passwd': 'user4:pass4'},
]

(3)除非特殊需要,禁用cookies,防止某些网站根据Cookie来封锁爬虫。代码如下。

COOKIES_ENABLED = False

(4)设置下载延迟。代码如下。

DOWNLOAD_DELAY = 3

(5)最后设置setting.py里的DOWNLOADER_MIDDLEWARES,添加自己编写的下载中间件类。代码如下。

DOWNLOADER_MIDDLEWARES = {
  #'mySpider.middlewares.MyCustomDownloaderMiddleware': 543,
  'mySpider.middlewares.RandomUserAgent': 1,
  'mySpider.middlewares.ProxyMiddleware': 100
}
点击此处
隐藏目录