内容导读
- Scrapy框架简介
- 通过Scrapy爬取文本信息
- 定制下载器中间件
一、Scrapy框架简介
Scrapy是一个为了爬取网站数据,提取结构化数据而编写的应用程序框架,可以应用在包括数据挖掘、信息处理或存储历史数据等一系列功能的程序中。
该框架也可以应用在获取API(如Amazon Associates Web Services的API)所返回的数据或通用的网络爬虫中。
在使用Scrapy框架之前,需要先了解该框架的构成、常用命令。
使用Scrapy爬取某企业官网新闻动态。
1、了解Scrapy爬虫框架
Scrapy是一个爬虫框架而非功能函数库,简单地说,它是一个半品,可以帮助用户简单快速地部署一个专业的网络爬虫。
Scrapy爬虫框架主要由引擎(Engine)、调度器(Scheduler)、下载器(Downloader)、Spiders、Item Pipelines、下载器中间件(Downloader Middlewares)、Spider中间件(Spider Middlewares)这7个组件构成。
引擎:负责控制数据流在系统所有组件中的流向,并能在不同的条件下触发相对应的事件。引擎组件相当于爬虫的"大脑",是整个爬虫的调度中心。
调度器:从引擎接收请求并将该请求加入队列,以便之后引擎需要时将它们提供给引擎。初始爬取的URL和后续在网页中获取的待爬取URL都将被放入调度器中,等待爬取,同时调度器会自动去除重复的URL。如果特定的URL不需要去重,那么可以通过设置实现,如POST请求的URL。
下载器:主要功能是获取网页内容,并将其提供给引擎和Spiders。
Spiders:是Scrapy用户编写的用于分析响应,并提取Items或额外跟进的URL的一个类。每个Spider负责处理一个(或一些)特定网站。
Item Pipelines:主要功能是处理被Spiders提取出来的Items。典型的处理有清理、验证及持久化(如将Items存取到数据库中)。当网页中被爬虫解析的数据存入Items后,将被发送到Item Pipelines,经过几个特定的数据处理次序后,存入本地文件或数据库。
下载器中间件:是一组在引擎及下载器之间的特定钩子(Specific Hook),主要功能是处理下载器传递给引擎的响应(Response)。下载器中间件提供了一个简便的机制,可通过插入自定义代码来扩展Scrapy的功能。通过设置下载器中间件可以实现爬虫自动更换User-Agent、IP地址等功能。
Spider中间件:是一组在引擎及Spiders之间的特定钩子,主要功能是处理Spiders的输入(响应)和输出(Items及请求)。同时,Spider中间件提供了一个简便的机制,可通过插入自定义代码来扩展Scrapy的功能。
2、Scrapy框架中各组件之间的数据流向
数据流在Scrapy中由执行引擎控制,其基本步骤如下:
引擎打开一个网站,找到处理该网站的Spiders,并向该Spiders请求第一个要爬取的URL。
引擎将爬取请求(Requests)转发给调度器,调度器指挥进行下一步。
引擎从调度器获取下一个要爬取的请求。
调度器返回下一个要爬取的请求,通过下载器中间件(请求方向)将请求转发给下载器。
当网页下载完毕时,下载器会生成一个该网页的响应,并将其通过下载器中间件(响应方向)发送给引擎。
引擎从下载器中接收到响应并通过Spider中间件(输入方向)发送给Spiders处理。
Spiders处理响应并返回爬取到的Items及(跟进)新的请求给引擎。
引擎将爬取到的Items(Spiders返回的)给Item Pipelines,将请求(Spiders返回的)给调度器。
重复步骤(2)直至调度器中没有更多的URL请求,引擎关闭该网站。
3、熟悉Scrapy常用命令
Scrapy通过命令行进行控制,Scrapy提供了多种命令,用于多种目的,并且每个命令都接收一组不同的参数和选项。
除了全局命令外,Scrapy还提供了专用于项目的项目命令。
在使用Scrapy爬虫框架的过程中,常用的命令主要是全局命令中的startproject、genspider、runspider,以及项目命令中的crawl、list。
二、通过Scrapy爬取文本信息
1、创建Scrapy爬虫项目
使用Scrapy框架进行网页数据爬取的第一步就是启动爬虫,使用Scrapy提供的startproject命令即可创建一个爬虫项目,其基本语法格式如下:
打开PyCharm,在"Terminal"(终端)运行"scrapy startproject TipDMSpider D:\项目7\code"命令,即可在目录"E:\mypython\code"下,创建一个名为"TipDMSpider"的Scrapy爬虫项目。
创建完成后,在"E:\mypython\code"下即可生成一个名为TipDMSpider的文件夹和scrapy.cfg文件。
需要用户自定义的目录与脚本文件的名称、作用如下表。
2、修改items/pipelines脚本
爬虫的主要目标是从网页非结构化的数据源中提取结构化的数据。
TipDMSpider项目最终的目标是解析出文章的标题(title)、时间(time)、正文(text)、浏览数(view_count)等数据。
Scrapy提供了Item对象来完成将解析数据转换为结构化数据的功能。
Item对象是一种简单的容器,用于保存爬取到的数据,它提供了类似于字典的API,以及用于声明可用字段的简单语法。
Item可使用简单定义语法及Field对象来声明。新建的TipDMSpider项目中的items脚本模板如下,用于定义存储数据的Item类,该类继承于scrapy.Item。
python
import scrapy
class TipdmspiderItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
pass
根据TipDMSpider项目的目标,对items脚本进行定制。TipdmspiderItem类如代码所示。
python
class TipdmspiderItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
title = scrapy.Field()
text = scrapy.Field()
time = scrapy.Field()
view_count = scrapy.Field()
Items将会流向Item Pipelines。Item Pipelines的作用是将获取到的数据持久化,其主要内容如下。
清理爬取到的数据。
验证爬取数据的合法性,检查Items是否包含某些字段。
保存数据至文件或数据库中。
值得注意的是,每个Item Pipelines都是一个独立的Python类,必须实现process_item()方法。每个Item Pipelines组件都需要调用process_item()方法,该方法必须返回一个Item对象,或抛出DropItem异常,被丢弃的Item将不会被之后的Pipelines组件所处理。
在新建的TipDMSpider项目中,自动生成的Item pipelines脚本模板如下。
python
from itemadapter import ItemAdapter
class TipdmspiderPipeline:
def process_item(self, item, spider):
return item
在pipelines脚本模板的process_item()方法中,除"self"参数外,还存在item和spider这两个参数,根据TipDMSpider项目的目标,对items脚本进行定制。
TipDMSpider项目提取的信息最终将存储至CSV文件或数据库中。使用pandas库将Items中的数据转换为DataFrame结构会更方便处理。
pandas库的DataFrame类的基本语法格式如下:
Items中的数据转换为DataFrame结构后即可使用to_csv()方法轻松地将数据存储至CSV文件中。to_csv()方法的基本语法格式如下:
还可以使用to_sql()方法将数据存储至数据库中。
需要注意的是,对数据库进行操作需要使用数据连接相关的工具,在项目3中已经介绍了使用PyMySQL库操作数据库,但to_sql()方法需要配合sqlalchemy库中的create_engine函数才能顺利使用。
create_engine函数可用于创建一个数据库连接,其主要参数是一个连接字符串,MySQL和Oracle数据库的连接字符串的格式如下。
数据库产品名+连接工具名://用户名:密码@数据库IP地址:数据库端口号/数据库名称?charset = 数据库数据编码
配合pandas库,修改pipelines脚本。
3、编写spider脚本
创建TipDMSpider项目后,爬虫模块的代码都放置于spiders目录中。创建之初,spiders目录下仅有一个"init.py"文件,并无其他文件,对于初学者而言极有可能无从下手。
使用genspider命令,可以解决这一问题,genspider命令的基本语法格式如下。
在PyCharm的"Terminal"中,使用"cd D:/项目7/code/TipDMSpider"命令进入Scrapy爬虫项目目录后,再运行"scrapy genspidertipdm www.tipdm.com"命令即可创建一个spider脚本模板。
spider脚本模板创建后,在spiders目录下会生成一个tipdm脚本模板。
在TipDMSpider项目目录下运行crawl命令即可启动爬虫,crawl命令的基本语法格式如下。
在PyCharm的"Terminal"中运行"scrapy crawl tipdm"命令。
在tipdm脚本中,parse()方法负责解析返回的数据并提取数据,以及生成需要进一步处理的URL的Reponse对象。
在此之前,需要根据爬取目标设计网页爬取的流程。本次爬取的目标是网站"http://www.tipdm.com"中的"新闻中心"页面中所有的信息。
在TipdmSpider类的parse()方法中,其中一个参数是response,对传入的响应直接使用XPath和CSS方法即可根据对应的规则解析网页。
要在TipDMSpider项目中使用XPath进行网页解析,首先需要分析摘要网页URL的规律。
通过规律能够较快获得所有的摘要网页的URL,从图所示的网页源代码可以看出,从第2页开始,网页的URL中发生改变的是index与html之间的网页编号,例如,第2页的网页URL后面部分是index_2.jhtml,第3页则是index_3.jhtml。
故获得总共的网页数目,即可知道所有摘要网页的网址。
获得"新闻中心"网页数目所在的节点信息的XPath为"//*[@id="t505"]/div[6]/div/a[6]/text()"
同时由于第1页网址与其他页网址规则不同,所以需要手动添加。
由于parse()方法默认响应start_urls中的网址,同时不同网页需要解析的内容不同,所以后续的解析需要通过调用其他方法来实现,代码中的最后一行使用了Scrapy中http包下的Request类用于回调。
Request类的基本语法格式如下:
Request类的回调方法的作用是获取所有文章网页网址,分析网页源代码可以获取所有文章网页网址的XPath,即"//*[@id="t505"]/div/div[3]/h1/a/@href"。
同时需要注意获取的网页网址并非一个完整的网址,还需要将每个网址补充完整。
TipDMSpider项目的最终目标是获取文章的标题、时间、正文、浏览数,在获取了文章的网址之后,对文章网页进行解析即可得到对应的内容。解析文章相关信息的XPath如下表所示。
如果正文存在分段的现象,那么在解析的过程中会将不同的段落放在同一个list中,为了保证存储方便,需要将list中的信息进行合并。
同时,需要将所有解析出来的信息均存放至item中。
ipDMSpider项目的spider脚本已基本编写完成,但需要注意,由于在parse()、parse_url()两个方法中调用了Request类,在parse_text()方法中调用了item,所以需要在创建的spider脚本最前端加入导入Request类和TipDMSpider项目构建的Item类的代码,完成添加后的spider脚本的所有导入函数与类的语句,如代码所示。
python
import scrapy
from scrapy.http import Request
from TipDMSpider.items import TipdmspiderItem
4、修改settings脚本
Scrapy设置允许自定义所有Scrapy组件,包括核心、扩展、管道和爬虫本身。
设置的基础结构可提供键值映射的全局命名空间,代码可以使用它,并从全局命名空间提取配置值。
用户可以通过不同的机制来填充设置,这些设置也是选择当前活动的Scrapy项目的机制之一。
在TipDMSpider项目的默认settings脚本中共有25个设置。
(续上表)
(续上表)
TipDMSpider项目中需要修改的设置分别为ROBOTSTXT_OBEY、DOWNLOAD_DELAY、ITEM_PIPELINES、HTTPCACHE_ENABLED、HTTPCACHE_DIR。
在PyCharm的"Terminal"中运行"scrapy crawl tipdm"命令运行项目。
三、定制下载器中间件
任务描述:
下载器中间件位于引擎和下载器之间。
引擎将未处理的请求发送给下载器的时候,会经过下载器中间件,这时在中间件里可以包装请求,如修改请求头信息(设置User-Agent、Cookie等)和添加代理IP地址。
当下载器将网站的响应发送给引擎时,也会经过下载器中间件,此时即可对响应内容进行处理。
任务分析:
编写下载器中间件脚本。
激活下载器中间件。
1、编写下载器中间件脚本
每个中间件组件都是一个Python类,下载器中间件定义了process_request()、process_response()、process_exception()中的一种或多种方法。
process_request()方法将会被所有通过下载器中间件的每一个请求调用,具有request和spider两个参数,参数说明如表所示。
process_request()方法的返回值有4种类型,每种返回值类型的说明如表所示。
下载器中间件常用于防止爬虫被网站的反爬虫规则所识别。通常绕过这些规则的常见方法如下。
动态设置User-Agent,随机切换User-Agent,模拟不同用户的浏览器信息。
禁用Cookie,也就是不启用CookiesMiddleware,不向服务器发送Cookie。有些网站通过Cookie的使用来发现爬虫行为,可以通过COOKIES_ENABLED控制CookiesMiddleware的开启和关闭。
设置延迟下载,防止访问过于频繁,设置延迟时间为2s或更高,可以通过DOWNLOAD_DELAY控制下载频率。
下载器中间件常用于防止爬虫被网站的反爬虫规则所识别。通常绕过这些规则的常见方法如下。
使用百度等搜索引擎服务器网页缓存获取的网页数据。
使用IP地址池,现在大部分网站都是根据IP地址来判断是否为同一访问者的。
使用Crawlera(专用于爬虫的代理组件),正确配置Crawlera和下载器中间件后,项目所有的请求都可通过Crawlera发出。
从实现难度上看,比较容易实现的方法是(1)、(2)、(3)、(5),其中,(2)与(3)通过修改settings脚本即可实现,另外两种则是使用process_request()方法随机选择访问网页的User-Agent与随机切换访问IP地址来实现的。
在TipDMSpider项目的middlewares脚本下创建下载器中间件,实现(1)、(5)两种方法。
除了定制下载器中间件外,在Scrapy框架中已经默认提供并开启了众多下载器中间件,在内置的下载器中间件中,DOWNLOADER_MIDDLEWARES_BASE设置的各中间件说明及其顺序如表所示。
(续上表)
激活下载器中间件组件,需要将其加入settings脚本下的DOWNLOADER_MIDDLEWARES设置中。
这个设置是一个字典(dict),键为中间件类的路径,值为其中间件的顺序(order),同时会根据顺序值进行排序,最后得到启用中间件的有序列表,即第一个中间件最靠近引擎,最后一个中间件最靠近下载器。
激活TipDMSpider项目中middlewares目录下创建的下载器中间件。
在settings脚本中,对DOWNLOADER_MIDDLEWARES设置进行修改后,会与Scrapy内置的下载器中间件设置DOWNLOADER_MIDDLEWARES_BASE合并,但并不会覆盖。
若要取消Scrapy默认在DOWNLOADER_MIDDLEWARES_BASE中打开的下载器中间件,可在DOWNLOADER_MIDDLEWARES中将该中间件的值设置为0。
如果需要关闭RobotsTxtMiddleware,那么需要在DOWNLOADER_MIDDLEWARES设置中将该中间件的值设置为0。
2、定制Spider中间件
在Scrapy中自带Spider中间件,通过激活Spider中间件可以获取到Item,即爬取数据的封装结构。
Spider中间件位于Spiders(程序)和引擎之间,在Item即将达到Item Pipeline之前,对Item和响应进行处理。
Spider中间件是介入Scrapy中的Spiders处理机制的钩子框架,可以在其中插入自定义功能来处理发送给Spiders的响应,以及Spiders产生的Items和请求。
Spider中间件定义了process_spider_input()、process_spider_output()、process_spider_exception()、process_start_requests()中的一种或多种方法。
根据Spider中间件的功能不同,需要用到的方法也不同,很多时候,Scrapy默认提供并开启的Spider中间件就已经能够满足多数需求。
在内置的Spider中间件中,SPIDER_MIDDLEWARES_BASE设置的中间件说明及其顺序如表所示。
激活Spider中间件组件的方法与激活下载器中间件的方法基本相同,需要将定制的Spider中间件加入settings脚本下的SPIDER_MIDDLEWARES设置中。
这个设置同样是一个字典,键为中间件类的路径,值为其中间件的顺序,同时会根据顺序值进行排序,最后得到启用中间件的有序列表,即第一个中间件最靠近引擎,最后一个中间件最靠近Spiders。
另外,针对Spider中间件,Scrapy同样内置了中间件设置SPIDER_MIDDLEWARES_ BASE,该设置也不能覆盖,在启用时会结合SPIDER_MIDDLEWARES设置。
若要取消Scrapy默认在SPIDER_MIDDLEWARES_BASE中打开的Spider中间件,同样需要在SPIDER_MIDDLEWARES设置中将中间件的值设置为0,如代码所示。
python
SPIDER_MIDDLEWARES = {
'scrapy.spidermiddlewares.referer.RefererMiddleware': 0,
}
更多精彩内容请关注本站!