前言
一般我们都会将数据爬取下来保存在临时文件或者控制台直接输出,但对于超大规模数据的快速读写,高并发场景的访问,用数据库管理无疑是不二之选。首先简单描述一下MySQL和MongoDB的区别:MySQL与MongoDB都是开源的常用数据库,MySQL是传统的关系型数据库,MongoDB则是非关系型数据库,也叫文档型数据库,是一种NoSQL的数据库。它们各有各的优点。我们所熟知的那些SQL语句就不适用于MongoDB了,因为SQL语句是关系型数据库的标准语言。
一、关系型数据库
关系模型就是指二维表格模型,因而一个关系型数据库就是由二维表及其之间的联系组成的一个数据组织。常见的有:Oracle、DB2、PostgreSQL、Microsoft SQL Server、Microsoft Access、MySQL、浪潮K-DB 等
MySQL:
1、在不同的引擎上有不同的存储方式。
2、查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高。
3、开源数据库的份额在不断增加,mysql的份额页在持续增长。
4、缺点就是在海量数据处理的时候效率会显著变慢。
二、非关系型数据库
非关系型数据库(nosql ),属于文档型数据库。文档的数据库:即可以存放xml、json、bson类型的数据。这些数据具备自述性,呈现分层的树状数据结构。数据结构由键值(key=>value)对组成。常见的有:NoSql、Cloudant、MongoDB、redis、HBase。
NoSQL(Not only SQL),泛指非关系型的数据库。随着互联网 web2.0 网站的兴起,传统的关系数据库在应付 web2.0 网站,特别是超大规模和高并发的 SNS 类型的 web2.0 纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL 数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题。非关系型数据库可以为大数据建立快速、可扩展的存储库。
MongoDB
1、存储方式:虚拟内存+持久化。
2、查询语句:是独特的MongoDB的查询方式。
3、适合场景:事件的记录,内容管理或者博客平台等等。
4、架构特点:可以通过副本集,以及分片来实现高可用。
5、数据处理:数据是存储在硬盘上的,只不过需要经常读取的数据会被加载到内存中,将数据存储在物理内存中,从而达到高速读写。
6、成熟度与广泛度:新兴数据库,成熟度较低,Nosql数据库中最为接近关系型数据库,比较完善的DB之一,适用人群不断在增长。
三、MongoDB优势与劣势
优势:
1、快速。 在适量级的内存的MongoDB的性能是非常迅速的,它将热数据存储在物理内存中,使得热数据的读写变得十分快。
2、高扩展性。 MongoDB的高可用和集群架构拥有十分高的扩展性。
3、自身的FaiLover机制。 在副本集中,当主库遇到问题,无法继续提供服务的时候,副本集将选举一个新的主库继续提供服务。
4、Json的存储格式。 MongoDB的Bson和JSon格式的数据十分适合文档格式的存储与查询。
劣势:
1、 不支持事务操作。MongoDB本身没有自带事务机制,若需要在MongoDB中实现事务机制,需通过一个额外的表,从逻辑上自行实现事务。
2、 应用经验少,由于NoSQL兴起时间短,应用经验相比关系型数据库较少。
3、MongoDB占用空间过大。
四、MySQL优势与劣势
优势:
1、在不同的引擎上有不同 的存储方式。
2‘、查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高。
3、开源数据库的份额在不断增加,mysql的份额页在持续增长。
劣势:
1、在海量数据处理的时候效率会显著变慢。
五、Mysql和Mongodb主要应用场景
1.如果需要将mongodb作为后端db来代替mysql使用,即这里mysql与mongodb 属于平行级别,那么,这样的使用可能有以下几种情况的考量:
(1) mongodb所负责部分以文档形式存储,能够有较好的代码亲和性,json格式的直接写入方便。(如日志之类)
(2) 从datamodels设计阶段就将原子性考虑于其中,无需事务之类的辅助。开发用如nodejs之类的语言来进行开发,对开发比较方便。
(3) mongodb本身的failover机制,无需使用如MHA之类的方式实现。
2.将mongodb作为类似redis ,memcache来做缓存db,为mysql提供服务,或是后端日志收集分析。 考虑到mongodb属于nosql型数据库,sql语句与数据结构不如mysql那么亲和 ,也会有很多时候将mongodb做为辅助mysql而使用的类redis memcache 之类的缓存db来使用。 亦或是仅作日志收集分析。
六、对比
数据库名 | MongoDB | MySQL |
数据库模型 | 非关系型 | 关系型 |
存储方式 | 以类JSON的文档的格式存储(虚拟内存+持久化) | 不同引擎有不同的存储方式 |
查询语句 | MongoDB查询方式(包含类似JavaScript的函数) | 传统SQL语句 |
数据处理方式 | 基于内存,将热数据存放在物理内存中,从而达到高速读写 | 不同引擎有自己的特点 |
架构特点 | 可以通过副本集,以及分片来实现高可用 | 常见有单点,M-S,MHA.MMMCluster等架构方式 |
成熟度 | 新兴数据库,成熟度较低 | 成熟度高 |
广泛度 | NoSQL数据库中,比较完善且开源,使用人数在不断增长 | 开源数据库,市场份额不断增长 |
事务性 | 仅支持单文档事务操作,弱一致性 | 支持事务操作 |
占用空间 | 占用空间大 | 占用空间小 |
join操作 | MongoDB没有join | MySQL支持join |
七、scrapy爬取猫眼电影排行榜海量数据,并法将其保存在本地Mysql和MongoDB中。
scrapy startproject myfrist(your_project_name)
(scrapy startproject mongodb)用pycharm打开项目所在目录,并在终端输入 scrapy gendpider maoyan maoyan.com(以猫眼电影网页为例) 创建爬虫。 创建爬虫命令 :scrapy genspider 爬虫名 爬虫的地址 ,完整项目结构如下:
2.思路:先访问首页的排行榜,可以提取出首页排行的电影名和得分(每页三十个数据)。在首页中提取下一页标签的href,不断推送。就可以循环爬取啦。
maoyan.py代码如下:
1 import scrapy 2 3 4 class MaoyanSpider(scrapy.Spider): 5 name = ‘maoyan‘ 6 allowed_domains = [‘maoyan.com‘] 7 start_urls = [‘https://maoyan.com/films?showType=3&offset=0‘] 8 count = 0 9 NUM_PAGE = 3 # 默认爬前三页 10 11 def parse(self, response): 12 if self.count == self.NUM_PAGE: # 控制抓取的页数 例如只抓取前三页就循环三次 13 return 14 names = response.xpath(‘//dd/div[@class="channel-detail movie-item-title"]/@title‘).extract() 15 grades = [div.xpath(‘string(.)‘).extract_first() for div in response.xpath(‘//dd/div[@class="channel-detail channel-detail-orange"]‘)] 17 next_url = response.xpath(‘//ul[@class="list-pager"]/li[last()]/a/@href‘).extract_first() # 匹配父标签下相同子标签的最后一个 18 for name, grade in zip(names, grades): 19 # 把数据推送给pipeline管道 20 yield { 21 ‘name‘: name, 22 ‘grade‘: grade 23 } 24 yield scrapy.Request(response.urljoin(next_url), callback=self.parse) 25 self.count += 1
3.数据的保存是在pipelines.py模块中,代码如下。
from pymongo import MongoClient from pymysql import connect class MonogodbPipeline: """ 数据库名:maoyan 数据表名:t_maoyan_movie 可以事先不用创建,python会自动创建数据库和数据表 """ def open_spider(self, spider): self.client = MongoClient(‘localhost‘, 27017) self.db = self.client.maoyan self.collection = self.db.t_maoyan_movie def process_item(self, item, spider): self.collection.insert(item) return item def close_spider(self, spider): self.client.close() class MySQLPipeline: """ 数据库名:maoyan 数据表名:t_maoyan_movie mysql需要自己手动创建数据库和相对应的数据表 """ def open_spider(self, spider): self.client = connect(host=‘localhost‘, port=3306, user=‘root‘, password=‘root‘, database=‘maoyan‘, charset=‘utf8‘) # 创建游标 self.cursor = self.client.cursor() def process_item(self, item, spider): sql = ‘insert into t_maoyan_movie values(0,%s,%s) ‘ self.cursor.execute(sql, [item[‘name‘], item[‘grade‘]]) self.client.commit() return item def close_spider(self, spider): self.cursor.close() self.client.close()
from fake_useragent import UserAgent # 偷懒的写法,一般自己定义USER-AGENT中间件 USER_AGENT = UserAgent().chrome ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY = 3 # 隔三秒爬一次
ITEM_PIPELINES = { ‘monogodb.pipelines.MonogodbPipeline‘: 300, ‘monogodb.pipelines.MySQLPipeline‘: 301, }
5. 创建mysql数据库和数据表 注意: python会自动创建mongodb数据库和对应collection,但mysql需要先手动创建。如果嫌命令创建麻烦,完全可以使用Navicat连接数据库界面操作。
1.连接mysql cmd中 命令: mysql -u root -p root
2. 创建数据库: create database maoyan charser ‘‘utf8 (库名必须和代码中库名一致)
3.切换到已创建数据库创建表:user maoyan
4. 创建表
create table t_maoyan_movie (id int primary key auto_increment,name varchar(20), grade varchar(20));
6. 执行程序插入数据
创建start.py文件,并执行
from scrapy.cmdline import execute execute(‘scrapy crawl maoyan‘.split())
也可以在终端中输入: scrapy crawl maoyan
7.结果:
1.mysql中结果
可以看到有90条数据。因为只爬了前三页,一页30条。可以在程序中选择页数。
mongodb中结果:
打开Robo 3T, 执行 db.getCollection(‘t_maoyan_movie‘).find({})
可以看到电影信息啦
执行 db.getCollection(‘t_maoyan_movie‘).find({}).count()
可以看到依然有90条数据。
至此,大功告成!