scrapy中间件的使用

学习目标

  1. 使用中间件设置随机UA
  2. 使用中间件设置代理IP
  3. scrapy与selenium配合使用

1. 中间件分类和作用

1.1 中间件分类

根据scrapy运行流程中所在位置不同分为:

  1. 下载中间件
  2. 爬虫中间件

1.2 中间件作用:预处理request对象和response对象

  1. 对header和cookies进行设置和处理
  2. 使用代理IP等
  3. 请求进行定制化操作

scrapy默认情况下,两个中间件都写在middlewares.py 文件中
且两个中间件使用方法相同,功能相同,通常使用下载中间件

2.中间件使用

  1. 在middlewares.py 中定义中间件类
  2. 在中间件中重写请求或者响应方法
    Downloader Middlewares(下载器中间件)默认的方法:
    • process_request(self, request, spider)
      None 如果所有的下载器中间件都返回为None,则请求最终被交给下载器处理
      request 如果返回请求,则将请求交给调度器
      response 将响应对象交给spider进行解析
    • process_response(self, request, response, spider)
      request 如果返回请求,则将请求交给调度器
      response 将响应对象交给spider进行解析
  3. 在settings文件中开启中间件的使用

3. 在中间件中集成Selenium

对于一些动态加载的网站,有时候可能找不到API接口,这种情况我们可以使用Selenium渲染请求目标的网页,将渲染后的页面源码返回爬虫。实例代码如下:

import time

from scrapy.http import HtmlResponse
from selenium import webdriver


class SeleniumMiddleware(object):
    def __init__(self):
        self.driver = webdriver.Chrome()

    def process_request(self, request, spider):
        if spider.name == 'blog_spider':
            self.driver.get(request.url)
            time.sleep(2)
            body = self.driver.page_source
            return HtmlResponse(self.driver.current_url, body=body, request=request, encoding="utf-8")

这个中间件的作用,就是对名为“blog_spider”的爬虫请求的网址,使用ChromeDriver先进行渲染,然后用返回的渲染后的HTML代码构造一个Response对象。
如果是其他的爬虫,就什么都不做。在上面的代码中,等待页面渲染完成是通过time.sleep(2)来实现的,
当有了这个中间件以后,就可以像访问普通网页那样直接处理需要异步加载的页面。

4. 开发Cookies中间件

对于需要登录的网站,可以使用Cookie保持登录状态。那么如果单独写一个小程序,用Selenium持续不断地用不同的账号登录网站,就可以得到很多不同的Cookies。由于Cookies本质上就是一段文本,所以可以把这段文本放在Redis里面。这样一来,当Scrapy爬虫请求网页时,可以从Redis中读取Cookies并给爬虫换上。这样爬虫就可以一直保持登录状态。
实例代码如下:

class LoginMiddleware():
	def __init__(self):
		self.client = redis.StrictRedis()
	def process_request(self, request, spider):
		if spider.name == 'xxx':
			cookies = json.loads(self.client.lpop('cookies').decode())
			request.cookies = cookies

如果有某网站的100个账号,那么单独写一个程序,持续不断地用Selenium和ChromeDriver或者Selenium和PhantomJS登录,获取Cookies,并将Cookies存放到Redis中。爬虫每次访问都从Redis中读取一个新的Cookies来进行爬取,就大大降低了被网站发现或者封锁的可能性。

5. 在中间件里重试

在爬虫的运行过程中,可能会因为网络问题或者是网站反爬虫机制生效等原因,导致一些请求失败。在某些情况下,少量的数据丢失是无关紧要的,例如在几亿次请求里面失败了十几次,损失微乎其微,没有必要重试。但还有一些情况,每一条请求都至关重要,容不得有一次失败。此时就需要使用中间件来进行重试。

有的网站的反爬虫机制被触发了,它会自动将请求重定向到一个xxx/404.html页面。那么如果发现了这种自动的重定向,就没有必要让这一次的请求返回的内容进入数据提取的逻辑,而应该直接丢掉或者重试。

1. 爬虫中间件

爬虫中间件的用法与下载器中间件非常相似,只是它们的作用对象不同。下载器中间件的作用对象是请求request和返回response;爬虫中间键的作用对象是爬虫,更具体地来说,就是写在spiders文件夹下面的各个文件。它们的关系,在Scrapy的数据流图上可以很好地区分开来,
scrapy中间件的使用_第1张图片
其中,4、5表示下载器中间件,6、7表示爬虫中间件。爬虫中间件会在以下几种情况被调用。

  1. 当运行到yield scrapy.Request()或者yield item的时候,爬虫中间件的process_spider_output()方法被调用。
  2. 当爬虫本身的代码出现了Exception的时候,爬虫中间件的process_spider_exception()方法被调用。
  3. 当爬虫里面的某一个回调函数parse_xxx()被调用之前,爬虫中间件的process_spider_input()方法被调用。
  4. 当运行到start_requests()的时候,爬虫中间件的process_start_requests()方法被调用。

1.1 在爬虫中间件处理爬虫本身异常

在爬虫中间件里面可以处理爬虫本身的异常。
scrapy中间件的使用_第2张图片
由于网站返回的只是一段普通的字符串,并不是JSON格式的字符串,因此使用JSON去解析,就一定会导致报错。这种报错和下载器中间件里面遇到的报错不一样。下载器中间件里面的报错一般是由于外部原因引起的,和代码层面无关。而现在的这种报错是由于代码本身的问题导致的,是代码写得不够周全引起的。
为了解决这个问题,除了仔细检查代码、考虑各种情况外,还可以通过开发爬虫中间件来跳过或者处理这种报错。在middlewares.py中编写一个类:

class ExceptionCheckSpider(object):
	def process_spider_exception(self, response, exception, spider):
		print(f'返回的内容是:{response.body.decode()}\n报错原因:{type(exception)}')
		return None

这个类仅仅起到记录Log的作用。在使用JSON解析网站返回内容出错的时候,将网站返回的内容打印出来。

process_spider_exception() 这个方法,它可以返回None,也可以运行yield item语句或者像爬虫的代码一样,使用yield scrapy.Request()发起新的请求。如果运行了yield item或者yield scrapy.Request(),程序就会绕过爬虫里面原有的代码。

1.2 激活爬虫中间件

爬虫中间件的激活方式与下载器中间件非常相似,在settings.py中,在下载器中间件配置项的上面就是爬虫中间件的配置项,它默认也是被注释了的,解除注释,并把自定义的爬虫中间件添加进去即可,

下载器中间件的数字越小越接近Scrapy引擎,数字越大越接近爬虫。如果不能确定自己的自定义中间件应该靠近哪个方向,那么就在500~700之间选择最为妥当。

你可能感兴趣的:(Python爬虫)