下载中间件: 位于引擎和下载器之间,可以拦截请求和响应对象;拦截到请求和响应对象后可以
篡改页面内容和请求和响应头信息。
爬虫中间件:位于spider和引擎之间,也可以拦截请求和响应对象,不常用。
作用
实现深度爬取。
深度爬取
爬取的数据不在同一张页面中。
在进行手动发送请求的时候,可以将一个meta字典传递给callback指定的回调函数
yield scrapy.Request(url,callback,meta={})
在回调函数中接收meta
response.meta[\'key\'] 将meta字典中key对应的value值取出
案例:电影名字和简介爬取案例地址:4567电影网电影分类
spiderName.py
# -*- coding: utf-8 -*- import scrapy from moviePro.items import MovieproItem class MovieSpider(scrapy.Spider): name = \'movie\' # allowed_domains = [\'www.xxx.com\'] start_urls = [\'https://www.4567kan.com/frim/index1.html\'] # 通用url url = \'https://www.4567kan.com/frim/index1-%d.html\' pagNum = 2 # 解析首页的数据,爬取电影名称和简介 def parse(self, response): li_list = response.xpath(\'/html/body/div[1]/div/div/div/div[2]/ul/li\') for li in li_list: mv_name = li.xpath(\'./div/a/@title\').extract_first() item = MovieproItem() item[\'name\'] = mv_name detail_url = "https://www.4567kan.com/" + li.xpath(\'./div/a/@href\').extract_first() yield scrapy.Request(url=detail_url, callback=self.parse_detail, meta={\'item\': item}) # meta 就是一个字典,可以将字典传给callback指定的回调函数,实现请求传参 # 全站信息的爬取,测试前4页 if self.pagNum < 5: new_url = format(self.url % self.pagNum) self.pagNum += 1 yield scrapy.Request(url=new_url,callback=self.parse) # 自定义解析方法,解析详情页电影简介 def parse_detail(self, response): desc = response.xpath(\'/html/body/div[1]/div/div/div/div[2]/p[5]/span[3]//text()\').extract_first() # 接收请求传参传递过来的item item = response.meta[\'item\'] item[\'desc\'] = desc yield item 中间件 爬虫中间件位于spider和引擎之间,也可以拦截请求和响应对象,不常用。
下载中间件(推荐)位于引擎和下载器之间,可以拦截请求和响应对象;拦截到请求和响应对象后可以
篡改页面内容和请求和响应头信息。
作用:拦截所有请求和响应
为什么要拦截请求?
UA伪装(篡改请求头信息)
process_request()方法中,
request.headers[\'User-Agent\'] ="请求头信息"
设置代理
process_exception()方法中,
request.meta[\'proxy\'] = \'https://ip:prot\'
return request
工程项目中middlewares.py就是中间件。
from scrapy import signals import random # UA池 user_agent_list = [ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 " "(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1", "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 " "(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 " "(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 " "(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 " "(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 " "(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5", "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 " "(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3", "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 " "(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 " "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 " "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24" ] PROXY_HTTP = ["ip:port"] PROXY_HTTPS = ["ip:port"] # 下载中间件 class MiddleproDownloaderMiddleware(object): def process_request(self, request, spider): """ 拦截正常请求 :param request: 拦截到的正常请求 :param spider: 爬虫类实例化的对象 :return: """ # UA伪装 request.headers[\'User-Agent\'] = random.choice(user_agent_list) return None def process_response(self, request, response, spider): """ process_response函数:拦截所有的响应 :param request: 响应对应的请求 :param response: 拦截到的响应 :param spider: 爬虫类实例化的对象 :return: 返回处理后的响应 """ return response def process_exception(self, request, exception, spider): """ 拦截发生异常的请求;对异常请求进行修正,让其变成正常请求 :param request: 拦截到的发生异常的请求对象 :param exception: 拦截到的异常信息 :param spider: 爬虫类实例化的对象 :return: 将修正后的请求对象进行重新发送 """ # 代理操作 if request.url.split(":")[0] == \'http\': request.meta[\'proxy\'] = "http:{}".format(random.choice(PROXY_HTTP)) else: request.meta[\'proxy\'] = "https:{}".format(random.choice(PROXY_HTTPS)) return request # 将修正后的请求对象进行重新发送 为什么要拦截响应?篡改响应数据
案例:网易新闻数据爬取
实现流程:
1,解析出5个板块对应的url
2,对5个板块的url发起请求
3,获取板块的页面源码数据
问题:数据为动态加载,源码数据中没有新闻标题和详情页的url
解决:将响应数据进行篡改,改成包含动态加载的数据
selenium帮助我们捕获到包含了动态加载的响应数据
selenium在scrapy中的使用
实例化一个浏览器对象(爬虫文件中)
在中间件process_response中进行selenium后续的操作
在爬虫文件的爬虫类冲重写一个closed(self,spider),关闭浏览器
在settings.py基本设置一下,打开下载中间件