007:Scrapy核心架构和高级运用
本篇内容:
Scrapy核心架构和其组件的功能
Scrapy的工作流
Scrapy的中文输出储存
介绍CrawSpider
编写了一个爬虫实战来进行我们的mysql数据库操作
Scrapy的核心架构
如下图所示:
主要组件包括了Scrapy引擎,调度器,管道,下载中间件,下载器,spider蜘蛛,爬虫中间件,实体管道(Item Pipeline)等。
1、Scrapy引擎:
scrapy引擎是整个scrapy架构的核心,负责控制整个数据处理流程,以及一些事物吃力。scrapy引擎与调度器、实体管道、中间件、下载器等组件都有关系,其出入整个框架的中心位置,对各项组件进行控制及协调。
2、调度器:
调度器主要实现储存待爬取的网址,并确定这些网址的优先级,决定下一次爬取哪个网址等。调度器会从引擎中接收request请求并存入优先队列中。
3、下载器:
下载器主要实现对网络上要爬取的网页资源进行高速下载,由于该组件需要通过网络进行大量数据的传输,所以该组件的压力负担也会比其他的多。下载器下载了对应的网页资源后,也会将这些数据传递给Scrapy引擎,再由Scrapy引擎传递给对应的爬虫进行处理。
4、下载中间件:
下载中间件是处于下载器和引擎之间的一个特定的组件。是用于全局修改Scrapy request和response的一个轻量、底层的系统。
5、蜘蛛spider:
spider是定义如何抓取某个网站(或一组网站)的类,包括如何执行抓取(即关注链接)以及如何从其网页中提取结构化数据(即抓取项目)。换句话说,Spider是您定义用于为特定网站(或在某些情况下,一组网站)抓取和解析网页的自定义行为的位置。
6、爬虫中间件:
爬虫中间件是处于Scrapy引擎与爬虫组件之间的一个特定的组件,主要用于对爬虫组件和Scrapy引擎之间的通信进行处理。同时,在爬虫中间件中可以加入一些自定义代码,很轻松的实现Scrapy功能的扩展。
7、实体管道:
实体管道主要用于接收从蜘蛛组件中提取出来的项目。接收后,会对这些item进行对应的处理。常见的处理主要由:清洗、验证、储存到数据库中。
Scrapy工作流
我们已经知道了Scrapy框架中主要由哪些组件,以及各项组件的具体作用有什么呢,各项数据在组件中又是怎么进行的呢。
1、将网址传递给scrapy引擎。
2、scrapy引擎将网址传给下载中间件
3、下载中间键将网址给下载器
4、下载器像网址发送request请求进行下载
5、网址接收请求,将响应返回给下载器
6、下载器将收到的响应返回给下载中间件
7、下载中间件与scrapy引擎通信
8、scrapy将response响应信息传递给爬虫中间件
9、爬虫中间件将响应传递给对应的爬虫进行处理
10、爬虫处理之后,会提取出来的数据和新的请求信息,将处理的信息传递给爬虫中间件
11、爬虫中间件将处理后的信息传递给Scrapy引擎
12、scrapy接收到信息之后,会将项目实体传递给实体管道进行进一步处理,同时将新的信息传递给调度器。
13、随后再重复执行1-12步,一直到调度器中没有网址或异常退出为止。
以上就是Scrapy框架中各项组件的工作流程。此时相信我们队Scrapu框架数据处理的过程就又了比较详细的了解。
Scrapy中文输出与中文存储
使用Scrapy抓取中文时,输出一般是unicode,要输出中文也只需要稍作改动。
单纯交互输出
如代码:
title = sel.xpath('a/text()').extract()
print title
此时输出的是title对应中文的unicode格式,只需要指定“utf-8”编码即可输出中文,如下:
title = sel.xpath('a/text()').extract()
for t in title:print t.encode('utf-8')
这里需要注意的是“encode()”函数是字符串专有的,而title是一个列表,因此需要对title中的每一个执行该操作。
存储
存储中文数据可以利用pipeline实现
1.定义pipeline
#coding: utf-8
import codecs
import jsonclass TutorialPipeline(object):def __init__(self):self.file = codecs.open('data_cn.json', 'wb', encoding='utf-8')def process_item(self, item, spider):line = json.dumps(dict(item)) + '\n'self.file.write(line.decode("unicode_escape"))return item
上述方法将得到的item解码,以便正常显示中文,并保存到定义的json文件中。
2.注册自定义的pipeline
为了启动pipeline,必须将其加入到“ITEM_PIPLINES”的配置中,在settings.py中加入下面一句:
ITEM_PIPELINES = {'tutorial.pipelines.TutorialPipeline':300 }
其中根目录是tutorial,pipelines是我的pipeline文件名,TutorialPipeline是类名
CrawlSpider详解:
在Scrapy基础——Spider中,我简要地说了一下Spider类。Spider基本上能做很多事情了,但是如果你想爬取知乎或者是简书全站的话,你可能需要一个更强大的武器。
CrawlSpider基于Spider,但是可以说是为全站爬取而生。
简要说明:
CrawlSpider是爬取那些具有一定规则网站的常用的爬虫,它基于Spider并有一些独特属性rules:
是Rule对象的集合,用于匹配目标网站并排除干扰parse_start_url: 用于爬取起始响应,必须要返回Item,Request中的一个。
因为rules是Rule对象的集合,所以这里也要介绍一下Rule。它有几个参数:link_extractor、callback=None、cb_kwargs=None、follow=None、process_links=None、process_request=None
其中的link_extractor既可以自己定义,也可以使用已有LinkExtractor类,主要参数为:
allow:满足括号中“正则表达式”的值会被提取,如果为空,则全部匹配。
deny:与这个正则表达式(或正则表达式列表)不匹配的URL一定不提取。
allow_domains:会被提取的链接的domains。
deny_domains:一定不会被提取链接的domains。
restrict_xpaths:使用xpath表达式,和allow共同作用过滤链接。还有一个类似的restrict_css
问题:CrawlSpider如何工作的?
因为CrawlSpider继承了Spider,所以具有Spider的所有函数。
首先由start_requests对start_urls中的每一个url发起请求,这个请求会被parse接收。
在Spider里面的parse需要我们定义,但CrawlSpider定义parse去解析响应。
根据有无callback,follow和self.follow_links执行不同的操作
def _parse_response(self, response, callback, cb_kwargs, follow=True): ##如果传入了callback,使用这个callback解析页面并获取解析得到的reques或itemif callback:cb_res = callback(response, **cb_kwargs) or ()cb_res = self.process_results(response, cb_res) for requests_or_item in iterate_spider_output(cb_res): yield requests_or_item ## 其次判断有无follow,用_requests_to_follow解析响应是否有符合要求的link。if follow and self._follow_links:for request_or_item in self._requests_to_follow(response): yield request_or_item
爬取豆瓣电影前250信息:
为了讲解后面的操作数据到数据库,这里插入scrapy框架爬取豆瓣网站信息。
首先创建项目,cmd输入命令
scrapy startproject doubanmovie
在spiders文件夹下创建文件MySpider.py。
在MySpider.py中创建类DoubanMovie继承自scrapy.Spider,同时定义以下属性和方法
name : 爬虫的唯一标识符
start_urls : 初始爬取的url列表
parse() : 每个初始url访问后生成的Response对象作为唯一参数传给该方法,该方法解析返回的Response,提取数据,生成item,同时生成进一步要处理的url的request对象
在settings文件中添加下面一行:
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0'
在doubanmovie文件夹下创建文件MovieItems.py,在该文件下编写存放爬取到的数据的容器
创建类MovieItem继承自scrapy.Item,定义各种属性,语句类似以下
name = scrapy.Field()
整个parse()方法代码如下
def parse(self, response):selector = scrapy.Selector(response)# 解析出各个电影movies = selector.xpath('//div[@class="item"]')# 存放电影信息item = MovieItem()for movie in movies:# 电影各种语言名字的列表titles = movie.xpath('.//span[@class="title"]/text()').extract()# 将中文名与英文名合成一个字符串name = ''for title in titles:name += title.strip()item['name'] = name# 电影信息列表infos = movie.xpath('.//div[@class="bd"]/p/text()').extract()# 电影信息合成一个字符串fullInfo = ''for info in infos:fullInfo += info.strip()item['info'] = fullInfo# 提取评分信息item['rating'] = movie.xpath('.//span[@class="rating_num"]/text()').extract()[0].strip()# 提取评价人数item['num'] = movie.xpath('.//div[@class="star"]/span[last()]/text()').extract()[0].strip()[:-3]# 提取经典语句,quote可能为空quote = movie.xpath('.//span[@class="inq"]/text()').extract()if quote:quote = quote[0].strip()item['quote'] = quote# 提取电影图片item['img_url'] = movie.xpath('.//img/@src').extract()[0]yield itemnext_page = selector.xpath('//span[@class="next"]/a/@href').extract()[0]url = 'https://movie.douban.com/top250' + next_pageif next_page:yield scrapy.Request(url, callback=self.parse)
数据存储:
目前选择将数据存放在json文件中,对数据库的处理在下面会讲解
在doubanmovie文件夹下创建文件MoviePipelines.py,编写类MoviePipeline,重写方法process_item(self, item, spider)用于处理数据。
import scrapy
from scrapy.contrib.pipeline.images import ImagesPipeline
from scrapy.exceptions import DropItem
class ImagePipeline(ImagesPipeline):def get_media_requests(self, item, info):yield scrapy.Request(item['image_url'])def item_completed(self, results, item, info):image_url = [x['path'] for ok, x in results if ok]if not image_url:raise DropItem("Item contains no images")item['image_url'] = image_urlreturn item
同时在settings文件中注册并设置下载目录:
ITEM_PIPELINES = {'doubanmovie.MoviePipelines.MoviePipeline': 1,'doubanmovie.ImgPipelines.ImgPipeline': 100,
}
在settings文件中将ROBOTSTXT_OBEY改为False,让scrapy不遵守robot协议,即可正常下载图片
IMAGES_STORE = 'E:\\img\\'
scrapy数据存入mysql数据库:
将爬取的各种信息通过json存在文件中,不过对数据的进一步使用显然放在数据库中更加方便,这里将数据存入mysql数据库以便以后利用。
首先在项目settings文件中添加与数据库连接相关的变量
MYSQL_HOST = 'localhost'
MYSQL_DBNAME = 'zzz'
MYSQL_USER = 'root'
MYSQL_PASSWD = '111'
创建数据库和表
class MovieItem(scrapy.Item):# 电影名字name = scrapy.Field()# 电影信息info = scrapy.Field()# 评分rating = scrapy.Field()# 评论人数num = scrapy.Field()# 经典语句quote = scrapy.Field()# 电影图片img_url = scrapy.Field()
据此创建数据库表,创建数据库的时候加上DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci,以防出现乱码
create database douban DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
use douban;
CREATE TABLE doubanmovie (name VARCHAR(100) NOT NULL, # 电影名字info VARCHAR(150), # 电影信息rating VARCHAR(10), # 评分num VARCHAR(10), # 评论人数quote VARCHAR(100), # 经典语句img_url VARCHAR(100), # 电影图片
)
在MoviePipelines.py文件中创建类DBPipeline,在其中进行对数据库的操作。
首先连接数据库,获取cursor以便之后对数据就行增删查改
def __init__(self):# 连接数据库self.connect = pymysql.connect(host=settings.MYSQL_HOST,db=settings.MYSQL_DBNAME,user=settings.MYSQL_USER,passwd=settings.MYSQL_PASSWD,charset='utf8',use_unicode=True)# 通过cursor执行增删查改self.cursor = self.connect.cursor();
注意这里charset属性为 ‘utf8’,中间没有-,在调试过程中因为这个-搞了半天
之后重载方法process_item(self, item, spider),在其中执行数据的增删查改,通过cursor编写sql语句,然后使用self.connect.commit()提交sql语句
def process_item(self, item, spider):try:# 插入数据self.cursor.execute("""insert into doubanmovie(name, info, rating, num ,quote, img_url)value (%s, %s, %s, %s, %s, %s)""",(item['name'],item['info'],item['rating'],item['num'],item['quote'],item['img_url']))# 提交sql语句self.connect.commit()except Exception as error:# 出现错误时打印错误日志log(error)return item
最后在settings文件中注册DBPipeline
ITEM_PIPELINES = {'doubanmovie.MoviePipelines.MoviePipeline': 1,'doubanmovie.ImgPipelines.ImgPipeline': 100,'doubanmovie.MoviePipelines.DBPipeline': 10,
}
可以尝试运行了。
然而爬取的数据是250条,在数据库存储中只有239条
查看MySpider.py文件
quote = movie.xpath('.//span[@class="inq"]/text()').extract()
if quote:quote = quote[0].strip()
item['quote'] = quote
如果网页中quote属性不存在,那么将item插入数据库时就会出错,增加一条else语句
if quote:quote = quote[0].strip()
else:quote = ' '
item['quote'] = quote
本篇到此为止了。本篇内容讲解了Scrapy核心架构和其组件的功能,Scrapy的工作量。以及Scrapy的中文输出储存,介绍了CrawSpider。并编写了一个爬虫实战来进行我们的mysql数据库操作。
理论上差不多可以了,后面的内容将会讲解各种实战项目,希望大家多多关注。
007:Scrapy核心架构和高级运用相关推荐
- 英伟达十年力作:新一代光线追踪显卡 Quadro RTX及核心架构Turing,可支持AI运算...
作者 | 琥珀 出品 | AI科技大本营(公众号ID:rgznai100) 北京时间 8 月 14 日清晨,英伟达(NVIDIA)CEO 黄仁勋准时出席在温哥华举办的 SIGGRAPH 2018 计算 ...
- Hadoop核心架构(1)
在大数据的发展过程中,出现了一批专门应用与大数据的处理分析工具,如Hadoop,Hbase,Hive,Spark等,我们先从最基础的Hadoop开始进行介绍 Hadoop是apache基金会下所开发的 ...
- 负载均衡10年发展,应用交付成核心架构
负载均衡10年发展,应用交付成核心架构 编者按:十年前,很少有人知道网络负载均衡,十年后,网络负载均衡已经成为网络应用的重要设备,特别是大型网络应用的核心设备.如今,负载均衡设备市场甚至并驾与基础路由 ...
- 【Unity学习笔记】b站Unity架构课Unity3D 商业化的网络游戏架构(高级/主程级别)
[Unity学习笔记]b站Unity架构课Unity3D 商业化的网络游戏架构(高级/主程级别) 自己跟着学完了,写了不少代码,会放在CSDN代码库,因为老师并没有提供源码,录屏也不是完全连续,所以难 ...
- 3D引擎架构设计高级篇
3D引擎架构设计最核心的技术包括:引擎框架设计,引擎内存管理,大场景加载以及卸载,引擎的渲染,模型骨骼插件:其他的模块还有粒子,AI,行为树,UI等等吧. 市场上对于引擎开发的需求也是比较大的,而且薪 ...
- Scrapy 框架架构
Scrapy 框架架构 目录 Scrapy 框架架构 前言 一.核心组成 二.数据流 三.项目结构 总结 前言 Scrapy (/ˈskreɪpaɪ/) 是一个用于抓取网站和提取结构化数据的应用程序框 ...
- android核心架构Framework组件介绍
作为一个android开发者,核心架构是必须要了解的.只有了解每个核心层的作用,才能更深入的理解和学习.本篇主要讲解Java Framework层核心代码流程. 文章目录 一,Android系统架构 ...
- W75 - 999、云计算架构师高级认证
初学耗时:999h 注:CSDN手机端暂不支持章节内链跳转,但外链可用,更好体验还请上电脑端. 『 因为要去见那个不一般的人,所以我就不能是一般人.』 W99.阿里大学征服路 - W系列总纲 ...
- 哈罗python的学费多少-哈啰出行招聘Java、算法、大数据开发、安卓、iOS、运维架构专家/高级专家等...
简历请发hanlongjie05932@hellobike.com 资深IOS开发工程师 工作职责: 1.负责IOS平台应用产品的研发工作: 2.负责根据产品需求完成模块设计.编码.编码集成工作: 3 ...
最新文章
- 如何有条件地向React组件添加属性?
- 窗体皮肤ssk 跟背景图片冲突_夫西地酸+阿达帕林~我要好皮肤
- c++观察者模式observer
- 在局域网访问_局域网访问共享文件需要密码怎么办?取消访问密码的方法
- 【安富莱二代示波器教程】第8章 示波器设计—测量功能
- hive 导出json格式 文件_hive存储json格式文件
- 黑客攻防:关于工业网络安全的那些事
- 字段的某记录相同,但是时间不同,找到MySQL里面最新的数据
- JavaScript小效果的实现(笔记)
- Actor编程模型——Erlang/OTP
- 从原理到应用,一文带你了解小程序插件能力
- (转)基于Ajax的应用程序架构汇总
- [LeetCode]12. Integer to Roman
- Qt5中this application has requested the runtime to terminate it in an unusual way 无法运行问题的解决
- oracle日期如何比较,Oracle日期比较
- 【转载】金山词霸”屏幕取词技术揭密(讨论稿)
- 推荐 四种优秀的数据库设计工具
- 基于HFSS阵列天线设计
- 一天一看————以太网交换机的基本原理与配置!
- CSS反爬获取伪元素的值
热门文章
- [渝粤教育] 郑州工程技术学院 大学计算机基础 参考 资料
- 江苏转本计算机一级,江苏“专转本”新规:考生需获计算机一级及以上证书
- 如何利用朋友圈做好微信营销之路
- 2020-01-01T00:00:00.000000Z 日期格式转换
- GTX 295 VS C1060 矩阵乘法测试(cublas)
- 拓扑排序 by zyz on 2021/4/11
- Unity3d轻量渲染管线(LWRP)民间文档
- Flutter·变换·先旋转再平移与先平移再旋转
- Paul Graham:未来的互联网创业
- JavaWeb(华清远见)