第3章Scrapy爬虫 本章学习目标  了解Scrapy爬虫概念。  掌握Scrapy爬虫框架的安装。  了解Scrapy爬虫的原理与流程。  掌握Scrapy爬虫框架的实现方式。 本章先向读者介绍Scrapy爬虫概念; 再介绍Scrapy爬虫的原理与流程,最后介绍Scrapy爬虫框架的实现。 视频讲解 3.1Scrapy爬虫概述 1. Scrapy的含义 Scrapy是一个使用Python语言编写的开源网络爬虫框架,是一个高级的Python爬虫框架。Scrapy可用于各种有用的应用程序,如数据挖掘、信息处理及历史归档等,目前主要用于抓取Web站点并从页面中提取结构化的数据。 Scrapy简单易用、灵活,并且是跨平台的,在Linux及Windows平台上都可以使用。Scrapy框架目前可以支持Python 2.7及Python 3+版本,本章主要介绍在Windows 7中,Python 3.7版本下Scrapy框架的应用。 2. Scrapy的安装 在Windows 7中安装Scrapy框架的命令为pip install Scrapy。但是安装Scrapy通常不会直接成功,因为Scrapy框架的安装还需要多个包的支持。 1) 下载Scrapy的twisted包 Scrapy依赖twisted包,同样使用whl格式的包进行安装,进入网站http://www.lfd.uci.edu/~gohlke/pythonlibs/,在网页中搜索twisted找到其对应的whl包并下载。 2) 下载Scrapy的whl包 在网上输入下载地址“http://www.lfd.uci.edu/~gohlke/pythonlibs/”,进入该网站找到所需要的Scrapy的whl包。 3) 下载Scrapy的lxml包 lxml包是用来做xpath提取的,这个库非常容易安装,直接在命令行窗口中输入“pip install lxml”。 4) 下载Scrapy的zope.interface包 zope.interface包是Scrapy爬虫的接口库,可直接在命令行窗口中输入“pip install zope.interface”。 5) 下载Scrapy的pywin32包 pywin32是一个第三方模块库,主要的作用是方便Python开发者快速调用Windows API的一个模块库,可直接在命令行中输入“pip install pywin32”。 6) 下载Scrapy的pyOpenSSL包 pyOpenSSL是在Python中一套基于网络通信的协议,可直接在命令行窗口中输入“pip install pyOpenSSL”。 7) 使用命令安装Scrapy 在安装Scrapy框架之前,必须依次安装twiste包、whl包、lxml包、zope.interface包、pywin32包和pyOpenSSL包,并在上述包全部安装完成后,运行pip install scrapy命令来安装Scrapy框架。为确保Scrapy框架已安装成功,在Python中测试是否能够导入Scrapy库,输入“import scrapy”命令,运行如图31所示。 图31导入Scrapy库 接着再输入“scrapy.version_info”命令显示Scrapy库的版本,运行结果如图32所示。 图32显示Scrapy库的版本 从图32中可以看出,当前安装的版本是1.5.1。在安装完成后,即可使用Scrapy框架爬取网页中的数据。 视频讲解 3.2Scrapy原理 3.2.1Scrapy框架的架构 1. Scrapy架构组成 Scrapy框架由Scrapy Engine、Scheduler、Downloader、Spiders、Item Pipeline、Downloader Middlewares及Spider Middlewares等几部分组成,具体结构如图33所示。 图33Scrapy架构组成 Scrapy框架的具体组件作用如下。 1) Scrapy Engine Scrapy Engine也称为Scrapy引擎,它是爬虫工作的核心,负责控制数据流在系统中所有组件中的流动,并在相应动作发生时触发事件。 2) Scheduler Scheduler也称为调度器,它从引擎接受Request并将它们入队,以便之后引擎请求它们时提供给引擎。 3) Downloader Downloader也称为下载器,它负责获取页面数据并提供给引擎,而后提供给Spider。 4) Spiders Spiders也可称为Spider,中文一般读作蜘蛛,它是Scrapy用户编写用于分析由下载器返回的Response,并提取出Item和额外的URL的类,每个Spider都能处理一个域名或一组域名。蜘蛛的整个抓取流程如下。 (1) 首先获取第一个URL的初始请求,当请求返回后调取一个回调函数。第一个请求是通过调用start_requests()方法,该方法默认从start_urls中的URL中生成请求,并执行解析来调用回调函数。 (2) 在回调函数中,解析网页响应并返回项目对象和请求对象或两者的迭代。这些请求也将包含一个回调,然后被Scrapy下载,然后有指定的回调处理。 (3) 在回调函数中,解析网站的内容,使用xpath选择器并生成解析的数据项。 (4) 最后,从蜘蛛返回的项目通常会进驻到项目管道。 5) Item Pipeline Item Pipeline也称为数据管道,它的主要责任是负责处理由蜘蛛从网页中抽取的数据,它的主要任务是清洗、验证和存储数据。当页面被蜘蛛解析后,将被发送到数据管道,并经过几个特定的次序处理数据。每个数据管道的组件都是由一个简单的方法组成的Python类。它们获取了项目并执行它们的方法,同时它们还需要确定的是是否需要在数据管道中继续执行下一步或是直接丢弃掉不处理。Item Pipeline通常执行的过程如下。 (1) 清洗HTML数据。 (2) 验证解析到的数据。 (3) 检查是不是重复数据。 (4) 将解析到的数据存储到数据库中。 6) Downloader middlewares Downloader middlewares也称为下载器中间件,它是介于Scrapy引擎和调度之间的中间件,主要用于从Scrapy引擎发送到调度的请求和响应。 7) Spider middlewares Spider middlewares也称为爬虫中间件,它是介于Scrapy引擎和爬虫之间的框架,主要工作是处理蜘蛛的响应输入和请求输出。 在整个框架组成中,Spiders是最核心的组件,Scrapy爬虫开发基本上是围绕Spiders而展开的。 此外,在Scrapy框架中还有3种数据流对象,分别是Request、Response和Items。  Request: Scrapy中的HTTP请求对象。  Response: Scrapy中的HTTP响应对象。  Item: 一种简单的容器,用于保存爬取得到的数据。 2. Scrapy框架的工作过程 当Spider要爬取某URL地址的页面时,首先用该URL构造一个Request对象,提交给Engine(图33中的①),随后Request对象进入Scheduler,按照某种调度算法排队,之后的某个时候从队列中出来,由Engine提交给Downloader(图33中的②、③、④)。Downloader根据Request对象中的URL地址发送一次HTTP请求到目标网站服务器,并接受服务器返回的HTTP响应,构建一个Response对象(图33中的⑤),并由Engine将Response提交给Spider(图33中的⑥),Spider提取Response中的数据,构造出Item对象或者根据新的连接构造出Request对象。分别由Engine提交给Item Pipeline或者Scheduler(图33中的⑦、⑧)这个过程反复进行,直至爬完所有的数据。同时,数据对象在出入Spider和Downloader时可能会经过Middleware进行进一步的处理。 3.2.2Request对象和Response对象 Scrapy中的Request对象和Response对象通常用于爬取网站,Request对象在爬虫程序中生成并传递到系统,直到它们到达下载程序,后者执行请求并返回 图34Scrapy中Request对象和 Response对象的作用 一个Response对象,该对象返回到发出请求的爬虫程序。如图34所示的是Scrapy中的Request对象和Response对象的作用。 1. Request对象 1) Request基础参数介绍 Request对象用于描述一个HTTP请求,由Spider产生,Request构造函数的参数列表如下。 Request(url[, callback, method='GET', headers, body, cookies, meta, encoding='utf-8', priority=0, dont_filter=False, errback]) 参数的含义如下。  url: 请求页面的URL地址。  callback: 请求回来的Response处理函数,也称为回调函数。如果请求没有指定回调函数,则将使用spider的parse()方法。  method: HTTP请求的方法,默认为'GET'。  headers: 请求的头部字典,dict类型。dict值可以是字符串(对于单值标头)或列表(对于多值标头)。如果None作为值传递,则不会发送HTTP头。  body: 请求的正文,str或unicode类型。如果unicode传递了a,那么它被编码为str使用传递的编码(默认为Utf8)。如果body没有给出,则存储一个空字符串。不管这个参数的类型,存储的最终值将是一个str(不会是unicode或None)。  cookies: 设置页面的cookies,Dict类型。当某些网站返回cookie(在响应中)时,这些cookie会存储在该域的cookie中,并在将来的请求中再次发送。  meta: 用于在页面之间传递数据,Dict类型。Request对象接收一个meta参数,一个字典对象,同时Response对象有一个meta属性可以取到相应request传过来的meta。  encoding: 请求的编码,url和body参数的默认编码为Utf8。  priority: 请求的优先级(默认为0)。调度器使用优先级来定义用于处理请求的顺序,具有较高优先级值的请求将较早执行。允许负值以指示相对低优先级。  dont_filter: 表示此请求不应由调度程序过滤,默认为False。  errback: 如果在处理请求时引发任何异常,将调用此函数,这包括失败的404 HTTP错误等页面。 2) Request对象方法介绍  copy(): 复制对象。  replace(): 替换对象。 3) 参数的应用 (1) 将附加数据传递给回调函数。请求的回调函数是当该请求的响应被下载时将被调用的函数。回调函数将使用下载的Request对象作为其第一个参数来调用,代码如下。 def parse_page1(self, response): return scrapy.Request("http://www.example.com/some_page.html", callback=self.parse_page2) def parse_page2(self, response): self.logger.info("Visited %s", response.url) (2) 使用errback在请求处理中捕获异常。请求的errback是在处理异常时被调用的函数,它接收一个Twisted Failure实例作为第一个参数,并可用于跟踪连接超时、DNS错误等,代码如下。 class ErrbackSpider(scrapy.Spider): name = "errback_example" start_urls = [ "http://www.httpbin.org/", "http://www.httpbin.org/status/404", "http://www.httpbin.org/status/500", "http://www.httpbin.org:12345/", "http://www.httphttpbinbin.org/", ] def errback_httpbin(self, failure): self.logger.error(repr(failure)) (3) 使用FormRequest通过HTTP POST发送数据。如果想在爬虫中模拟HTML表单POST并发送几个键值字段,可以返回一个FormRequest对象,代码如下。 return [FormRequest(url="http://www.example.com/post/action", formdata={'name': 'John tom', 'age': '37'}, callback=self.after_post)] 2. Response对象 1) Response基础参数介绍 Response对象用于描述一个HTTP响应,由Downloader产生,Response构造函数的参数列表如下: Response(url[, status=200, headers=None, body=b'', flags=None, request=None]) 参数的含义如下。  url: 响应页面的URL地址。  status: 响应的HTTP状态,默认为200。  headers: 包含响应标题的类字典对象。可以使用get()返回具有指定名称的第一个标头值或getlist()返回具有指定名称的所有标头值来访问值。  body: HTTP响应正文。  flags: 包含此响应的标志的列表。标志是用于标记响应的标签,如'cached'、'redirected'等。  request: 产生该HTTP响应的request对象。 2) Response对象方法介绍  copy(): 返回一个新的响应。  replace(): 返回具有相同成员的Response对象,但通过指定的任何关键字参数赋予新值的成员除外。 3) Response响应子类介绍 Response对象是一个基类,根据响应内容有3个子类,分别是TextResponse、HtmlResponse和XmlResponse。 (1) TextResponse子类。TextResponse支持新的构造参数,是对Response对象的补充,TextResponse方法的参数如下。 TextResponse(url[, encoding[, ...]]) TextResponse的主要作用是添加一个新的构造函数encoding()。encoding(string)是一个字符串,包含用于此响应的编码。如果创建一个TextResponse具有Unicode主体的对象,它将使用这个编码进行编码。如果encoding()是None(默认值),则将在响应标头和正文中查找编码。 除此以外,TextResponse还支持以下属性或对象。  text: 文本形式的HTTP响应正文。  Selector: 用于在Response中提取数据。在使用时先通过xpath或者css选择器选中页面中要提取的数据,再进行提取。  xpath(query): 使用xpath选择器在Response中提取数据。  css(query): 使用css选择器在Response中提取数据。  urljoin(url): 用于构造绝对url。 (2) HtmlResponse子类和XmlResponse子类。HtmlResponse和XmlResponse两个类本身只是简单地继承了TextResponse,因此它们是TextResponse的子类。用户通常爬取的网页,其内容大多是HTML文本,创建的就是HtmlResponse类。HtmlResponse类有很多方法,但是最常见的是xpath(query)、css(query)和urljoin(url)。其中前两个方法用于提取数据,后一个方法用于构造绝对url。 3.2.3Select对象 1. Select对象简介 分析Response对象的代码,如下所示。 def selector(self): from scrapy.selector import Selector if self._cached_selector is None: self._cached_selector = Selector(self) return self._cached_selector def xpath(self, query, **kwargs): return self.selector.xpath(query, **kwargs) 从上面的源码可以看出,Scrapy的数组组织结构是Selector,它使用xpath选择器在Response中提取数据。 从页面中提取数据的核心技术是HTTP文本解析,在Python中常用的处理模块如下。  BeautifulSoup: 一个非常流行的解析库,API简单,但解析的速度慢。  lxml: 一个使用C语言编写的xml解析库,解析速度快,API相对比较复杂。 Scrapy中的Selector对象是基于lxml库建立的,并且简化了API接口,使用方便。 2. Select对象的用法 在使用Selector对象的时候要先使用xpath或者css选择器选中页面中要提取的数据,然后进行提取。 1) 创建对象 在Python中创建对象有以下两种方式。 (1) 将页面html文档字符串传递给Selector构造器方法的text参数。例如: >>> from scrapy.selector import Selector >>> text = """

hello world

hello scrapy

hello python """ >>> selector = Selector(text = text) >>> selector (2) 使用一个Response对象构造Selector对象。例如: >>> from scrapy.selector import Selector >>> from scrapy.http import HtmlResponse >>> text = """

hello world

hello scrapy

hello python """ >>> response = HtmlResponse(url = "http://www.example.com",body = text,encoding = "utf8") >>> selector = Selector(response = response) >>> selector 在实际开发中,一般不需要手动创建Selector对象,在第一次访问一个Response对象的Selector属性时,Response对象内部会以自身为参数自动创建Selector对象,并将Selector对象缓存,以便下次使用。 2) 选中数据 在Scrapy中使用选择器是基于Selector这个对象的,Selector对象在Scrapy中是通过xpath或css来提取数据的。例如: selector_list = selector.xpath('//h1')#选取文档中所有的h1 selector_list #其中包含两个

对应的selector对象 ] [] SelectorList对象也有xpath和css方法,调用它们的方法为: 以接收到的参数分别调用其中一个Selector对象的xpath css,将所有搜集到的一个新的SlectorList对象返回给用户,例如: selector_list.xpath('./text()') selector.xpath('.//path').css('li').xpath('./text()') [] [] [] 在具体实现中,Scrapy使用css和xpath选择器来定位元素,它的基本方法如下。  xpath(): 返回选择器列表,每个选择器代表使用xpath语法选择的节点。  css(): 返回选择器列表,每个选择器代表使用css语法选择的节点。 (1) xpath。xpath是XML路径语言,它是一种用来确定XML文档中某部分位置的语言。表31列举了常见的xpath路径表达式。 表31xpath路径表达式 表达式描述 nodename选取次节点的所有子节点 /从根节点选取 //从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 .选取当前节点 ..选取当前节点的父节点 @选取属性 此外,在xpath中可以使用谓语来查找某个特定的节点或者包含某个指定值的节点,谓语被嵌在方括号中。可以对任意节点使用谓语,并输出结果。表32给出了常见的谓语表达式及输出结果。 表32常见谓语表达式 表达式输 出 结 果 / students/student[1]选取属于students元素的第1个student元素 / students/student[last()]选取属于students元素的最后1个student元素 / students/student[last()-1]选取属于students元素的倒数第2个student元素 / students/student[position()<2]选取最前面的1个属于students元素的student元素 // student[@id]选取所有拥有名为id的属性的student元素 // student[@id='00111']选取所有student元素,且这些元素拥有值为00111的id属性 例如: response.xpath('/html/body/div') #选取body下的所有div response.xpath('//a') #选中文档中的所有a response.xpath('/html/body//div') #选中body下的所有节点中的div,无论在什么位置 response.xpath('//a/text()') #选取所有a的文本 response.xpath('/html/div/*') #选取div的所有元素子节点 (2) css。css即层叠样式表,它的语法简单,功能不如xpath强大。当调用Selector对象的css方法时,内部Python库cssSelect将css转化为xpath再执行操作。表33列举了css的一些基本语法。 表33css基本语法 表达式描述 *选取所有元素 E选取E元素 E1,E2选取E1,E2元素 E1 E2选取E1后代元素中的E2元素 E1>E2选取E1子元素中的E2元素 E1+E2选取兄弟中的E2元素 .container选取class属性为container的元素 # container选取id属性为container的元素 [attr]选取包含attr属性的元素 [attr=value]选取包含attr属性且值为value的元素 E:nth(last)child(n)选取E元素,且该元素必须是其父元素的第n个元素 E:empty选取没有子元素的E元素 E::text选取E元素的文本节点(text node) 例如: response.css('div a::text').extract()#所有div下的所有a的文本 response.css('div a::attr(href)').extract() #href的值 response.css('div>a:nth-child(1)')#选中每个div的第一个a节点,会设定 #只在子节点中找,不会到孙节点中 response.css('div:not(#container)') #选取所有id不是container的div response.css('div:first-child>a:last-child') #第一个div中最后一个a 3.2.4Spider开发流程 对于大多数用户来讲,Spider是Scrapy框架中最核心的组件,Scrapy爬虫开发时通常是紧紧围绕Spider而展开的。一般而言,实现一个Spider需要以下几步。 (1) 继承scrapy.Spider。 (2) 为Spider命名。 (3) 设置爬虫的起始爬取点。 (4) 实现页面的解析。 1. 继承scrapy.Spider Scrapy框架提供了一个Spider基类,编写的Spider都需要继承它,代码如下。 import scrapy class MeijuSpider(scrapy.Spider) scrapy.Spider这个基类实现了以下功能。 (1) 提供了Scrapy引擎调用的接口。 (2) 提供了用户使用的工具函数。 (3) 提供了用户访问的属性。 2. 为Spider命名 name: 在Spider中使用属性name来为爬虫命名。该名称在项目中必须是独一无二的,不能和其他的爬虫有相同的名称。一般做法是以该网站(domain)来命名Spider。例如,如果Spider爬取mywebsite.com,该Spider通常会被命名为mywebsite。如果没有给爬虫命名,爬虫会在初始化爬虫的时候抛出ValueError。 3. 设置起始爬取点 start_urls: 定义Spider开始爬取数据的URL列表,随后生成的其他需要爬取的URL都是从这些URL对应的页面中提取数据生成出来的。例如: start_urls = ['http://www.meijutt.com/new100.html'] 实际上,对于起始爬取点的下载请求是由Scrapy引擎调用Spider对象的start_requests()提交的。这个方法必须返回该Spider的可迭代的初始requests对象供后续爬取。Scrapy会在该Spider开始爬取数据时被调用,且只会被调用一次,因此可以很安全地将start_requests()作为一个生成器来执行。默认的执行会生成每一个在start_urls中的URL对应的Request对象。 4. 实现页面的解析 parse(): parse方法是Scrapy默认的解析函数,用于回调处理下载的response,并且当response没有指定回调函数时,该方法是Scrapy处理response的默认方法。 parse方法比较简单,只是对response调用_parse_response方法,并设置callback为parse_start_url,follow=True(表明跟进链接)。如果设置了callback,也就是parse_start_url,会优先调用callback处理,然后调用process_results方法来生成返回列表。例如: def parse(self, response): return self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True) Spider中常见属性和方法如表34所示。 表34Spider中常见属性和方法 Spider中常见属性含义 name定义Spider名称的字符串 allowed_domains包含了Spider允许爬取的域名(domain)的列表,可选 start_urls初始URL元祖/列表。当没有制定特定的URL时,Spider将从该列表中开始进行爬取 custom_settings定义该Spider配置的字典,这个配置会在项目范围内运行这个spider的时候生效 crawler定义Spider实例绑定的crawler对象,这个属性是在初始化Spider类时由from_crawler()方法设置的,crawler对象概括了许多项目的组件 settings运行Spider的配置,这是一个settings对象的实例 logger用Spider名称创建的Python记录器,可以用来发送日志消息 start_requests(self)该方法包含了Spider用于爬取(默认实现是使用start_urls的URL)的第一个Request parse(self, response)当请求URL返回网页没有指定回调函数时,默认的Request对象回调函数,用来处理网页返回的response,以及生成Item或者Request对象 视频讲解 3.3Scrapy的开发与实现 3.3.1Scrapy爬虫开发流程 要开发Scrapy爬虫,一般有以下几步。 (1) 新建项目。 (2) 确定抓取网页目标。 (3) 制作爬虫。 (4) 设计管道储存爬取内容。 Scrapy爬虫实现步骤如图35所示。 图35Scrapy爬虫实现步骤 3.3.2创建Scrapy项目并查看结构 1. Scrapy常用命令介绍 (1) startproject。 startproject命令表示创建一个新工程,所有的爬虫程序都需要先创建新工程,语法为: scrapy startproject 其中语句name表示创建工程的名称。 (2) genspider。 genspider命令表示在该工程下创建一个爬虫,语法为: scrapy genspider 其中语句name表示爬虫的名称,domain表示要爬取的网站的域名。 (3) settings。 settings命令表示获得爬虫配置信息,语法为: scrapy settings (4) crawl。 crawl表示运行已经创建好的爬虫,语法为: scrapy crawl 其中语句表示创建好的爬虫的名称。 (5) list。 list命令表示列出工程中的所有爬虫,语法为: scrapy list 2. 创建Scrapy项目 【例31】创建一个最简单的Spider爬虫。 该实例以爬取美剧天堂前100最新网站(http://www.meijubar.net/)为例,讲述Scrapy爬虫的创建和运行。 1) 创建工程 在本地选中某一文件夹,同时按住Shift键右击,在弹出的快捷菜单中选择“在此处打开命令窗口”命令,输入命令: scrapy startproject movie 创建Scrapy工程,运行如图36所示。 图36创建Scrapy工程 2) 创建爬虫程序 在创建好Scrapy工程以后,下一步就是创建爬虫程序。输入命令: scrapy genspider meiju meijutt.com 该命令创建Spider爬虫,并命名为meiju,运行如图37所示。 图37创建Spider爬虫 3. 查看并认识爬虫目录结构 图38目录结构 使用tree命令查看目录结构,如图38所示。 目录结构的含义如下。  scrapy.cfg: 部署Scrapy爬虫的配置文件。  movie/: 外层目录。  items.py: Items代码模板(继承类)。  middlewares.py: middlewares代码模板(继承类)。  pipelines.py: Pipelines代码模板(继承类)。  settings.py: Scrapy爬虫的配置文件。  settings.pyc: Scrapy爬虫的配置文件,由Python生成,同settings.py。  __init__.py: 初始文件,无须修改。  __init__.pyc: 初始化脚本, 由Python生成,同__init__.py。  spiders/: Spiders代码模板目录(继承类)。  meiju.py: Scrapy爬虫的主程序。  __init__.py: 初始化脚本。  __init__.pyc: 初始化脚本, 同__init__.py。 创建好以后,可在文件夹中看到以下目录,如图39~图311所示。 图39根目录结构 图310movie目录结构 图311spiders目录结构 3.3.3编写代码并运行爬虫 1. 设置Spider爬虫 运行Python,在meiju.py中输入以下代码。 import scrapy from movie.items import MovieItem class MeijuSpider(scrapy.Spider): name = "meiju" allowed_domains = ["meijutt.com"] start_urls = ['http://www.meijutt.com/new100.html'] def parse(self, response): movies = response.xpath('//ul[@class="top-list fn-clear"]/li') for each_movie in movies: item = MovieItem() item['name'] =each_movie.xpath('./h5/a/@title').extract()[0] yield item 2. 设置item模板 在items.py中输入以下代码。 import scrapy class MovieItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() name = scrapy.Field() 3. 设置配置文件 在settings.py中增加如下代码。 ITEM_PIPELINES = {'movie.pipelines.MoviePipeline':100} 4. 设置数据处理脚本 在pipelines.py中输入如下代码。 图312运行爬虫结果 class MoviePipeline(object): def process_item(self, item, spider): with open("my_meiju.txt",'a') as fp: fp.write(item['name'].encode("utf8") + '\n') 5. 运行爬虫 在爬虫根目录中执行以下命令。 scrapy crawl meiju 其中meiju表示该爬虫Spider的名称,运行结果如图312所示。 从图312可以看出,该实例显示了美剧的最新目录。 3.4本章小结 (1) Scrapy是一个使用Python语言编写的开源网络爬虫框架,是一个高级的Python爬虫框架。Scrapy可用于各种有用的应用程序,如数据挖掘、信息处理及历史归档等,目前主要用于抓取Web站点并从页面中提取结构化的数据。 (2) Scrapy框架由Scrapy Engine、Scheduler、Downloader、Spiders、Item Pipeline、Downloader middlewares以及Spider middlewares等几部分组成。 (3) Scrapy中的Request对象和Response对象通常用于爬取网站,Request对象在爬虫程序中生成并传递到系统,直到它们到达下载程序,后者执行请求并返回一个Response对象,该对象返回到发出请求的爬虫程序。 (4) Spider是Scrapy框架中最核心的组件,Scrapy爬虫开发时通常是紧紧围绕Spider而展开的。 (5) 要开发Scrapy爬虫,一般步骤为: 新建项目、确定抓取网页目标、制作爬虫、设计管道存储爬取内容等。 3.5实训 1. 实训目的 通过本章实训了解Scrapy爬虫框架的特点,能使用Scrapy框架进行简单的网站数据爬取。 2. 实训内容 使用Scrapy框架编写爬虫访问网站。 (1) 访问专门的爬虫网站http://quotes.toscrape.com,该网站有多个页面,如http://quotes.toscrape.com/page/2/、http://quotes.toscrape.com/page/3等,首页页面如图313所示。 图313爬虫网站 (2) 爬取该页面中的每一个子区域对应的文本内容、作者和分类,如图314所示。 图314爬取网站相应内容 (3) 新建爬虫工程,并命名为quotesbotmaster,并在此工程中创建Spider爬虫,命令为toscrapexpath。 (4) 打开toscrapexpath.py,输入以下代码。 import scrapy class ToScrapeSpiderXPath(scrapy.Spider): name = 'toscrape-xpath' start_urls = [ 'http://quotes.toscrape.com/', ] def parse(self, response): for quote in response.xpath('//div[@class="quote"]'): yield { 'text': quote.xpath('./span[@class="text"]/text()').extract_first(), 'author': quote.xpath('.//small[@class="author"]/text()').extract_first(), 'tags': quote.xpath('.//div[@class="tags"]/a[@class="tag"]/text()').extract() } next_page_url = response.xpath('//li[@class="next"]/a/@href').extract_first() if next_page_url is not None: yield scrapy.Request(response.urljoin(next_page_url)) 其中,语句'text': quote.xpath('./span[@class="text"]/text()').extract_first()表示爬取页面子区域的文本内容,语句'author': quote.xpath('.//small[@class="author"]/text()').extract_first()表示爬取页面子区域的作者,语句'tags': quote.xpath('.//div[@class="tags"]/a[@class="tag"]/text()').extract()表示爬取页面子区域的分类。 语句next_page_url = response.xpath('//li[@class="next"]/a/@href').extract_first()表示依次爬取该网站的下一页。 (5) 在pipelines.py中输入以下代码。 class QuotesbotPipeline(object): def process_item(self, item, spider): return item (6) 在settings.py中输入以下代码。 BOT_NAME = 'quotesbot' SPIDER_MODULES = ['quotesbot.spiders'] NEWSPIDER_MODULE = 'quotesbot.spiders' (7) 在items.py中输入以下代码。 import scrapy class QuotesbotItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() pass (8) 运行该爬虫,在爬虫根目录中执行命令scrapy crawl toscrapexpath,可以得到爬取结果,如图315和图316所示。 图315运行该爬虫 图316爬虫的页面内容 (9) 查看爬取的每一个具体内容,如图317所示。 图317爬虫的页面具体内容 习题 1. 请阐述什么是Scrapy框架。 2. 如何安装Scrapy框架? 3. Scrapy框架有哪些特点? 4. Scrapy框架的组成部分是什么? 5. Scrapy框架的工作原理是什么? 6. 如何使用Scrapy框架来爬取页面?