Python 爬虫基础与实战 课件 第5章 scrapy框架_第1页
Python 爬虫基础与实战 课件 第5章 scrapy框架_第2页
Python 爬虫基础与实战 课件 第5章 scrapy框架_第3页
Python 爬虫基础与实战 课件 第5章 scrapy框架_第4页
Python 爬虫基础与实战 课件 第5章 scrapy框架_第5页
已阅读5页,还剩82页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第5章Scrapy框架

数scrapy是一个快速的Web爬虫框架。是一套基于Twisted的异步处理框架,纯python实现的爬虫框架,用户只需要定制开发几个模块就可以轻松的实现一个爬虫,抓取指定网站的内容或图片等信息。5.1.1scrapySpider示例我们先假设已经安装了scrapy框架模块,下面我们将通过一个示例来分析scrapy框架中实现爬虫spider类的原理。5.1scrapy框架中的Spider类例5-1:scrapySpider示例。importscrapyclassl_spider(scrapy.Spider):#继承scrapy.Spider类name='quotes'start_urls=['/tag/humor/',]defparse(self,response):forquoteinresponse.css('div.quote'):yield{'author':quote.xpath('span/small/text()').get(),'text':quote.css('span.text::text').get(),}next_page=response.css('li.nexta::attr("href")').get()ifnext_pageisnotNone:yieldresponse.follow(next_page,self.parse)5.1scrapy框架中的Spider类scrapy框架有自己的模式,因此程序运行的方式也不同于前面常规的爬虫。将以上代码在python环境中编辑为“例5-1.py”,假设保存在“d:\scrapy”目录下。打开cmd窗口,将当前目录设置为“d:\scrapy”,然后使用以下“scrapyrunspider”命令运行编辑的这个爬虫文件:scrapyrunspider例5-1.py–oli1.json其中,–o为输出参数标志,即将爬取的结果输出到“li1.json”这个json格式文件中。当运行上述命令时,Scrapy会在其中查找Spider定义,然后通过其搜寻器引擎运行它。5.1scrapy框架中的Spider类爬虫开始时对start_urls属性中定义的URL发出请求,并将请求后返回的响应对象responses作为参数传递爬虫处理方法parse;parse是默认爬虫处理回调方法;在parse回调中,可以使用scrapy的内部选择器CSS选择器遍历quote元素,生成包含提取的报价文本'text'和作者'author'的Python字典数据;同时查找指向下一页的链接next_page,并使用与parsecallback相同的方法安排下一个请求。在parse方法中,yield的作用就是把一个函数变成一个生成器(generator),带有yield的函数不再是一个普通函数。生成器特殊的地方在于函数体中没有return关键字,函数的返回值是一个生成器对象。当执行gen1=demo1()返回的是一个生成器对象,此时函数体中的代码并不会执行,只有显性或隐性地调用next的时候才会真正执行里面的代码。5.1scrapy框架中的Spider类5.1.2scrapy.Spider类

scrapy.Spider类是所有爬虫的基类,用户定义的爬虫必须从这个类继承。这个基类Spider并没有提供什么特殊的功能,其仅仅请求给定的“start_urls/start_requests”,并根据返回的结果(responses)调用scrapy.Spider类的“parse()”方法。

对scrapy.Spider类来说,爬取的循环如下:(1)以初始的URL初始化Request对象,并设置回调函数。当该request下载完毕并返回时,将生成Response对象,并作为参数传给该回调函数。5.1scrapy框架中的Spider类(2)spider中初始的request是通过调用start_requests()来获取的。start_requests()读取start_urls中的URL,并以parse为回调函数生成Request对象。(3)在回调函数parse内分析返回的(网页)内容,返回Item对象或者Request或者一个包括二者的可迭代容器。返回的Request对象之后会经过Scrapy处理,下载相应的内容,并调用设置的callback函数(函数可相同)。(4)在回调函数内,您可以使用选择器(Selectors),也可以使用BeautifulSoup,lxml或者其他任何解析器来分析网页内容,并根据分析的数据生成item。(5)最后,由spider返回的item将被存到数据库(由某些ItemPipeline处理)或使用Feedexports存入到文件中。5.1scrapy框架中的Spider类1、scrapy.Spider类的属性和主要方法:(1)name:定义spider爬虫名字的字符串(string)。spider的名字定义了Scrapy如何定位(并初始化)spider,所以其必须是唯一的。name是spider最重要的属性,而且是必须的。(2)allowed_domains:可选。包含了spider允许爬取的域名(domain)列表(list)。当OffsiteMiddleware启用时,域名不在列表中的URL不会被跟进。(3)start_urls:URL列表。当没有制定特定的URL时,spider将从该列表中开始进行爬取。因此,第一个被获取到的页面的URL将是该列表之一。后续的URL将会从获取到的数据中提取。5.1scrapy框架中的Spider类(4)start_requests():该方法必须返回一个可迭代对象(iterable)。该对象包含了spider用于爬取的第一个Request。当spider启动爬取并且未指定URL时,该方法被调用。当指定了URL时,make_requests_from_url()将被调用来创建Request对象。该方法仅仅会被scrapy调用一次。该方法的默认实现是使用start_urls的url生成Request对象。(5)make_requests_from_url(url):该方法接受一个URL并返回用于爬取的request对象。该方法在初始化request时被start_requests()调用,也被用于转化url为request。5.1scrapy框架中的Spider类(6)parse(self,response):当response没有指定回调函数时,该方法是Scrapy处理下载的response的默认方法。parse负责处理response并返回处理的数据以及(/或)跟进的URL。Spider对其他的Request的回调函数也有相同的要求。该方法及其他的Request回调函数必须返回一个包含Request及(或)Item的可迭代的对象。(7)closed(reason):当spider关闭时,该函数被调用。通过分析scrapy.Spider类的定义,以及有此类生成的其他类的调用如Request类等,可以充分理解scrapy.Spider类爬取的过程以及属性和方法。5.1scrapy框架中的Spider类2、scrapy.Spider类定义:classSpider(object_ref):#定义spider名字的字符串(string)。spider的名字定义了Scrapy如何定位(并初始化)spider,所以其必须是唯一的。

name=None#name是spider最重要的属性,而且是必须的。

def__init__(self,name=None,**kwargs):#初始化,提取名字,start_urls

ifnameisnotNone:

=name

elifnotgetattr(self,'name',None):#如果爬虫没有名字,中断报错

raiseValueError("%smusthaveaname"%type(self).__name__)#python对象或类型通过内置成员__dict__来存储成员信息

self.__dict__.update(kwargs)5.1scrapy框架中的Spider类#URL列表。当没有指定的URL时,spider将从该列表中开始进行爬取。因此,第一个被获取到的页面的URL将是该列表之一。后续的URL将会从获取到的数据中提取。

ifnothasattr(self,'start_urls'):self.start_urls=[]

#start_requests()方法将读取start_urls内的地址,并为每一个地址生成一个Request对象,交给Scrapy下载并返回Response。该方法仅调用一次。

defstart_requests(self):forurlinself.start_urls:

yieldself.make_requests_from_url(url)5.1scrapy框架中的Spider类#start_requests()中调用,实际生成Request的函数。

#Request对象默认的回调函数为parse(),提交的方式为getdefmake_requests_from_url(self,url):returnRequest(url,dont_filter=True)#parse,默认的Request对象回调函数,处理返回的response响应信息。

#生成Item或者Request对象。用户必须实现这个类。

defparse(self,response):raiseNotImplementedError5.1scrapy框架中的Spider类3、Request类(由Spider产生)构造函数参数分析:classRequest(object_ref):#url:请求参数

#callback:请求回调函数

#method:http请求类型

#headers:请求头

#body:请求体

#cookies:自动登录后,scrapy会自动把cookie加入request中

#该操作的实现是由的scrapy内置CookiesMiddleware完成的

#meta:元信息,(可以在Request中传递)#encoding:网页编码格式,默认UTF-8#priority:设置在scheduler的调度优先级

#dont_filter:是否不过滤同时发出的相同request请求

#errback:失败的回调函数

5.1scrapy框架中的Spider类

def__init__(self,url,callback=None,method='GET',headers=None,body=None,cookies=None,meta=None,encoding='utf-8',priority=0,dont_filter=False,errback=None,flags=None):…………4、Response类(由Downloader产生)构造函数参数分析classResponse(object_ref):#url网页的url#status返回状态码,默认是200,代表成功

#headers服务器返回的响应头

#body返回的内容体

#request之前yield的Request,对应的请求

def__init__(self,url,status=200,headers=None,body=b'',flags=None,request=None):…………5.1scrapy框架中的Spider类5、parse()方法的工作机制分析parse(self,response)方法,当请求url返回网页没有指定回调函数,默认的Request对象的回调函数即为parse()方法,用来处理网页返回的response,和生成的Item或者Request对象。以下分析一下parse()方法的工作机制:(1) parse方法中因为使用的yield,而不是return,parse函数将会当做一个生成器使用,scrapy会注意调用parse方法中生成的结果,并且判断该结果是一个什么样的类型;我们分析一下scrapy中使用yield循环处理网页url的情况: 首先,scrapy框架对含有yield关键字的parse()方法的调用是以迭代的方式进行的。相当于:

forninparse(self,response):pass5.1scrapy框架中的Spider类 其次,python将parse()函数视为生成器,但首次调用才会开始执行代码,每次迭代请求(即上面的for循环)才会执行yield处的循环代码,生成每次迭代的值。如下方法:defparse(self,response):hxs=HtmlXPathSelector(response)#创建查询对象

all_urls=hxs.select('//a/@href').extract()#获取所有的url,

forurlinall_urls:ifurl.startswith('http://www.……com/……'):#符合给定条件的网址

yieldRequest(url,callback=self.parse)#递归的找下去

print(url)……5.1scrapy框架中的Spider类Scrapy框架开始执行spider,即是对parse()方法迭代的过程{forninparse(self,response)},首先程序会将第一个response对象分析提取需要的东西,然后提取该response中所有的urls进行循环处理;urls循环处理过程中,首次执行到parse-for-yield处,会返回一个迭代值,即生成一个Request1对象(其中定义了回调方法为parse,即callback=self.parse);#此时第一次迭代结束。第一次迭代过程中生成的Request1对象,即一个新的url请求,会返回一个新的response,然后框架会使用该response执行回调函数,进行另一个分支的迭代处理;分支迭代的程序处理完成,进行第二次迭代,会从yield的下一条语句开始,即print,然后继续执行for循环,最后执行到yield,又会生成一个request2对象,生成request2对象,相当于又开始了一个新的分支,直到循环结束。5.1scrapy框架中的Spider类(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);其中callback或-c:指定spider里面用于处理response的函数,默认使用parse函数;6)Request对象经过调度,执行生成scrapy.http.response()响应对象,并送回parse()方法,直到调度器中没有Requset请求(递归的思路);(7)取完之后,parse()工作结束,引擎再根据队列和pipeline中的内容去执行相应的操作;(8)程序在取得各个页面的items前,会先处理完之前所有的request队列的请求,然后再提取items。5.1scrapy框架中的Spider类5.2Scrapy框架5.2.1Scrapy框架组件Scrapy框架分为以下几个部件来协同工作,如图5-1所示。下面分别介绍一下各个组件在框架中的功能。1、Scrapy框架组件的功能介绍(1)ScrapyEngine(引擎):负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等;是整个框架的核心。通过ScrapyEngine处理整个系统的数据流,触发事务等,实现整个框架的正常工作;(2)Scheduler(调度器):用来接受引擎发过来的Request请求并按照一定的方式进行整理排列压入队列中,当引擎需要时,交还给引擎。可以将调度器想像成一个待抓取网页的网址或链接的URL的优先队列,由它来决定下一个要抓取的网址是什么,同时去除重复的网址;5.2Scrapy框架(3)Downloader(下载器):负责下载ScrapyEngine(引擎)发送的所有Requests请求,并将其获取到的内容Responses返回给ScrapyEngine(引擎),由引擎交给Spider来处理。spider将内容进行解析。提取有用的数据或者进行下一步的抓取,或者将数据结构化给pipeline;(4)Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器);(5)ItemPipeline(管道):它负责处理Spider中获取到的Item,并进行后期处理(详细分析、过滤、存储等)的地方;(6)DownloaderMiddlewares(下载中间件):下载中间件可以理解为是一个可以自定义扩展下载功能的组件;5.2Scrapy框架(7)SpiderMiddlewares(Spider中间件):可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests)。在scrapy框架中,我们需要①先设置start_urls这个属性,Scheduler将从start_urls开始,将其交给Downloader进行下载,下载之后会②交给Spider进行分析,Spider分析出来的结果有两种:一种是需要进一步抓取的链接,例如之前分析的“下一页”的链接,这些新的需要下载的链接会③被传回Scheduler;另一种是需要保存的数据,它们则被③送到ItemPipeline模块,对数据进行分析、过滤、存储等后期处理。5.2Scrapy框架2、Scrapy组件的运作流程:当我们用scrapy框架的机制写好一段爬虫程序后,程序运行过程中,各个部件的工作流程如下:(1)ScrapyEngine(引擎)询问Spider,需要处理的网站信息;Spider将start_urls的值传给ScrapyEngine(引擎);(2)ScrapyEngine(引擎)请求Scheduler(调度器),将request请求排序插入网络链接地址队列中;(3)ScrapyEngine(引擎)请求Scheduler(调度器),把Scheduler(调度器)处理好的request请求发给ScrapyEngine(引擎);(4)ScrapyEngine(引擎)把request请求发给Downloader(下载器),请求Downloader(下载器)按照DownloaderMiddlewares(下载中间件)的设置下载这个request请求;(5)Downloader(下载器)反馈信息到ScrapyEngine(引擎),下载器将响应对象responses信息反馈给引擎;5.2Scrapy框架(6)ScrapyEngine(引擎)分析responses对象,如下载成功则将信息传给Spider模块,responses默认是交给defparse()函数处理的,解析出items或者requests;如失败则引擎告知调度器,这个request下载失败了,请调度器记录下来,待会儿再进行下载处理;(7)Spider将解析出的解析出items或者requests提交处理信息给ScrapyEngine(引擎);(8)ScrapyEngine(引擎)获取到items或者requests后,分别请求ItemPipeline(管道)或Downloader(下载器),将items发送给ItemPipeline,将requests发送给scheduler。(9)从第三步开始不断循环,直到获取完需要的全部信息。当调度器中不存在任何request请求了,整个程序才会停止。对于下载失败的URL,Scrapy会重新下载。5.2Scrapy框架5.2.2scrapy框架的安装Scrapy框架功能十分强大,因此Scrapy依赖很多扩展库的功能。为了顺利安装成功,最好不要使用pipinstallscrapy命令直接安装,而将需要的依赖库先行安装。下面介绍Windows系统中使用scrapy框架,需要安装的一些支撑库。其中,可能需要安装一些安装依赖库需要的一些工具。如安装wheel,以便于后面依赖库的安装。1、工具和依赖库简介scrapy需要安装四个依赖库,分别为lxml,pyOpenSSL,Twisted和PyWin32。同时为了安装这些依赖库,有时还需要安装一个wheel以便于执行“.whl”文件。“.whl”格式本质上是一个压缩包,里面包含了py文件,以及经过编译的pyd文件。5.2Scrapy框架依赖库的版本:如python3.6版本信息就是3.6版本,这样后期下载依赖库时必须选择是64位的或是32位的系统且与python版本对应的依赖库。2、安装wheel和升级pip(1)安装wheel:在cmd窗口下,输入以下命令行:Pip3installwheel(2)升级pip命令:如果pip版本较低,需先升级pip命令。cmd窗口下进入python安装目录后,输入命令行:C:\Python35>python-mpipinstall--upgradepip5.2Scrapy框架3、安装依赖库(1)首先,查看python版本信息:在cmd中输入指令python,查看python的版本,从上面系统信息中可以看出我的Python版本为Python3.5.2-64bit。

C:\Windows\System32>python(2)下载第三方的依赖库:在/~gohlke/pythonlibs/有很多用于windows系统环境下的编译好的Python第三方库,我们下载好对应自己Python版本的库即可。登录网址/~gohlke/pythonlibs/,Ctrl+F搜索Lxml、Twisted、pyOpenSSL、Scrapy,下载对应的版本,例如:lxml-3.7.3-cp35-cp35m-win_adm64.whl,表示lxml的版本为3.7.3,对应的python版本为3.5-64bit。如下载后存放在文件夹“d:\scrapy依赖库”中。5.2Scrapy框架(3)安装:在cmd窗口中输入DOS指令,进入下载好的whl文件的文件夹下,例如我的whl文件放在了“d:\scrapy依赖库”文件夹下,依次执行如下命令:

pip3installlxml-3.7.3-cp35-cp35m-win_amd64.whlpip3installTwisted-17.1.0-cp35-cp35m-win_amd64.whlpip3installpyOpenSSL-19.1.0-py2.py3-none-any.whlpip3installScrapy-1.5.1-py2.py3-none-any.whlpip3installpywin32‑228‑cp35‑cp35m‑win_amd64.whl5.2Scrapy框架以上的安装步骤是比较稳妥的情况。在网络条件比较好的情况下,我们也可以在cmd窗口下直接使用命令行:pip3installscrapy直接安装。如果报错,也可以使用下列命令行逐步安装:

pip3installlxmlpip3installTwistedpip3installpyOpenSSLpip3installpywin32pip3installscrapy4、检查是否安装成功:打开cmd窗口,输入命令:

C:\Windows\System32>scrapyversionScrapy1.5.1显示Scrapy1.5.1版本信息,表明安装成功。5.2Scrapy框架5.2.3scrapy框架的应用通常使用框架编写爬虫程序时,由于爬虫框架中各个组件的基本功能已经实现。因此,在我们使用scrapy框架进行编程时,首先需要了解一些常用的命令。制作Scrapy爬虫一共需要4步:新建项目(scrapystartprojectxxx):新建一个新的爬虫项目明确目标(编写items.py):明确你想要抓取的目标制作爬虫(spiders/xxspider.py):制作爬虫开始爬取网页存储内容(pipelines.py):设计管道存储爬取内容5.2Scrapy框架1、常用命令创建项目:scrapystartprojectxxx进入项目:cdxxx#进入某个文件夹下创建爬虫:scrapygenspiderxxx(爬虫名)

(爬取域)生成文件:scrapycrawlxxx-oxxx.json(生成某种类型的文件)运行爬虫:scrapycrawlXXX列出所有爬虫:scrapylist获得配置信息:scrapysettings[options]5.2Scrapy框架2、命令的应用安装好Scrapy以后,我们可以运行上述的startproject命令生成该项目的默认结构。具体步骤为:打开cmd终端进入我们想要存储Scrapy项目的目录,然后运行scrapystartproject<projectname>。这里我们用FirstProj作为项目名。即:scrapystartprojectFirstProj。(1)创建项目:进入存放项目的目录位置,为d:\scrapystartprojectFirstProj认识目录结构:在上述命令执行后,将在d:盘下创建了一个D:\FirstProj文件夹。可以看一下此文件夹下,scrapy命令生成的文件结构。注:带*的是重点。5.2Scrapy框架├─FirstProj项目总目录││scrapy.cfg部署项目的配置文件(一般不用)│└─FirstProj项目核心目录││items.py定义数据结构的文件(*),这是创建数据容器的地方,爬取的信息分别放到不同容器里││middlewares.py存放各种中间件的文件││pipelines.py管道文件(*)││settings.py项目配置文件(*)││__init__.py包的标记│├─spiders爬虫核心目录,该目录下存储实际的爬虫代码│││__init__.py││└─__pycache__│└─__pycache__python的缓存文件5.2Scrapy框架(2)生成爬虫文件:应用模板先生成一个爬虫文件。需要有如下2个步骤:cd项目核心目录scrapygenspider爬虫名字爬虫域名如在cmd窗口下输入命令:cdFirstProjscrapygenspiderbaidu在创建的爬虫文件中,只是以模板生成了最基本的爬虫文件。打开项目目录,分析一下baidu.py代码:5.2Scrapy框架#-*-coding:utf-8-*-importscrapyclassBaiduSpider(scrapy.Spider):#继承Spider类

name='baidu'#爬虫的唯一标识,不能重复,启动爬虫的时候要用

allowed_domains=['']#限定域名,只爬取该域名下的网页

start_urls=['/']#开始爬取的链接地址

defparse(self,response):pass#未定义,由用户根据需求定义其实我们也可以自行创建baidu.py并编写上面的代码,只不过使用命令可以免去编写固定代码的麻烦。5.2Scrapy框架编程建立一个Spider,必须用scrapy.Spider类创建一个子类,并确定三个强制的属性和一个方法。name="":这个爬虫的识别名称,必须是唯一的,在不同的爬虫必须定义不同的名字。allow_domains=[]是搜索的域名范围,也就是爬虫的约束区域,规定爬虫只爬取这个域名下的网页,不存在的URL会被忽略。start_urls=[]:爬虫从这里开始抓取数据,所以,第一次下载的数据将会从这些urls开始。parse方法,主要有两个作用,负责解析start_url地址形成的请求request下载的Response对象;如果有新的url则加入爬取队列。5.2Scrapy框架如我们可以完善baidu.py文件:#-*-coding:utf-8-*-importscrapyclassBaiduSpider(scrapy.Spider):name='baidu'allowed_domains=['']start_urls=['/']defparse(self,response):fname=response.url.split(".")[-2]#获取url,用”.”分段,获取文件名

withopen(fname+'.txt','w')asf:f.write(response.text)#把访问的得到的网页源码写入文件5.2Scrapy框架注意:以上程序的运行需打开setting.py文件,将“ROBOTSTXT_OBEY=True”注释掉。response是一个响应对象,可通过对象的一些主要属性访问响应信息:

response.url请求的urlresponse.status状态码

response.headers响应头

response.text响应的字符串格式内容

response.body响应的字节格式内容

response.xpath('……').extract()方法用来提取数据5.2Scrapy框架4)启动爬虫cdFirstProj/FirstProj/spidersscrapycrawl爬虫名字(scrapycrawlbaidu)需要注意,不要带文件后缀.py。这里的爬虫名字是爬虫文件baidu.py中的name='baidu'。那么启动爬虫时框架做了什么工作呢?Scrapy为Spider的start_urls属性中的url创建了Request对象,并将parse方法作为回调函数(callback)赋值给了requests,而requests对象经过调度器的调度,执行生成response对象并送回给parse()方法进行解析。所以请求链接的改变是靠回调函数实现的。如parse()方法中生成了后继的新访问地址url,需要调用以下的yield语句:yieldscrapy.Request(self.url,callback=self.parse)5.2Scrapy框架3、启动spider的方式(1)终端模式启动:进入爬虫文件目录,输入以下命令:scrapycrawl爬虫名字(2)文件方式启动:在spider目录下新建一个python文件。如:start.py。然后编写如下代码:fromscrapyimportcmdline#导入cmdline模块#以下两种任选其中一种cmdline.execute(['scrapy','craw','baidu'])cmdline.execute('scrapycrawlbaidu'.split(''))或fromscrapy.cmdlineimportexecute#以下两种任选其中一种execute('scrapycrawlbaidu'.split())execute(['scrapy','crawl','baidu'])

然后,在pythonidle或其他集成环境中运行start.py文件即可。5.2Scrapy框架4、输出格式一般在scrapy框架中,通过在item.py文件中设置需要提取的数据容器,然后通过管道程序pipeline.py进行相应的处理。Scrapy框架中,提供了三种item数据输出的文件方式,分别为:json、xml和csv文件格式。(1)scrapy输出格式cmd命令行:scrapycrawl爬虫名字-o自定义文件名.格式。(2)默认文件存放目录为spiders目录下。json类型:scrapycrawlbaidu-obaidu.jsonxml类型:scrapycrawlbaidu-obaidu.xmlcsv类型:scrapycrawlbaidu-obaidu.c5.2Scrapy框架(3)注意事项:如果想保存item到一个json文件中,除了使用我们后面介绍的pipeline进行写入保存外,还可以cmd命令。一般情况下,使用这种格式输出,需要定义数据项并需要返回。如果没有设置提取数据项或spider爬虫文件没有yielditem,,一般返回文件为空;如果保存的文件出现中文乱码,可以在settings文件中写入一行:FEED_EXPORT_ENCODING='utf-8'在设计爬虫时,最麻烦的一步就是对网页元素进行分析,Scrapy带有自己的数据提取机制。Scrapy的元素选择器XPath或CSS表达式或结合正则表达式能快速的实现定位功能且提取效率极高。5.3.1scrapy集成XPath或CSS选择器的不同scrapy已经集成了XPath或CSS和选择器方法,直接使用即可。在scrapy框架中使用XPath或CSS,得到的是selector对象。假设HTML标签为:

<title>sracpyselectorwebsite</title>,让我们构造一个XPath来选择title标记内的文本,分析scrapy中的XPath或CSS表达式返回的值为selector对象:5.3Scrapy框架中的选择器(selector)下面以例5-2分析scrapy中的XPath或CSS表达式返回的值为selector对象:例5-2:选择器的不同。fromscrapy.selectorimportSelectorbody='<html><body><span>good</span></body></html>'sel=Selector(text=body)sel1=sel.xpath('//span/text()')print(sel1)输出为selector对象:[<Selectorxpath='//span/text()'data='good'>]。5.3Scrapy框架中的选择器(selector)我们在对比一下常规的XPath选择器解析的结果:fromlxmlimportetreebody='<html><body><span>good</span></body></html>'body1=etree.HTML(body)sel2=body1.xpath('//span/text()')print(sel2)输出为字符串列表:['good']。由此可见,scrapy集成XPath或CSS选择器的捕获的结果不是常规的字符串值,而是selector对象。如要提取selector对象需要进行内容提取。5.3Scrapy框架中的选择器(selector)5.3.2ScrapySelectors选择器ScrapySelectors内置了XPath和CSSSelector表达式机制。Selector提供一些基本的方法,最常用的还是xpath()方法。1、Selector的基本方法xpath():传入xpath表达式,返回该表达式所对应的所有节点的selector对象list列表。语法同前面的Xpath语法。css():传入CSS表达式,返回该表达式所对应的所有节点的selector对象list列表,语法同前面css语法。re():根据传入的正则表达式对数据进行提取,返回Unicode字符串list列表。re_first():根据传入的正则表达式对数据进行提取,返回Unicode字符串list列表的第一个元素。extract():序列化该节点为Unicode字符串并返回list列表数据。等同于getall()方法。extract_first():并返回list列表里面的第一个字符串。等同于get()方法。5.3Scrapy框架中的选择器(selector)2、scrapy的extract()、extract_first()方法,get()、getall()方法在使用scrapy爬虫的时候,使用xpath()或css()来获取html标签,需用到提取的方法,有两类提取的方法,分别是:extract()、extract_first()方法和get()、getall()方法。例5-3:xpath选择器的方法应用。fromscrapy.selectorimportSelectorbody='<html><body><span>good</span><span>scrapy</span></body></html>'sel=Selector(text=body)sel1=sel.xpath('//span/text()')print(sel1)print("extract()=",sel1.extract())5.3Scrapy框架中的选择器(selector)print("extract_first()=",sel1.extract_first())print("extract()[0]=",sel1.extract()[0])#取列表第一个元素print("get()=",sel1.get())print("getall()=",sel1.getall())print("get()[0]=",sel1.getall()[0])#列表第一个元素输出的结果为:[<Selectorxpath='//span/text()'data='good'>,<Selectorxpath='//span/text()'data='scrapy'>]extract()=['good','scrapy']extract_first()=goodextract()[0]=goodget()=goodgetall()=['good','scrapy']get()[0]=good5.3Scrapy框架中的选择器(selector)注意事项:(1)get()、getall()方法是新发布的方法,extract()、extract_first()方法是早期Scrapy版本方法。(2)extract()、extract_first()方法取不到就返回None。(3)get()、getall()方法取不到就raise一个错误5.3Scrapy框架中的选择器(selector)使用ScrapySelectors选择器获取下载网页信息中有效数据,一般需要三个过程:首先需要构造选择器Selectors对象;其二是在Selectors对象上使用XPath和CSSSelector表达式,获得Selectors对象;最后使用getall()等方法提取有效的数据。1、构造选择器Scrapy选择器是Selector通过将TextResponse对象或标记作为unicode字符串文本(在text参数中)传递而构造的类的实例。5.3.3使用ScrapySelectors选择器通常,不需要手动构造Scrapy选择器:Spider回调parse()方法中提供了response对象,因此在大多数情况下,使用response.selector.xpath()和response.selector.css()或快捷方式response.css()和response.xpath(),即可对响应正文进行一次解析。有时,需要直接使用Selector。一般需要构造Selector对象后才能使用。(1)从字符串文本构造。看以下的代码:>>>fromscrapy.selectorimportSelector#导入Selector#定义一段html文本>>>body='<html><body><span>good</span></body></html>'>>>sel=Selector(text=body)

#构造构造Selector对象>>>sel.xpath('//span/text()').get()#解析和提取数据5.3.3使用ScrapySelectors选择器分析:①从scrapy.selector导入Selector:fromscrapy.selectorimportSelector。②构造Selector对象:sel=Selector(text=body),其中需要将文本信息传递给text参数。Body是html文本串。(2)在Scrapy的Spider类中的parse()回调函数中的参数response直接调用xpath()或者css()方法来提取数据。response有一个属性selector,调用response.selector返回的内容就相当于用response的text构造了一个Selector对象。Scrapy提供了两个实用的快捷方法,response.xpath()和response.css(),它们二者的功能完全等同于response.selector.xpath()和response.selector.css()。5.3.3使用ScrapySelectors选择器2、使用选择器构造了选择器后,通过这个Selector对象我们可以调用xpath()、css()方法以及正则表达式re()等,通过向方法传入XPath或CSS选择器参数就可以实现信息的提取。xpath()、css()方法以及正则表达式re()的语法已在前面章节“网页解析器”中介绍,这里不再赘述。5.3.3使用ScrapySelectors选择器下面我们使用我们前面介绍的scrapy的命令来是实现第一个爬虫spider1.py。我在制作这个爬虫时是以D:/根目录作为存放地址的。程序在例5-5fspider文件夹下。1、创建项目在开始抓取之前,设置一个新的Scrapy项目名称如fspider。打开cmd窗口,使用dos命令进入D:/根目录,输入下列命令行:scrapystartprojectfspider2、生成爬虫文件使用模板生成一个爬虫框架文件,我们首先确定需要爬取的网站网址,我们以作为示例网站。如在cmd窗口下输入命令:cdfspiderscrapygenspiderspider15.4scrapy爬虫的简单应用可以进入d:\fspider查看一下目录情况,可以发现在D:\fspider\fspider\spiders\下生成了一个名为“spider1.py”的文件,这个即为模板生成的爬虫文件。模板会将相关的配置信息在setting.py文件中初步设置好。但“spider1.py”爬虫文件的回调函数parse()需要用户根据需要编写。如我们现在需要提取网页中class="text"、class="author"和class="tag"标签后的所有内容。我们需通过编写代码完善“spider1.py”程序。首先我们打开网站,分析每个“quote”都所示的HTML元素。Scrapy爬虫部件通常会生成许多字典,其中包含从页面中提取的数据。为此,我们改写prase()函数,使用yield关键字将需要提取的数据返回给scrapy框架的相关部件。5.4scrapy爬虫的简单应用spider1.py如下所示:#-*-coding:utf-8-*-importscrapyclassSpider1Spider(scrapy.Spider):name='spider1'allowed_domains=['']start_urls=['/']defparse(self,response):

forquoteinresponse.css('div.quote'):yield{'text':quote.css('span.text::text').get(),'author':quote.css('small.author::text').get(),'tags':quote.css('div.tagsa.tag::text').getall(),}5.4scrapy爬虫的简单应用3、运行并存储抓取的数据存储已抓取数据的最简单方法是使用Feed输出,并使用以下命令:cdspider#进入爬虫目录scrapycrawlspider1-os1.json生成一个s1.json文件,其中包含所有以JSON序列化的剪贴项目默认存放在项目目录下。其中需要注意的是,Scrapy会每次附加到给定文件,而不是覆盖其内容。如果您两次运行此命令而没有在第二次之前删除该文件,有可能得到一个损坏的JSON文件。5.4scrapy爬虫的简单应用4、爬取后继链接检查页面,在代码中查找“Next”标签,我们可以看到这一段指向下一页的链接的代码:

<ulclass="pager"><liclass="next"><ahref="/page/2/">Next<spanaria-hidden="true">→</span></a></li></ul>parse()修改为以递归方式链接到下一页的链接,并从中提取数据:5.4scrapy爬虫的简单应用defparse(self,response):forquoteinresponse.css('div.quote'):yield{'text':quote.css('span.text::text').get(),'author':quote.css('small.author::text').get(),'tags':quote.css('div.tagsa.tag::text').getall(),}#获取新的需访问的地址

next_page=response.css('li.nexta::attr(href)').get()ifnext_pageisnotNone:next_page=response.urljoin(next_page)#生成绝对地址

yieldscrapy.Request(next_page,callback=self.parse)5.4scrapy爬虫的简单应用或forhrefinresponse.css('li.nexta::attr(href)').getall():next_page=response.urljoin(href)

yieldscrapy.Request(next_page,self.parse)该parse()方法将查找到下一页的链接,使用该urljoin()方法构建完整的绝对URL(因为链接可以是相对的),并产生对下一页的新请求,并调用自身为回调函数以进行处理提取下一页的数据,并保持对所有页面的抓取。5.4scrapy爬虫的简单应用5、创建请求的快捷方式scrapy提供了response.follow()和response.follow_all()方法作为创建Request对象的快捷方式,其中response.follow()只创建一个Request实例;response.follow_all()创建多个Request请求。response.follow()方法:与scrapy.Request不同,response.follow直接支持相对URL,无需调用urljoin方法。也可以直接将地址选择器传递给response.follow而不一定需要提取字符串地址。可以将parse()中的产生下一页的请求修改为:next_page=response.css('li.nexta::attr(href)').get()ifnext_pageisnotNone:

yieldresponse.follow(next_page,callback=self.parse)5.4scrapy爬虫的简单应用response.follow_all()方法:要从一个可迭代对象创建多个请求,可以使用response.follow_all()方法。anchors=response.css(''li.nexta::attr(href)')yieldfromresponse.follow_all(urls=anchors,callback=self.parse)或者,将其进一步缩短:yieldfromresponse.follow_all(css=''li.nexta::attr(href)',callback=self.parse)Scrapy框架中除了通过feed提供简单的数据输出管道参数“-o”功能之外,框架的ItemPipeline组件还提供了数据输出处理。ItemPipeline组件主要通过框架中的两个文件完成响应的功能,我们可以打开“d:\fspiders\fspiders”目录,可以看到其中“items.py”和“pipeline。py”两个文件,这是模板自动生成。5.5.1items编写爬虫的主要目标是从通常是web页面的非结构化源中提取结构化数据。爬行器可以将提取的数据作为Python中定义为“键-值”对的对象item数据项返回。“items.py”文件就是用来提供定义需要提取的item数据项的文件。5.5数据管道1、定义Item

Item是保存爬取到的数据的容器,其使用方法和python字典类似,并且提供了额外保护机制来避免拼写错误导致的未定义字段错误。通过创建一个scrapy.Item子类,并且定义类型为scrapy.Field的类属性来定义一个Item。如下例:importscrapyclassFspiderItem(scrapy.Item):#创建一个继承scrapy.Item的子类

name=scrapy.Field()price=scrapy.Field()stock=scrapy.Field()tags=scrapy.Field()last_updated=scrapy.Field(serializer=str)5.5数据管道这样就定义了一个类似于pyhon字典dict类型的数据容器,其中,name、price、stock、tags和last_updated为Item项的“键”名称。在spiders组件的parse()方法中,通过将需提取的数据赋值给item,如item['name']=response.css('li.nexta::attr(href)').get(),完成数据提取到items容器中。2、项目字段FieldField对象用于为每个字段指定元数据。例如,last_updated上面示例中说明的字段的序列化函数功能。Field对象接受的值没有任何限制,可以通过Item.fields属性访问它们。3、使用Item对items的数据项的操作非常类似于dict字典。对字典的适用的方法等基本都是用于item对象。例5-6示。5.5数据管道例5-6:item容器应用。importscrapyclassFspiderItem(scrapy.Item):#创建一个继承了scrapy.Item的子类

name=scrapy.Field()price=scrapy.Field()stock=scrapy.Field()last_updated=scrapy.Field(serializer=str)#实例化类fsitem=FspiderItem()fsitem1=FspiderItem(name='python',price=1000)#实例化类print("fsitem=",fsitem,"及fsitem1=",fsitem1)#字段填充和获取字段值fsitem['name']='DesktopPC'print(fsitem['name'])print(fsitem.get('name'))#访问所有填充值print(fsitem1.keys())print(fsitem1.items())5.5数据管道4、spiders中的item项的应用示例以例5-5fspider目录下的例子为基础,首先将目录下的“items.py”文件修改为:importscrapyclassFspiderItem(scrapy.Item):#创建一个继承了scrapy.Item的子类

text=scrapy.Field()#存储引文信息

author=scrapy.Field()#存储作者信息

tags=scrapy.Field()#存储引文标签信息5.5数据管道在spiders目录下新建一个“spider2.py”文件。代码如下:importscrapyfromfspider.itemsimportFspiderItem#导入items.py模块中的FspiderItem类classspider2Spider(scrapy.Spider):name="spider2"defstart_requests(self):#本例以自定义的start_req

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论