目录

Scrapy知网爬虫(一)整体理论篇

简要介绍:本系列是基于scrapy开发的知网爬虫(专利、论文、项目),已经爬了百万级别的数据,程序健壮性、速度均得到了验证。采用模块化的设计,拥有流程控制模块、错误重爬模块、任务分发模块,任务监督模块等。该系列预计分为:理论篇(整体介绍)、详细设计篇(披露代码细节,完整代码不一定开源)等。本文为理论篇,整体介绍了爬虫的理念、概要设计。本文由原word论文直接导出而后简单修改,所以部分样式可能没有md原汁原味。

1 相关概念、理论和工具介绍

1.1 Scrapy

Scrapy是一套基于Twisted的异步处理框架,由纯Python实现,用于从web网站中抓取结构化数据,是目前应用最广泛的工业级爬虫框架。Scrapy最大的优势在于,它设计了一个爬虫的通用架构,预设了多种爬虫基类,也提供了许多组件和中间件,任何人都能按照自己的需求快速写出高性能爬虫代码,并根据自己的需要编写中间件灵活应对各种业务场景。

Scrapy框架主要由七大组件组成,它们分别是Scrapy引擎(Scrapy Engine)、调度器(Scheduler)、下载器(Downloader)、爬虫(Spider)、实体管道(Item Pipeline)、下载器中间件(Downloader middlewares)和爬虫中间件(Spider middlewares)。展示了Scrapy的整体架构。

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/d98d59fc3e58e6364ae032e43ab0851d.png

1.1.1 Scrapy引擎(Scrapy Engine)

引擎是Scrapy框架的核心,用来控制调度器、下载器、爬虫。引擎相当于爬虫的“大脑”,操控数据在系统中所有组件的传送,并在合适的时机触发相应的动作。

1.1.2 调度器(Scheduler)

在Scrapy中,所有的request(网络请求)都交由调度器统一管理。无论是start_url(起始请求)还是后续在页面中获取的新的url,都经由引擎传送至调度器,然后入队,统一调度,待轮到请求发起时,调度器将队列中的request出队,提供给引擎,传送至其他模块。

调度器的设置,能更加高效利用CPU从而提高运行效率。没有队列作缓冲,网络延迟、文件读取等情况都会阻塞进程的运行,而将request放在调度器中,可以由引擎决定程序执行、网络请求、文件读取的时机,三大任务并行执行不会相互阻塞。

同时调度器带有自动request去重功能,对于每一种请求,都可选择是否去重。值得一提的是,调度队列保存在内存中,若程序异常终止,缓存的request会丢失。

1.1.3 下载器(Downloader)

下载器用于执行网络请求,高速下载网络上的资源。Scrapy建立在异步模型Twisted之上,Twisted采用回调机制,在处理IO或执行网络请求等费时操作时,程序不会一直等待响应,而是会注册一个回调至事件循环中并为该事件分配一个回调后处理的函数,而后将处理器资源分配到其他任务中,在多个任务快速切换且不用担心阻塞和线程安全问题。所以用户在编写代码时,只需要用少量的代码,即可编写出高效率的线程安全爬虫。

1.1.4 爬虫(Spider)

爬虫,是用户需要自定义最多的部分,涉及初始请求的构造、网页结构的解析、实体结构的提取、新请求的生成等。

  • 初始请求构造:用户传入start_urls列表作为初始请求url,Scrapy提取初始Url,调用默认的start_requests函数将url封装成request,传至网络请求调度器。业务场景复杂时,当简单的url列表难以满足爬虫需要(如需要一次传入不同的参数作为起始url),也可直接覆写 start_requests函数,自行封装requests传入调度器

  • 网页结构解析:Request得到的是html源代码,需要再使用网页解析工具,如Xpath(XML Path Language)、Beautiful Soup。前者提供了非常简洁明了的路径选择表达式用于从XML文档中提取信息,后者封装了简单的Python式函数用来处理XML、HTML文档的标签提取、搜索。前者的优势在于速度快,灵活高效,后者的优势在于使用简单,本设计选用了Xpath解析网页。

  • 实体结构的提取:解析网页结构完毕后,爬虫真正的目的是数据的持久化,所以用户需要将获取的一个个字段封装成不同类型的实体(Item),传至实体管道(Item Pipeline)。

  • 新请求的生成:一般情况下,初始url不会包含所有待爬url,程序编写者需自行实现链接提取、翻页等逻辑,以构建新的网络请求。在本设计中,设定每一轮次获取特定日期特定学科分类的所有文献信息。实际运行时,start_requests只执行一次搜索请求,之后通过翻页与链接提取获得所有文献链接,再将链接加入请求调度序列执行新一轮请求解析。

1.1.5 实体管道(Item Pipeline)

用户在Sider中提取出实体结构(Item),将被发送至实体管道,经过用户定义的process_item函数后,持久化至数据库或本地文件,也可丢弃。

1.1.6 下载器中间件(Downloader middlewares)

下载器中间件是在引擎及下载器之间的hook(钩子),下载器返回的response先经过中间件处理后再交由引擎。通过下载器中间件的创建,重写其中的方法,可扩展Scrapy功能,实现更换请求头、设置代理、自动重试、网络异常处理等功能。

1.1.7 爬虫中间件(Spider middlewares)

Spider中间件是在引擎及爬虫之间的钩子,可以过滤引擎传递的响应(response)和数据(items)。

2 科技大数据采集处理系统

2.1 爬虫概述

科技大数据采集处理系统采用Scrapy-Redis框架,实现了全自动化抓取知网专利、论文并持久化至文件系统中。

本系统在数据完整性、爬虫速度、错误处理、程序健壮性与可维护性上都进行了深入的研究,代码量超过3000行。主要由流程控制模块、链接获取模块、Scrapy-Redis核心引擎、页面解析模块、错误记录与错误重爬模块组成。

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/bfe072103482e3bba5e91d0c8fc3892d.png

2.2 文献遍历策略分析

评价爬虫成功与否的一大标准就是数据量的完整度,因此,必须采取一种合理的能够便利整个专利库、论文库检索方案。

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/aee90b91eca87e40fa4162bcb2ac3340.png

上图是知网专利的高级检索页面,经分析,程序可通过学科分类(左侧红框所示)与公开日(右侧红框所示)限定检索范围,实现整个数据库的遍历。

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/07f30c260a9c53e147482e3178868028.png

如上图所示,知网搜索结果为每页50条,只返回前120。所以必须保证每一次检索的专利条数都在6000条以内,因此本设计采用了每轮只爬特定日期的特定学科分类下的文献,确保搜索结果不溢出。下图为文献遍历策略流程图。

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/1317903ff48bb4b9cc36d8f5934e29ba.png

2.3 流程控制模块

2.3.1 模块设计理念与优点

流程控制模块是上文文献遍历策略的具体实现。一个优秀的爬虫系统是无状态的,即爬虫本身不记录任何运行状态,一切交由外部数据库掌控。优点有三:

(1)爬虫任务的制定和代码无关,每次只需启动爬虫无需改动代码,通过修改数据库可在远程直接控制爬虫任务的开始、暂停。

(2)若状态管理在爬虫内部实现,由内存控制,那么当程序异常终止(如严重异常、进程被Kill)时,极易丢失当前任务进度

(3)本流程控制模块兼具简单的远程监控功能,可实时查看爬虫进度

通过流程控制模块,爬虫核心部分只需实现爬取特定日期特定学科分类下的所有文献功能即可,至于启动时该从哪里开始爬、爬完当前学科分类与日期下一个爬什么、异常终止再启动后从哪里续爬、爬虫任务设定与读取等功能,全部交由流程控制模块即可。(注意,本流程控制模块实现的是任务级的粗粒度状态管理,请求级别的细粒度状态管理将在后文展开介绍)。

2.3.2 模块具体实现

前文讲到,文献遍历的核心在于任务制定以及每次传给爬虫程序一个日期加一个学科分类信息,本模块将围绕其展开。分持久层与代码流程两部分讲解

2.3.2.1 持久层

持久层,即采用什么数据库持久化爬虫任务状态,又如何定义数据库结构

数据库选用:

程序原先采用的是文件系统置访问标记的方式,但这样的弊端太多:访问标记需要全局统一、每次获取下一个日期和分类需要重新遍历整个文件、线程不安全,因为同时涉及日期和分类两个状态的更新导致文件修改逻辑非常复杂,不但要置访问标记还要在遍历完一个轮次后擦除访问标记。

后期系统采用Mysql数据库,优点如下:

(1)对状态的修改直接调用数据库的增删改查即可,方便且不易出错

(2)可远程控制任务开始、停止

(3)线程安全

数据库结构定义:

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/1f2cafb84ef623134db9340aef956984.png

本系统包含了专利、论文、成果等多种文献爬虫,所以设置了type字段用于区分。curCode字段包含两个含义,起始日期与当前日期,程序启动时爬虫将读取该字段作为起始日期,启动后将不断更新该字段来表示当前运行日期。endDate字段为终止日期,由用户设定,也可不设定,默认为当天。Status 字段简单指示了爬虫的状态,流程控制模块每次被调用的时候会将当前时间更新至status,用户可根据该字段判断程序是否正在运行。

2.3.2.2 代码流程

本采集系统将所有学科分类代码放在了一个文件中,在启动时读取一次加载至内存中,得到学科分类列表。因为列表固定不变,所以无需存放至数据库中。程序运行时,通过比对内存中的学科分类列表和从数据库中获取的上一次爬的学科分类即可获得上一次学科分类的下标,进而通过下标加一的操作获得下一个学科分类。下图是完整的学科分类与日期获取控制流程。本流程图隐去了数据库重连,任务有效性判断(如未定义起始日期)等细节。

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/80e468db53d9d06a95f382465f78c6cf.png

2.3.3 模块使用

任务设定:程序运行前设定开始日期(curDate)、结束日期(endDate,结束日期可不设,默认当天),运行程序即可。可在运行中任意时刻更新结束日期字段

任务状态查看:通过curDate和curCode字段可查看当前运行进度,通过status字段查看上一次调用流程控制模块时间判断程序是否仍在运行中。

任务终止:更新结束日期字段,使其早于(小于)开始日期(curDate)字段即可。程序会在处理完当前队列中缓存的请求、保存完所有管道中的文件后停止。

2.4 链接获取模块

链接获取模块负责获取一个分类下所有的文献链接,对于每个链接发起新的页面请求,以获得文献标题、摘要等信息。新的请求将由引擎通过请求队列统一调度。

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/6c84b51a3c61ea097e3ee5eab1e42b3b.png

流程图见上,展示了程序如何获取特定日期特定学科分类下的所有链接,涉及链接提取解析、自动翻页、Cookie更换等。Cookie更换是因为知网限定每次搜索,只能翻15页左右,所以在翻页到达一定次数的时候,需要重新执行搜索请求更换Cookie。程序的结束由流程控制模块决定,故本流程图未标明。

2.5 页面解析模块

页面解析模块负责解析下载器返回的网页内容,提取结构化信息,生成文献对象,传至数据管道。

系统采用xpath作为网页结构解析工具,因代码细节过多,本文只介绍专利内容解析中较为复杂的一个例子。专利详情页(部分)如下图:

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/ccb50cfa763a8226fc6dfa223580fab6.png

初次尝试链接提取时,程序按顺序提取了右侧的非加粗文字。后期随着程序的运行,出现了下标越界等异常,问题在于:专利页面字段不是固定的,如部分专利拥有“代理人”字段,没有“申请公布号”、“公开公告日”,而是“授权公告日”、“公开公告日”等。

故本系统采用了如下方式,确保能成功提取到所有字段:将形如“专利类型:发明公开”的字段作为一个整体一起提取,将其看作键值的形式,通过分析大量的专利页面找到所有的键,之后将当前页面的键与键列表一一比对,解决了字段不一的问题。实际运行过程中,还发现,“申请公布号”和“公开公告日”两字段前有个空格。

下面是网页代码分析。

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/a487da26cf52afe46d36579748e1acc0.png

网页源代码部分也较为混乱,表面上获取row、rowtit、funds等标签即可,仔细分析网页结构将会发现,网页同时含有row,row-1, row-2, rowtit, rowtit2等标签,并且不同字段间的网页标签选择并没有明显规则。加上含有超链接文字与纯文本的提取又不同,给网页解析带来了非常大的困难。

所以系统选用了灵活性极高的xpath,用少量的代码优雅解决了这一问题,下图代码同时展示了对复杂标签的提取策略与前文提高的键值方式解析字段的详细实现方法。

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/b778a209fdc8582efdc7d98051fbb08c.png

2.6 下载中间件设置

本系统改写了下载中间件,主要做了两项工作:

(1)在引擎从调度序列取出request后,设置了请求头信息,如修改user-agent,动态设置代理

(1)网页请求结果预分析,遇到异常网络状态码时,自动重试,达到一定次数后发送信息至错误记录模块。

2.6.1 请求头设置

(1)在项目设置文件中设置默认请求头,如下:

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/b8a121a0ad0c294f96a3827a0ceb9cc0.png

(2)预定义多个user-agent,重写下载中间件的process_request方法,每次随机选取一个user-agent

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/3355c7a31c7557903a1ba4f756264739.png

(3)Referer是反爬虫手段之一,告知服务器在此请求发送前用户访问的是哪个链接,为了防止被网站识别,这里需要针对专利和论文设置不同的Refer,值为高级搜索页面链接,同样写在process_request中。

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/c4fc7a36fff4fa2cada745a3a6d978c1.png

2.6.2 代理设置

为了防止因反爬机制高频率抓取网页内容而被封禁ip,可以采用代理,起到伪装自己而不被服务器发现真正请求源的作用。Scrapy的代理设置方式与请求头设置方式类似,新建下载中间件类,重写process_request方法,修改请求头添加相应字段即可。由于不同代理商的具体获取方式不同,本文略过代理获取、使用部分,主要介绍本设计研发的适用于Scrapy框架的两种代理设置通用工具。

全局代理开关设置

爬虫初期需要快速抓取数据需要代理,后期增量更新时抓取量少可不用代理,所以非常有必要设计一套简单可行的全局代理开关设置方法。

本设计采用的方式是在scrapy设置文件settings.py中增设PROXY_OPEN设置项,所有使用代理的地方通过判断该设置值选择是否启用代理。

但代理中间件的开启与否相对复杂,使用了python的类三目运算,动态设置代理中间件的优先级变量,若PROXY_OPEN为True则设定数字优先级,此时代理中间件开启,否则设定优先级为None,即不开启。

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/819037d8136e088a1ed18cc61cdad30c.png

代理复用组件

网络代理费用较为昂贵,以本次研究使用的代理为例,包月500元左右,ip不限量,但只能每5秒获取5个代理IP,所以本设计设计了一套代理复用组件。可在配置文件中设置平均代理复用的次数,组件将每次随机返回一个代理,并记录总使用次数,若发生代理失效异常,组件也会自动将失效代理剔除,所有代理复用完毕后将自动获取下一批代理,流程图如下(省略了异常处理等细节):

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/cf009475b78a7364cf27fe50dced079b.png

2.6.3 网络异常处理

数据采集时,经常会遇到各种网络异常,造成的原因是多样的,如:当前电脑网络拥堵、服务器错误、请求过快被服务器识别、302跳转、验证码弹窗、Cookie失效。其中的大部分异常只是由于暂时性的网络不畅或部分tcp连接丢失造成的,这部分网络错误重新请求是可以正常获取网页内容的。

所以本设计网络异常处理分为两步:

  1. 通过改写下载中间件获取异常网络状态码,若该状态码在定义的重试状态码列表内,立即重试,否则抛弃该请求,交由错误记录模块处理。

  2. 定义最大重试次数,超过后有可能是Cookie失效等原因导致目前多次请求无法正常获取内容,交由错误记录模块处理。

    具体代码如下:

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/fc38caa5aa289ce4236f99d30cc28a53.png

代码除了执行自动重试操作,还进行了有关代理异常的判断,如果异常是由于代理引起的,则会向代理模块发送代理错误信息,移除失效代理。其中的save_url函数逻辑较简单未贴出:判断当前重试次数是否超过最大重试次数,若超过,调用错误记录函数记录出错日期、学科分类、链接。

2.7 异常处理、错误记录与错误重爬模块

2.7.1 异常处理

为了保证程序的健壮性,必须在程序异常时由下至上、由细及粗地接住所有可能的异常、错误。底层先接住可知的、已预测到的、主动抛出的异常,如有时请求网页传回的是js而非html,抛出网页解析异常,这部分异常不记录具体异常信息,只记录出错的日期、学科分类、链接;对于未预测到的异常,顶层定义一个全局异常处理类,记录详细异常调用栈,并记录出错日期、学科分类、链接。

2.7.2 错误记录

为了保证数据的完整性,对出错任务的记录与重爬尤为重要。

记录的错误类型:本数据采集系统主要分两步,第一步是获取文献链接,第二步是请求文献链接解析内容。因此,错误记录也被分为两种,一种是在获取文献链接阶段时,记录失败任务对应的日期、学科分类;另一种则是在请求文献链接得到文献详细信息时,记录出错失败的链接。

错误捕捉策略:随着程序的不断迭代优化,因对网页结构分析不到位与程序代码缺陷引发的异常已被全部规避。目前部分链接获取与解析失败的原因绝大多数还是源于网络问题,如非正常网络状态码(302跳转、服务器拒绝连接、请求超时),这部分会由网络异常处理模块捕捉,传送至错误记录模块;另一部分则是程序在实际运行中,存在少量状态码正确但网页内容不是预期搜索结果的情况,这部分也会被错误记录模块记录下来。

错误记录数据表结构:程序共定义了两个数据表用来记录错误,errorCode表用于记录链接获取阶段时的失败任务;errorLink用于记录请求文献链接解析详情时的失败链接。

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/80a585d0c15f4c231391a2bcff3982dc.png

https://tcualhp-notes.oss-cn-hangzhou.aliyuncs.com/img/900ed8305b80ebcced5006aadc67445a.png

2.7.3 错误重爬模块

系统会在运行时自动记录两种错误至mysql数据库中,当所有预设任务结束时,程序将进入错误重爬模块。

第一步,读取errorCode表,获取失败的日期与学科分类,重新获取文献链接,并解析链接对应的文献详情,直到表空。因为爬虫核心实现了每轮次对特定日期特定日期分类的文献抓取工作,正常任务流程的日期与学科分类输入源来自流程控制模块,在错误重爬时,只需要更换输入源为errorCode表即可。

第二步:读取errorLink表,获取请求文献详情阶段失败的文献链接,重新执行请求与解析,直到表空。

2.8 请求级细粒度爬虫状态管理

本数据采集系统的网络请求主要分为两个阶段,第一阶段获取所有的文献链接,第二阶段请求文献链接获取文献详情。为了最大程度实现系统运行的自动化,这两个阶段其实是互相交织、无中间文件生成、无明显顺序的。系统并不是先获取完所有的文献链接,存至文件中,结束后再启动第二阶段工作,而是每请求得到一个链接,立即传送至第二阶段。

前文的流程控制系统中对状态管理只是停留在任务级,或者说只能实现记录当前爬到哪个“日期-学科分类”轮次。但要想完美解决细粒度状态记录、防止数据丢失、文献去重还有非常多的问题要解决,主要有以下几点:

  1. Scrapy调度器管理的请求队列保留在内存中,程序异常终止时,所有未调度请求会丢失。待调度的请求包括第一阶段链接获取与第二阶段内容解析。

  2. 因Scrapy的统一调度策略,致使当前轮次并不与调度队列中的请求同步,调度队列中可能还存放着前几轮获取的文献链接,待传送至第二阶段的获取文献详情模块。这使得程序中断重启动后很难决定从哪个轮次继续:如果只是重复上一未完成轮次可能会漏掉前几轮次的未传入第二阶段的链接,如果重复轮次过深又会多做大量不必要的重复性链接获取工作。

  3. Scrapy自带去重器也在内存中,所以只能保证单次运行抓取不重复,若程序意外中断而重启,重新抓取时该去重器无法达到去重效果。

系统采用了Scrapy-Redis框架解决上述问题,具体如下:

  1. 使用Redis持久化请求队列,将原本内存中处理的调度换成Redis队列。

  2. 使用Redis进行去重,为每个需要去重的请求生成一个独特的指纹,持久化至Redis中(Set数据结构),新请求加入请求队列前,先判断数据库中是否含有相同指纹,无则入队。

使用Redis持久化调度器中的请求队列,使得每个新生成的请求都会被立刻缓存至Redis中,程序终止时几乎不会丢失;程序重新启动后,将从Redis读取请求,完美解决问题(1)(2)。

使用Redis将去重数据持久化,程序运行而去重序列不丢失,解决了问题(3)。

2.9 任务分发

为了进一步加快抓取速度,本设计构建了任务分发模式,是分布式爬虫的一种实现方式。

传统的分布式爬虫是多个服务器上运行一个任务,这样的形式优点在于可以快速执行完一个任务。但程序的运行环境安装非常繁琐,可行的方案是使用docker统一安装,但linux服务器数量不多,window安装docker也很麻烦。

故本设计将程序使用了pyinstaller打包工具,将代码和运行环境一同打包成可执行文件,可在任意一台联网的windows系统电脑上运行,大幅度增强了程序的移植性,提高了分发效率。

得益于系统采用的任务状态管理模块,使得任务的切分非常方便。原系统任务的设定通过操作数据库完成,新系统只要加一个自动建库建表、从配置文件中读取任务、自动更新数据库任务的逻辑即可。

本分发模式的优点在于:

  1. 运行环境依赖低,可以直接使用家用电脑运行程序
  2. 程序与配置分离,一次打包后,通过修改配置文件就能实现任务的分发

3 Redis在Scrapy中的使用

3.1 Scrapy介绍(只介绍redis相关部分)

  • 请求调度方面
    • 平时我们写爬虫,使用requests,请求后处理结果都是顺序执行的
    • scrapy是基于twisted的,所有的请求都对应了一个回调函数
    • 并且,scrapy的所有请求不是马上执行的,它有个调度器,所有的网络请求都会被统一存在一个队列里面,由scrapy引擎调度
    • 问题在于,这个 调度序列在内存里面 ,程序终止的时候,调度队列会丢失
  • 去重方面
    • Scrapy有自带的去重器,同时它也在内存里面,所以它只能保证程序单次运行,链接不重复。但当你要爬的数据量大的时候,或者说想实现断点续爬功能,就gg了。
  • scrapy提供的解决方式
    • 它自带一个jobdir功能,可以在程序终止的时候把内存中的状态信息写到磁盘里。但我不太敢用,听有人说有时候不好用。加上业务逻辑复杂,我觉得还是自己写的靠谱。
  • 单机、集群(或者说分布式方面)
    • 无论是前面的
      • ①请求调度
      • ②请求去重
      • ③以及没提到的,我们获取了请求了网页,并且提取了其中的字段,将字段封装成了对象,将python对象执行数据处理与保存操作的时候
    • 这三个操作原始的scrapy都是单机的,用redis可以达到分布式的作用

3.2 Scrapy-Redis框架

  • 持久化请求队列,保证数据几乎不丢失
    • 之前的scrapy策略是,有了新的请求,将请求入队至内存中的调度队列
    • 现在的策略是,有了新请求,将请求放到redis中,出队了再删除
    • 所以之前程序一关闭,就会丢失队列中所有的请求,数量级在几十到上千乃至上万;现在因为每个新请求直接是入了redis的队的,所以关闭了几乎不会丢失请求(要丢失的话可能只是某个函数执行到一半导致的请求丢失),丢失的数量基本是0,最多1、2这样
    • 换一种表达方式就是,入队这个操作其实是很快的,但是原来只有出队了,保存了数据,这个请求对应的数据才算真正抓取到了,所以程序一关闭,没执行出队的请求、请求了没来得及处理、保存数据的,都会丢失;现在因为是把请求队列放在redis了,数据丢失只可能发生在将入队却未入队的那一刹那,几乎不会丢
  • 持久化items
    • 解释一下items:请求得到网页源代码,提供了你想要的字段,生成的数据对象(比如提取摘要、作者,封装成论文对象,论文就是items),得到数据对象之后,执行数据写入也有个间隙,持久化items可以起到防止这阶段的数据丢失的作用
  • 持久化去重队列
    • 之前讲到scrapy的去重在内存里,只能保证本机本次运行的链接不重复,那么如果持久化了,就能保证集群、多次运行链接不重复
  • 集群、分布式
    • 这个很好理解了,请求队列由redis掌管,那么可以由多个slave都从redis读请求,分布执行;去重也可;也可以把数据处理弄成分布式的,因为封装完成的items会先经过redis暂存一下。(不过我没用itmes的持久化,因为毕竟论文专利对象太占内存了。。)