Scrapy

Scrapy简介和历史

Scrapy是用纯Python实现一个为了爬取网站数据、提取结构性数据而编写的应用框架,用途非常广泛。

框架的力量:用户只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页内容以及各种图片,非常之方便。

Scrapy 使用了 Twisted'twɪstɪd异步网络框架来处理网络通讯,可以加快我们的下载速度,不用自己去实现异步框架,并且包含了各种中间件接口,可以灵活的完成各种需求。

Scrapy基本结构和框架

名称 功能
engine 引擎,类似于一个中间件,负责控制数据流在系统中的所有组件之间流动,可以理解为“传话者”
spider 爬虫,负责解析response和提取Item
downloader 下载器,负责下载网页数据给引擎
schedule 调度器,负责将url入队列,默认去掉重复的url
item pipeline 管道,负责处理被spider提取出来的Item数据
  • 调度器(Scheduler)

调度器,说白了把它假设成为一个URL(抓取网页的网址或者说是链接)的优先队列,由它来决定下一个要抓取的网址是 什么,同时去除重复的网址(不做无用功)。用户可以自己的需求定制调度器。

  • 下载器(Downloader)

下载器,是所有组件中负担最大的,它用于高速地下载网络上的资源。Scrapy的下载器代码不会太复杂,但效率高,主 要的原因是Scrapy下载器是建立在twisted这个高效的异步模型上的(其实整个框架都在建立在这个模型上的)。

在引擎及下载器之间的特定钩子(specific hook),处理Downloader传递给引擎的response。 其提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能。

  • 爬虫(Spider)

爬虫,是用户最关心的部份。用户定制自己的爬虫,用于从特定的网页中提取自己需要的信息,即所谓的实体(Item)。 用户也可以从中提取出链接,让Scrapy继续抓取下一个页面。
spider是scrapy用户编写用于分析response并提供给item或额外跟进的URL类。每个spider负责处理一个特定(或一些)网站。

  • 实体管道(Item Pipeline)

实体管道,用于处理爬虫提取的实体。主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。
item Pipeline负责处理被spider提取出来的item。典型的处理有清理、验证及持久化(如存取到数据库中)

  • Scrapy引擎(Scrapy Engine)

Scrapy引擎是整个框架的核心.它用来控制调试器、下载器、爬虫。实际上,引擎相当于计算机的CPU,它控制着整个流程。

Spider中间件是在引擎及Spider之间的特定钩子(specific hook),处理spider的输入(response)和输出(items及requests)。 其提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能。

Scrapy基本结构和框架
Scrapy基本结构和框架
Scrapy基本结构和框架

流程

1.首先爬虫将需要发送请求的url(requests)经引擎交给调度器;

2.排序处理后,经ScrapyEngine,DownloaderMiddlewares(有User_Agent, Proxy代理)交给Downloader;

3.Downloader向互联网发送请求,并接收下载响应.将响应经ScrapyEngine,可选交给Spiders;

4.Spiders处理response,提取数据并将数据经ScrapyEngine交给ItemPipeline保存;

5.提取url重新经ScrapyEngine交给Scheduler进行下一个循环。直到无Url请求程序停止结束。

安装

Scrapy框架官方网址:http://doc.scrapy.org/en/latest

Scrapy中文维护站点:http://scrapy-chs.readthedocs...

Windows 安装方式

推荐使用 :conda install Scrapy

Mac 等系统

pass

常用命令

常用命令

scrapy保存信息的最简单的方法主要格式

格式 命令
json格式,默认为Unicode编码 scrapy crawl Atguigu -o 项目名.json
json lines格式,默认为Unicode编码 scrapy crawl Atguigu -o 项目名.jsonlines
csv 逗号表达式,可用Excel打开 scrapy crawl Atguigu -o 项目名.csv
xml格式 scrapy crawl Atguigu -o 项目名.xml

Parse()方法的工作机制

1.因为使用的yield,而不是return。parse函数将会被当做一个生成器使用。scrapy会逐一获取parse方法中生成的结果,并判断该结果是一个什么样的类型;
2.如果是request则加入爬取队列,如果是item类型则使用pipeline处理,其他类型则返回错误信息。
3.scrapy取到第一部分的request不会立马就去发送这个request,只是把这个request放到队列里,然后接着从生成器里获取;
4.取尽第一部分的request,然后再获取第二部分的item,取到item了,就会放到对应的pipeline里处理;
5.parse()方法作为回调函数(callback)赋值给了Request,指定parse()方法来处理这些请求 scrapy.Request(url, callback=self.parse) Request对象经过调度,执行生成 scrapy.http.response()的响应对象,并送回给parse()方法,直到调度器中没有Request(递归的思路)
6.取尽之后,parse()工作结束,引擎再根据队列和pipelines中的内容去执行相应的操作;
7.程序在取得各个页面的items前,会先处理完之前所有的request队列里的请求,然后再提取items。
8.这一切的一切,Scrapy引擎和调度器将负责到底。

爬虫框架深入

去重规则

scrapy默认使用 scrapy.dupefilter.RFPDupeFilter 进行去重,相关配置有:

DUPEFILTER_CLASS = 'scrapy.dupefilter.RFPDupeFilter'
DUPEFILTER_DEBUG = False
JOBDIR = "保存范文记录的日志路径,如:/root/"  # 最终路径为 /root/requests.seen

使用redis的集合自定制去重规则:
利用scrapy的封装的request_fingerprint 进行对每个request对象进行加密,变成固长,方便存储。
定制完去重规则后,如何生效,只需更改配置文件即可:
settings.py文件中设置 DUPEFILTER_CLASS = '自定制去重规则的类的路径'
由此可见,去重规则是由两个因素决定的,一个是request对象中的dont_filter参数,一个是去重类。那这两个因素又是如何处理的? 这是由调度器中的enqueue_request方法决定的

调度器

1.使用队列(广度优先)
2.使用栈(深度优先)
3.使用优先级的队列(利用redis的有序集合)

下载中间件

在request对象请求下载的过程中,会穿过一系列的中间件,这一系列的中间件,在请求下载时,会穿过每一个下载中间件的process_request方法,下载完之后返回时,会穿过process_response方法。

作用:统一对所有的request对象进行下载前或下载后的处理

我们可以自定制中间件,在请求时,可以添加一些请求头,在返回时,获得cookie

自定制下载中间件时,需要在settings.py配置文件中配置才会生效。

DOWNLOADER_MIDDLEWARES = {
   'myspider.middlewares.MyspiderDownloaderMiddleware': 543,}

我们可以在请求的中间件中添加请求头,也可以添加cookie,但是,scrapy框架为我们写好了很多东西,我们只需要用即可,自定制的中间件添加scrapy中没有的就行。那么scrapy为我们提供了那些下载中间件呢?


scrapy 固有中间件

比如:我们请求头中常携带的useragent(在useragent.py中做了处理),还有redirect.py 中,处理了重定向的设置,我们在请求时,会出现重定向的情况,scrapy框架为我们做了重定向处理。

爬虫中间件

爬虫应用将item对象或者request对象依次穿过爬虫中间件的process_spider_output方法传给引擎进行分发,下载完成后依次穿过爬虫中间件的process_spider_input方法。

返回值:process_spider_output方法必须返回None或者抛出一个异常

同样的,我们自定义爬虫中间件也要在配置文件中配置

SPIDER_MIDDLEWARES = {
   'myspider.middlewares.MyspiderSpiderMiddleware': 543,}

那么爬虫中间件有什么作用呢?我们爬取的深度(DEPTH_LIMIT参数)和优先级是如何实现的呢?就是通过内置的爬虫中间件实现的。  


scrapy 内置爬虫中间件

那爬虫爬取的深度限制和优先级是如何实现的呢? 通过depth.py 这个文件

爬虫执行到深度中间件时,会先调用from_crawler方法,这个方法会先去settings文件中获取几个参数:DEPTH_LIMIT(爬取深度)、DEPTH_PRIORITY(优先级)、DEPTH_STATS_VERBOSE(是否收集最后一层),然后通过process_spider_output 方法中判断有没有设置过depth,如果没有就给当前的request对象设置depth=0参数,然后通过每层自加一 depth = response.meta['depth'] + 1实现层级的控制

备注:response.request 表示当前响应是由那个request对象发起的;
response.meta 等同于 response.request.meta 可以获取到当前响应对应的request对象的meta属性;
没有meta属性时,会默认携带一些参数:比如当前页面下载的时间。
同时,request的优先级,通过自身的priority的值自减depth的值得到request.priority -= depth * self.prio

如果 配置值DEPTH_PRIORITY设置为1,则请求的优先级会递减(0,-1,-2,...)
如果 配置值DEPTH_PRIORITY设置为-1,则请求的优先级会递增(0,1,2,...)
通过这种方式,通过改变配置的正负值,来实现优先级的控制(是深度优先(从大到小),还是广度优先(从小到大))
scrapy中DEPTH_LIMIT 和 DEPTH_PRIORITY的默认值

#scrapy框架内置的爬虫中间件的默认配置信息
SPIDER_MIDDLEWARES_BASE = {
    # Engine side
    'scrapy.spidermiddlewares.httperror.HttpErrorMiddleware': 50,
    'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': 500,
    'scrapy.spidermiddlewares.referer.RefererMiddleware': 700,
    'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware': 800,
    'scrapy.spidermiddlewares.depth.DepthMiddleware': 900,
    # Spider side
}

scrapy框架完美的遵循了开放封闭原则(源码封闭,配置文件开放)

自定制命令

pass

自定制扩展

pass

代理

基于环境变量 (给当前进程中的所有的请求加代理)

  • 基于环境变量 (给当前进程中的所有的请求加代理)
  • 基于request的meta参数 (给单个请求加代理)
  • 基于下载中间件

参考资料:

神一般的Scrapy框架,Python中Scrap的基本结构和去重原理
scrapy框架教程
Scrapy 框架
scrapy框架的基本使用
Scrapy框架流程图解析
都是干货---真正的了解scrapy框架

你可能感兴趣的:(Scrapy)