17-爬虫之scrapy框架五大核心组件工作流程及下载中间件介绍04
scrapy的五大核心组件
引擎(Scrapy)
对整个系统的数据流进行处理, 触发事务(框架核心).
调度器(Scheduler)
用来接受引擎发过来的请求. 由过滤器过滤重复的url并将其压入队列中, 在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么.
下载器(Downloader)
用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的).
爬虫(Spiders)
爬虫是主要干活的, 它可以生成url, 并从特定的url中提取自己需要的信息, 即所谓的实体(Item). 用户也可以从中提取出链接, 让Scrapy继续抓取下一个页面.
项目管道(Pipeline)
负责处理爬虫从网页中抽取的实体, 主要的功能是持久化实体、验证实体的有效性、清除不需要的信息. 当页面被爬虫解析后, 将被发送到项目管道, 并经过几个特定的次序处理数据.
工作流程
当我们执行爬虫文件的时候,这五大组件就已经开始工作了 。其中,
-
1 首先,我们最原始的起始url是在我们爬虫文件中的,通常情况系,起始的url只有一个,当我们的爬虫文件执行的时候,首先对起始url发送请求,将起始url封装成了请求对象,将请求对象传递给了引擎,引擎就收到了爬虫文件给它发送的封装了起始URL的请求对象。我们在爬虫文件中发送的请求并没有拿到响应(没有马上拿到响应),只有请求发送到服务器端,服务器端返回响应,才能拿到响应。
-
2 引擎拿到这个请求对象以后,又将请求对象发送给了调度器,队列接受到的请求都放到了队列当中,队列中可能存在多个请求对象,然后通过过滤器,去掉重复的请求
-
3 调度器将过滤后的请求对象发送给了引擎,
-
4 引擎将拿到的请求对象给了下载器
-
5 下载器拿到请求后将请求拿到互联网进行数据下载
-
6 互联网将下载好的数据发送给下载器,此时下载好的数据是封装在响应对象中的
-
7 下载器将响应对象发送给引擎,引擎接收到了响应对象,此时引擎中存储了从互联网中下载的数据。
-
8 最终,这个响应对象又由引擎给了spider(爬虫文件),由parse方法中的response对象来接收,然后再parse方法中进行解析数据,此时可能解析到新的url,然后再次发请求;也可能解析到相关的数据,然后将数据进行封装得到item,
-
9 spider将item发送给引擎,
-
10 引擎将item发送给管道。
其中,在引擎和下载中间还有一个下载器中间件,spider和引擎中间有爬虫中间件,
爬虫中间件
- 拦截请求和响应,对请求和响应进行处理。
下载器中间件(重点)
- 可以拦截请求和响应对象,请求和响应交互的时候一定会经过下载中间件,可以处理请求和响应。
- 拦截请求:
- 篡改请求url
- 伪装请求头信息UA Cookie
- 设置请求代理(重点)
- 拦截响应
- 篡改响应数据
- 代理操作必须使用中间件才可以实现
- process_exception:
- request.meta[‘proxy’] = ‘http://ip:port’ # 设置代理
- process_exception:
- 拦截请求:
创建工程
创建一个爬虫工程:scrapy startproject proName
进入工程目录创建爬虫源文件:scrapy genspider spiderName www.xxx.com
执行工程:scrapy crawl spiderName
对middlewares.py进行精简并编辑
- 只留下下载中间件的类容
from scrapy import signals
from itemadapter import is_item, ItemAdapter
class MiddleproDownloaderMiddleware(object):
# 拦截所有(正常&异常)的请求
# 参数: request就是拦截到的请求,spider就是爬虫类实例化的对象
def process_request(self, request, spider):
print('process_request()')
return None # or request
# 拦截所有的响应对象
# 参数:response拦截到的响应对象,request响应对象对应的请求对象
def process_response(self, request, response, spider):
print('process_response()')
return response
# 拦截异常的请求
# 参数:request就是拦截到的发生异常的请求
# 作用:想要将异常的请求进行修正,将其变成正常的请求,然后对其进行重新发送
def process_exception(self, request, exception, spider):
# 请求的ip被禁掉,该请求就会变成一个异常的请求
request.meta['proxy'] = 'http://ip:port' # 设置代理
print('process_exception()')
return request #将异常的请求修正后进行重新发送