返回介绍

13.5 下载器中间件

发布于 2024-01-26 22:39:51 字数 7705 浏览 0 评论 0 收藏 0

从Scrapy框架图12-1中可以看到,下载器中间件是介于Scrapy的request/response处理的钩子框架,是用于全局修改Scrapy的request和response,可以帮助我们定制自己的爬虫系统。

13.5.1 激活下载器中间件

要激活下载器中间件组件,需要将其加入到DOWNLOADER_MIDDLEWARES设置中。该设置位于Settings.py文件,是一个字典(dict),键为中间件类的路径,值为其中间件的顺序。示例如下:

  DOWNLOADER_MIDDLEWARES = {
     'myproject.middlewares.CustomDownloaderMiddleware': 543,
  }

在Settings.py中对DOWNLOADER_MIDDLEWARES的设置,会与Scrapy内置的下载器中间件设置DOWNLOADER_MIDDLEWARES_BASE合并,但不会覆盖,而是根据顺序值进行排序,最后得到启用中间件的有序列表:第一个中间件是最靠近引擎的,最后一个中间件是最靠近下载器的。Scrapy内置的中间件设置DOWNLOADER_MIDDLEWARES_BASE为:

·'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware':100

·'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware':300

·'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware':350

·'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware':400

·'scrapy.downloadermiddlewares.retry.RetryMiddleware':500

·'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware':550

·'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware':580

·'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware':590

·'scrapy.downloadermiddlewares.redirect.RedirectMiddleware':600

·'scrapy.downloadermiddlewares.cookies.CookiesMiddleware':700

·'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware':750

·'scrapy.downloadermiddlewares.chunked.ChunkedTransferMiddleware':830

·'scrapy.downloadermiddlewares.stats.DownloaderStats':850

·'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware':900

如何分配中间件的位置,首先看一下内置的中间件的位置,然后根据将你想放置的中间件的位置设置一个值。有时候你想放置的中间件可能会依赖前后的中间件的作用,因此设置顺序相当重要。如果想禁用内置的中间件,必须在DOWNLOADER_MIDDLEWARES中定义该中间件,并将值设置为None。例如想关闭User-Agent中间件:

  DOWNLOADER_MIDDLEWARES = {
     'myproject.middlewares.CustomDownloaderMiddleware': 543,
     'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': None,
  } 

注意  DOWNLOADER_MIDDLEWARES_BASE中内置中间件并不是都开启的,有些中间件需要通过特定的设置来启用。

13.5.2 编写下载器中间件

如何定制我们自己的下载器中间件才是我们比较关心的问题,编写下载器中间件非常简单。每个中间件组件是定义了以下一个或多个方法的Python类:

·process_request(request,spider)

·process_response(request,response,spider)

·process_exception(request,exception,spider)

下面分别介绍这三种中间件。

1.process_request(request,spider)

方法说明: 当每个Request通过下载中间件时,该方法被调用,返回值必须为None、Response对象、Request对象中的一个或Raise IgnoreRequest异常。

参数:

Request(Request对象):处理的Request。

Spider(Spider对象):该Request对应的Spider。

返回值:

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

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

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

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

2.process_response(request,response,spider)

方法说明: 该方法主要用来处理产生的Response,返回值必须是Response对象、Request对象中的一个或Raise IgnoreRequest异常。

参数:

request(Request对象):Response对应的Request。

response(Response对象):处理的Response。

spider(Spider对象):Response对应的Spider。

返回值:

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

如果返回Request对象,则中间件链停止,返回的Request会被重新调度下载。处理类似于process_request()返回Request时所做的那样。

如果抛出IgnoreRequest异常,则调用Request的errback方法。如果没有代码处理抛出的异常,则该异常被忽略且不记录。

3.process_exception(request,exception,spider)

方法说明: 当下载处理器或process_request()抛出异常,比如IgnoreRequest异常时,Scrapy调用process_exception()。process_exception()应该返回None、Response对象或者Request对象其中之一。

参数:

request(Request对象):产生异常的Request。

exception(Exception对象):抛出的异常。

spider(Spider对象):Request对应的Spider。

返回值:

如果返回None,Scrapy将会继续处理该异常,接着调用已安装的其他中间件的process_exception()方法,直到所有中间件都被调用完毕,则调用默认的异常处理。

如果返回Response对象,则已安装的中间件链的process_response()方法被调用。Scrapy将不会调用任何其他中间件的process_exception()方法。

如果返回Request对象,则返回的request将会被重新调用下载,这将停止中间件的process_exception()方法执行,类似于返回Response对象的处理。

下面通过两个例子帮助大家理解下载器中间件的编写,这两个例子也是在实际项目中经常用到。

一个是动态设置Request的User-Agent字段,主要是为了突破反爬虫对User-Agent字段的检测,实例代码如下:

  '''
  这个类主要用于产生随机User-Agent
  '''
  
  class RandomUserAgent(object):
  
     def __init__(self,agents):
       self.agents = agents
  
     @classmethod
     def from_crawler(cls,crawler):
       # 从Settings中加载USER_AGENTS的值
       return cls(crawler.settings.getlist('USER_AGENTS'))
  
     def process_request(self,request,spider):
       # 在process_request中设置User-Agent的值
       request.headers.setdefault('User-Agent', random.choice(self.agents))

其中USER_AGENTS是写在Settings.py中的User-Agent列表,内容如下:

  USER_AGENTS=[
     "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; AcooBrowser; .NET CLR 
       1.1.4322; .NET CLR 2.0.50727)",
     "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET 
       CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)",
     "Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 
       5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)",
     "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)",
     "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Tri
       dent/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",
     "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.
       fc10 Kazehakase/0.5.6",
     "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.11 (KHTML, like Gecko) 
       Chrome/17.0.963.56 Safari/535.11",
  ]

一个是动态设置Request的代理IP,主要是为了突破反爬虫对IP的检测,实例代码如下:

  '''
  这个类主要用于产生随机代理
  '''
  class RandomProxy(object):
  
     def __init__(self,iplist):# 初始化一下数据库连接
       self.iplist=iplist
  
     @classmethod
     def from_crawler(cls,crawler):
     # 从Settings中加载IPLIST的值
       return cls(crawler.settings.getlist('IPLIST'))
  
     def process_request(self, request, spider):
       '''
       在请求上添加代理
       :param request:
       :param spider:
       :return:
       '''
       proxy = random.choice(self.iplist)
       request.meta['proxy'] =proxy

其中IPLIST是写在Settings.py中的代理IP列表,内容如下:

  IPLIST=["http://220.160.22.115:80", "http://183.129.151.130:80","http://112.228. 
       35.24:8888"]

写完以上两个中间件,如果想使用的话,直接按照上一节讲解的那样,进行激活即可。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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