大数据时代,各行各业对数据采集的需要日益增多,网络爬虫的使用也更为宽泛,越来越多的人开始学习网络爬虫这项技术,K 哥爬虫此前曾经推出不少爬虫进阶、逆向相干文章,为实现从易到难全方位笼罩,特设【0 根底学爬虫】专栏,帮忙小白疾速入门爬虫,本期为数据存储。
概述
上期咱们介绍到了文件存储,讲到了如何将数据存入各种文本文件之中,这种数据存储形式尽管很简便,然而存在很多问题,如:数据容易失落、文件容易损坏、数据不易共享。因而本期将介绍更加实用的数据库存储形式。
本文将介绍三种风行的数据存储技术:
MySQL:一种关系型数据库管理系统,宽泛用于企业级应用程序中
MongoDB:一种文档型数据库,适宜解决半结构化数据和大规模数据集。
Redis:一种内存数据库,用于解决高速读写操作和缓存数据。
在本文中,咱们将别离介绍 MySQL、MongoDB 和 Redis 的优缺点、实用场景以及如何抉择最适宜本人的数据库存储技术。作为爬虫初学者,本文将帮忙你更好地了解这三种数据库存储技术的工作原理,以及如何抉择适宜你的应用程序的数据库。
MySQL
介绍
MySQL 是一种开源的关系型数据库管理系统,是目前最风行的关系型数据库之一。MySQL 是一个疾速、高效的数据库系统,可能解决大量的数据和申请。另一个长处是它的灵活性和可扩展性,能够依据须要进行配置和调整,以满足不同利用的需要。MySQ L 应用 SQL(结构化查询语言)作为其查问和治理语言,SQL 是一种规范的关系型数据库语言,用于定义、操作和查问数据。
MySQL 被宽泛用于 Web 开发、数据分析和数据存储等畛域,是一个十分弱小和受欢迎的数据库系统。同时,因为它是开源软件,因而能够在不领取任何费用的状况下应用和批改,这也使得它成为了很多开发者的首选数据库系统。
装置
首先须要装置 MySQL 数据库,在 MySQL 官网 下载对应版本的文件进行装置。
装置好 MySQL 并确保 MySQL 可能失常运行后须要装置 Python 的第三方库 PyMySQL。
pip install pymysql
应用
在应用 Python 操作 MySQL 数据库前,咱们须要先理解一下根本的 sql 语句。
sql 语句
SQL 即结构化查询语言 (Structured Query Language),是一种非凡目标的编程语言,是一种数据库查问和程序设计语言。
数据库操作
-- 创立数据库
create database 数据库库名;
-- 查看所有数据库
show databases;
-- 应用数据库
use 数据库库名;
-- 删除数据库
drop database 数据库库名;
表操作
-- 创立表
create table 表名 (
属性名 数据类型 束缚,
.
.
);
-- 查看表构造
desc 表名;
-- 批改表名
alter table 表名 rename to 新的表名;
-- 增加新字段
alter table 表名 add 属性; 数据类型; 束缚;
-- 删除一个字段
alter table 表名 drop 属性名;
-- 删除表
drop table 表名;
束缚 | 形容 |
---|---|
PRIMARY KEY | 主键束缚。第一范式要求每一张表都应该有一个主键作为表的惟一标识,主键具备唯一性。 |
UNIQUE | 惟一束缚。标识该属性的值是惟一的。 |
NOT NULL | 非空束缚。标识该属性的值不能为空。 |
FOREIGN KEY | 外键束缚。标识该属性为该表的外键,与某表的主键关联。 |
AUTO_INCREMENT | 标识该属性的值主动减少 |
DEFAULT | 为该属性设置默认值 |
插入数据
insert into 表名 (属性 1, 属性 2, 属性 3) values(值 1, 值 2, 值 3);
批改数据
-- 批改指定数据
update 表名 set 属性 1 = 值 1, 属性 2 = 值 2 where 条件表达式;
删除数据
-- 删除表中所有数据
delete from 表名;
-- 删除指定数据
delete from 表名 where 条件表达式;
查问数据
-- 查问所有数据
select * from 表名;
-- 条件查问
select 字段 1, 字段 2 from 表名 where 字段 in (值 1, 值 2, 值 3...)
-- 多条件查问
select 字段 1, 字段 2 from 表名 where 字段 1 in (值 1, 值 2, 值 3...) and 字段 2 in (值 4, 值 5, 值 6...)
-- 范畴查问
select 字段 1, 字段 2 from 表名 where 字段 BETWEEN 值 1 and 值 2; -- 查问字段值在值 1 到值 2 之间的记录
-- 含糊查问
-- % 代表任意字符;-- _ 代表单个字符;select * from 表名 where 字段 like '张 %'; -- 查问字段值以张结尾的记录
select * from 表名 where 字段 like '_张 %'; -- 查问字段值第二位是张的记录
-- 排序
select 字段 from 表名 order by 字段名 ASC|DESC; -- ASC 升序 DESC 降序
-- 去重
select DISTINCT 字段 from 表名;
-- 分组查问
select 字段 1,AVG(字段 2) from 表名 group by 字段 1; -- 按字段 1 分组,查问字段 2 的平均值
-- 示例
select gender,avg(grade) from users group by gender; -- 按性别分组,查问各性别的均匀问题
Python 操作 MySQL
连贯数据库
import pymysql
db = pymysql.connect(
host='localhost',
user='root',
database='user',
password='test123',
port=3306,
charset='utf8mb4'
)
#获取操作游标
cursor = db.cursor()
host:IP 地址
user:用户名
password:明码
database:库名
port:数据库端口
charset:字符集编码
连贯数据库后,调用 cursor() 办法获取对数据库的操作游标,通过游标能够执行 sql 语句。
创立表
#sql 语句
sql = 'CREATE TABLE students (id VARCHAR(255) PRIMARY KEY, name VARCHAR(255) NOT NULL, age INT NOT NULL, grade INT)'
# 通过游标执行 sql 语句
cursor.execute(sql)
#敞开数据库连贯
db.close()
插入数据
上一步中咱们创立了一张 students 表,当初咱们要向 students 表中插入数据。
# 插入语句
sql = 'INSERT INTO students(id, name, age, grade) values ("%(id)s","%(name)s", %(age)d, %(grade)d)'
try:
#执行语句
cursor.execute(sql % {'id': '1001', 'name': '张三', 'age': 25, 'grade': 92})
#提交
db.commit()
except:
#插入异样则回滚数据
print('插入异样')
db.rollback()
db.close()
插入数据时,字符串类型的数据应被单引号或双引号包裹,否则会导致程序异样。在执行语句和提交语句时应该进行异样解决,产生异样时回滚数据,确保事务的原子性。
更新数据
sql = 'UPDATE students SET grade = %(grade)d WHERE id ="%(id)s"'
try:
cursor.execute(sql % {'id':'1001', 'grade': 90})
db.commit()
except:
db.rollback()
db.close()
删除数据
sql = 'DELETE FROM students WHERE id ="%(id)s"'
try:
cursor.execute(sql % {'id':'1001'})
db.commit()
except:
db.rollback()
db.close()
查问数据
在查问数据之前,咱们能够从新创立一个新的表,插入一些数据来作为案例。
# 创立表
create_table_sql = """CREATE TABLE students (
id INT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
age INT NOT NULL,
gender ENUM('男', '女') DEFAULT '男' NOT NULL,
grade INT DEFAULT NULL
);
"""
# 插入数据
insert_sql = """
INSERT INTO students (id, name, age, gender, grade)
VALUES
(1, '张三', 20, '男', 80),
(2, '李四', 19, '男', 75),
(3, '王五', 21, '男', 88),
(4, '赵六', 18, '女', 92),
(5, '钱七', 20, '女', 85),
(6, '孙八', 19, '男', 78),
(7, '周九', 21, '女', 90),
(8, '吴十', 18, '男', 86),
(9, '郑一', 20, '女', 81),
(10, '王二', 19, '男', 77);
"""
执行查问语句后,能够调用 fetchall 办法获取查问后果。
# 查问年龄大于 20 岁的记录
sql = """SELECT * FROM students WHERE age > 20"""
cursor.execute(sql)
# 返回一条查问后果
# result = cursor.fetchall()
# 返回所有查问后果
result = cursor.fetchall()
print(result)
# ((3, '王五', 21, '男', 88), (7, '周九', 21, '女', 90))
# 查问姓名以张结尾的记录
select_like_sql = """SELECT * FROM students WHERE name like' 张 %'"""
((1, '张三', 20, '男', 80),)
# 以性别分组查问平均分
select_group_sql = """SELECT gender, avg(grade) FROM students group by gender"""
(('男', Decimal('80.6667')), ('女', Decimal('87.0000')))
MongoDB
介绍
上文中讲到的 MySQL 是一种关系型数据库,而 MongoDB 与下文中的 Redis 都属于非关系型数据库,也被称为 NoSQL(Not Only SQL)。MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 利用提供可扩大的高性能数据存储解决方案。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中性能最丰盛,最像关系数据库的。它将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档相似于 JSON 对象。字段值能够蕴含其余文档,数组及文档数组。
装置
首先须要装置 MongoDB 数据库,在 MongoDB 官网 下载对应版本的文件进行装置。
装置好 MongoDB 并确保 MongoDB 可能失常运行后须要装置 Python 的第三方库 PyMongo。
pip install pymongo
应用
首先须要理解一下 MongoDB 的常用命令
-- 查看以后数据库
db
-- 查看所有数据库
show dbs
-- 切换数据库(不存在则创立)use 数据库名
-- 删除数据库
db.dropDatabase()
-- 创立汇合
db.createCollection(汇合名称, 创立参数)
-- 查看汇合(与 MySQL 中的表类似)show tables
show collections
-- 删除汇合
db. 汇合名称.drop()
Python 操作 MongoDB
连贯数据库
import pymongo
client = pymongo.MongoClient('mongodb://localhost:27017/')
插入数据
# 应用 test 库 (没有则创立)
db = client['test']
# 创立一个汇合
students = db['students']
data = {'id':'1001','name':'张三','age':20,'gender':'男'}
# 插入一条
result_one = students.insert_one(data)
# 插入多条
resutl_many = students.insert_many([{'id':'1002','name':'李四','age':22,'gender':'男'},{'id':'1003','name':'王五','age':24,'gender':'女'}])
print(result)
print(resutl_many)
# <pymongo.results.InsertOneResult object at 0x00000200BB19AA88>
# <pymongo.results.InsertManyResult object at 0x00000200BB1D6E08>
查问数据
# 查问一条 name 为李四的数据
result_one = students.find_one({'name':'李四'})
# {'_id': ObjectId('64375e380fa1b587bc84e32d'), 'id': '1002', 'name': '李四', 'age': 22, 'gender': '男'}
# 查问多条, 返回一个生成器
result_many = students.find({'gender':'男'})
# <pymongo.cursor.Cursor object at 0x000002527225A888>
for result in result_many:
print(result)
# {'_id': ObjectId('64375e3b89cfb1bb0c54b1c3'), 'id': '1001', 'name': '张三', 'age': 20, 'gender': '男'}
# {'_id': ObjectId('64375e3b89cfb1bb0c54b1c4'), 'id': '1002', 'name': '李四', 'age': 22, 'gender': '男'}
比拟符
# 查问年龄大于 20 的数据
students.find({'age':{'$gt':20}})
# 查问年龄不等于 20 的数据
students.find({'age':{'$ne':20}})
符号 | 含意 |
---|---|
$lt | 小于 |
$gt | 大于 |
$lte | 小于等于 |
$gte | 大于等于 |
$ne | 不等于 |
$in | 在范畴内 |
$nin | 不在范畴内 |
更新数据
query = {"name":"张三"}
new_values = {"$set":{ "age":25}}
# 更新第一条符合条件的数据
# students.update_many(query, new_values)
# 更新所有符合条件的数据
result = students.update_many(query, new_values)
# <pymongo.results.UpdateResult object at 0x0000022C92BA8E08>
删除数据
# 删除一条
query = {"name": "张三"}
students.delete_one(query)
# 删除多条
query = {"age": {"$gt":22}}
students.delete_many(query)
# 删除所有
students.delete_many({})
# 删除汇合
students.drop()
Redis
介绍
Redis 是一个基于内存的键值对存储系统,也被称为数据结构服务器,反对多种数据结构。它被宽泛用于缓存、会话治理、音讯队列等应用程序中。
装置
首先须要装置 Redis 数据库,装置好 Redis 并确保 Redis 可能失常运行后须要装置 Python 的第三方库 redis-py。
pip install redis
应用
Redis 根本数据类型
字符串:字符串(string)是 redis 最根本的数据类型,它能够蕴含任意数据。
哈希:哈希(hash)是一个键值对汇合,是一个 string 类型的 field 和 value 的映射表。
列表:列表(list)是简略的字符串列表,按插入程序排序,reids 列表反对在它的头尾部插入数据。
汇合:汇合(set)是字符串类型的无序汇合,汇合内的元素具备唯一性。
有序汇合:有序汇合(zset)与汇合一样也是字符串类型的汇合。不同的是有序汇合中每个元素都会关联一个 double 类型的分数,它会通过分数来对元素进行升序排序。
Python 操作 Redis
连贯数据库
from redis import StrictRedis
redis = StrictRedis(host='localhost',port=6379,decode_responses=True)
# Redis<ConnectionPool<Connection<host=localhost,port=6379,db=0>>>
字符串操作
redis 默认返回后果是字节,在连贯时设置 decode_responses=True
能够将返回后果改为字符串。
# 增加一条数据,ex 为过期工夫(秒),过期后键 name 的值就变为 None
redis.set('name','张三', ex=3)
redis.set('nick','张三三三')
# 返回指定键的值
redis.get('name') # 张三
# 设置新值,返回旧值
redis.getset('name','李四') # 张三
# 依据字节取值,(0,2)取前三位的字节,一个汉字三个字节,一个字母一个字节
print(redis.getrange('nick', 0, 2)) # 张
# 从指定地位开始批改内容
redis.setrange('nick',3,'五五五')
redis.get('nick') # 张五五五三
# 批量取值
redis.mget('name','nick') # ['李四', '张五五五']
# 批量赋值
redis.mset({'key1':'value1','key2':'value2'})
redis.mget('key1', 'key2') # ['value1', 'value2']
哈希操作
# 单个增加, 向 hash1 中设置一个键值对(hash1 存在则批改,不存在则创立)redis.hset('hash1','key1','value1')
redis.hset('hash1','key2','value2')
# 取 hash1 中所有的 key
redis.hkeys('hash1') # ['key1', 'key2']
# 单个取 hash1 的 key 对应的值
redis.hget('hash1', 'key1') # value1
# 多个取 hash1 的 key 对应的值
# 批量增加
redis.hmset('hash2', {'key3': 'value3', 'key4': "value4"})
# 批量取出
redis.hmget('hash2','key3','key4') # ['value3', 'value4']
# 取出所有键值对
redis.hgetall('hash2') # {'key3': 'value3', 'key4': 'value4'}
# 取出所有值
redis.hvals('hash2') # ['value3', 'value4']
# 取出所有键
redis.hkeys('hash2') # ['key3', 'key4']
列表操作
# 将元素增加到列表最右边,列表不存在则新建
redis.lpush('grade', 88, 87, 92)
# 将元素增加到列表最左边,列表不存在则新建
redis.rpush('grade', 78, 67, 99)
# 同字符串切片
redis.lrange('grade', 0, -1) # ['92', '87', '88', '78', '67', '99']
# 向已有列表增加数据,列表不存在不会新建
redis.lpushx('age',22)
# 返回列表长度
redis.llen('age') # 0
# 在某个值的前或后插入一个值
# 在右边一个元素 88 前插入元素 66
redis.linsert('grade','before',88,66)
# 批改列表中某个地位的值
# 将索引号为 0 的元素值批改为 77
redis.lset('grade', 0, 77)
# 删除指定值
# 删除右边第一次呈现的 87
redis.lrem('grade', 87, 1)
# 删除所有 87
redis.lrem('grade', 87, 0)
# 删除并返回
redis.lpop('grade') # 删除最右边的元素并返回
汇合操作
# 增加元素
redis.sadd('count', 88, 87, 92)
# 汇合长度
redis.scard('count') # 3
# 获取所有元素
redis.smembers('count') # {'92', '87', '88'}
# 删除随机元素并返回
redis.spop('count') # 87
# 删除指定元素
redis.srem('count',88)
# 差集,返回在汇合 1 中且不在汇合 2 中的元素汇合
redis.sadd('set1', 12, 13, 14, 15)
redis.sadd('set2', 12, 15, 18, 21)
# 在 set1 中且不在 set2 中的元素
redis.sdiff('set1','set2') # {'13', '14'}
# 交加,返回多个汇合雷同的元素汇合
redis.sinter('set1','set2') # {'15', '12'}
# 并集,返回多个汇合的并集
redis.sunion('set1','set2') # {'13', '12', '18', '21', '14', '15'}
有序汇合操作
# 增加元素
redis.zadd('fruit',{'apple':10,'banana':6})
# 汇合长度
redis.zcard('fruit') # 2
# 获取所有元素
redis.zrange('fruit',0,-1) # ['banana', 'apple']
# 从大到小排序
redis.zrevrange('fruit',0,-1) # ['apple', 'banana']
# 获取在某个区间中的元素个数
redis.zcount('fruit', 5, 8) # 1
# 删除指定值
redis.zrem('fruit', 'apple')
# 依据范畴删除
redis.zremrangebyscore('fruit', 5, 8)
# 获取值对应的分数
redis.zscore('fruit', 'apple') # 10.0
总结
以上讲到了三种数据库的根本应用办法以及它们各自的特点,MySQL 应用 sql 语句来对数据进行操作,比拟成熟,然而在海量数据处理时效率会显著变慢。MongoDB 是一个面向汇合的,模式自在的文档型数据库,采纳虚拟内存与长久化的存储形式,可能存储 JSON 格调的数据,能做到数据的高速读写,然而它不反对事务操作,且占用空间过大。Redis 则是一个纯正的内存数据库,所有数据寄存在内存中,它也反对数据的长久化,能够将数据存到磁盘中,它领有多种数据类型,性能极高,但与 MongoDB 一样不适宜存储大量数据。因而在开发时,抉择哪种数据库来存储数据须要以本人的理论需要为准。