Python爬虫--数据存储
数据存储
txt文件
占坑
代码
实例代码
Json文件
实例代码
csv文件
数据库存储
数据量多且复杂,存储到文件的数据管理不方便,效率较低。
将数据存储到数据库中,方便存储和管理。
关系型数据库
概念:
- 关系型数据库是建立在关系模型基础的数据库。
- 借助于集合代数等数学概念和方法处理数据库中的数据。
- 由多张能互相连接的二维行列表格组成。
MYSQL
mysql优势
- 开源(可根据需要修改),免费
- 支持大型数据库,可以处理拥有上千万条记录的大型数据库
- 核心线程完全是多线程,支持多处理器
mysql安装
sudo apt install mysql-server
启动服务器
- 启动服务
sudo service mysql start
- 重启服务
sudo service mysql restart
- 查看服务进程
ps -axu|grep mysqld
启动客户端
-u 表示用户名, -p 表示密码
mysql -uroot -p # -p后输入root用户密码
配置支持远程连接
MySQL默认不支持远程连接,只能本主机连接
配置:
- 找到MySQL配置文件并修改
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf将bind-address=127.0.0.1注释
- 登录MySQL,修改Host值
登录mysql -uroot -p
选择使用MySQL数据库
use mysql;
更新,将root原来的 Host值(localhost) 改成 %
localhost 表示只能本地登录,% 表示任何机器都可以登录
update user set Host="%" where User = "root";
刷新权限信息让所做的设置马上生效
flush privileges;
退出登录
exit;
- 重启服务
sudo service mysql restart
- 测试远程连接
-h 参数 指定客户端登录的MySQL主机名,登录本机,该参数可省略
如果是远程连接,则必须指定其值是远程主机的IP地址,这里的192.168.1.150就是主机的IP地址
mysql -h192.168.1.150 -uroot -p
数据库命令
查看数据库
show databases;
创建数据库
create database 数据库名 charset=utf8;
删除数据库
drop database 数据库名;
切换数据库
use 数据库名;
查看当前选择的数据库
select database();
表命令
查看当前数据库中所有表
show tables;
创建表
create table 表名(列及类型);
修改表
alter table 表名 add|modify|drop 列名 类型;
删除表
drop table 表名;
查看表结构
desc 表名;
更改表名称
rename table 原表名 to 新表名;
查看表的创建语句
show create table 表名;
增删改查命令
新增
insert into 表名 (field, field, ..., fieldN) values(value, value, ..., valueN);
删除
delete from 表名 [where 条件];
更新
update table_name set field = new-value, field = new-value [where 条件];
查询
select field, field from table_name [where 条件];
使用命令
流程
service mysql start # 启动mysql
mysql -uroot -p1234 # 登录mysql
create database python default charset=utf8; # 创建python数据库
use python; # 切换到python数据库
-- 创建grade表(主键表)create table grade(
id int primary key auto_increment,
name varchar(100) not null
);
-- 创建student表(外键表)create table student(
id int primary key auto_increment,
name varchar(100) not null,
sex char(1) not null,
phone char(11) unique not null,
address varchar(100) default \'郑州\',
birthday date not null,
gid int not null,
foreign key(gid) references grade(id)
);
-- 年级(grade)表中插入数据insert into grade(name) values(\'一年级\');
insert into grade(name) values(\'二年级\');
-- 学生(student)表中插入数据insert into student(name, sex, phone, address, birthday, gid) values(\'王强\', \'男\' ,\'15583678666\' , \'开封\', \'1990-2-4\', 1);
insert into student(name, sex, phone, address, birthday, gid) values(\'李丽\', \'女\', 16683678659\'\', \'郑州\', \'1991-3-12\', 2);
select * from grade; # 查询年级(grade)表中的数据
select * from student; # 查询学生表数据
update student set phone = \'16683678657\' where id = 2; # 更改id为2的学生电话号码
delete from student where id = 1; # 删除id为1的学生
Python与MySQL交互
安装pymysql模块
pip install pymysql -i https://pypi.tuna.tsinghua.edu.cn/simple
创建连接
\'\'\'Python与MySQL交互-创建连接\'\'\'import pymysql
获取连接对象
conn = pymysql.Connect(host=\'localhost\', port=3306, db=\'python\', user=\'root\', passwd=\'1234\', charset=\'utf8\')
print(conn)
关闭
conn.close()
说明:
- MySQL的服务器必须先启动才可以连接成功
- pymysql.Connect用来创建数据库连接对象
- 参数
host=\'localhost\', 表示连接主机是本机,也可指定IP地址
port=3306,主机端口号,默认是3306
host=\'localhost\',连接主机,localhost表示连接主机是本机,也可使用指定IP地址
port=3306, 主机端口号,mysql默认端口号为3306,一般不用更改
db=\'python\', 连接的数据库,这里连接的数据库是python
user=\'root\', 用户名
passwd=\'1234\',密码
charset=\'utf8\', 编码格式
- 连接对象使用完毕后要关闭,释放相关资源
查询和修改
Python与MySQL交互_查询与修改import pymysql
def select():
\'\'\'查询\'\'\'
try:
# 获取连接对象
conn = pymysql.Connect(host=\'localhost\', port=3306, db=\'python\', user=\'root\', passwd=\'1234\', charset=\'utf8\')
# 创建可执行对象,可以执行SQL语句
cur = conn.cursor()
# 执行SQL语句,并传递参数
cur.execute(\'select * from student where id=%s\', [2])
# 查询一个结果
result = cur.fetchone()
print(result)
# 关闭
conn.close()
except Exception as ex:
print(ex)
def update():
\'\'\'修改\'\'\'
try:
# 创建连接
conn = pymysql.Connect(host=\'localhost\', port=3306, db=\'python\', user=\'root\', passwd=\'1234\', charset=\'utf8\')
# 创建可以执行SQL语句的对象
cur = conn.cursor()
# 执行SQL语句,并传递参数
count = cur.execute(\'update student set name=%s where id=%s\', [\'张三\', 2])
# 判断结果
if count > 0:
print(\'成功\')
else:
print(\'失败\')
# 提交
conn.commit()
# 关闭
conn.close()
except Exception as ex:
print(ex)
if __name__ == \'__main__\':
select()
update()
说明:
- 如果是增删改,cur执行SQL语句返回值是受影响的行数。
- 如果是查询,则需要继续调用cur的查询方法,fetchone是查询符合条件的第一个对象,fetchall是查询符合条件的结果集
非关系型数据库
NoSQL(Not Only SQL)
特点
- 不支持SQL语法
- 存储数据KV形式
- NoSQL没有通用语言,每种NoSQL数据库都有各自的API和语法,以及擅长的业务场景
对比
- 适用场景:关系型数据库适用于关系特别复杂的数据查询场景,非关系型数据库反之
- 事务特性的支持:关系型数据库对事务支持完善,非关系型数据基本不支持事务
- 两者取长补短。对于爬虫的数据,可能有缺失值,可能结构不同。
用关系型数据库,建数据库,数据库表,关系约束,数据筛选,或拆分,这样使用效率较低;而非关系型数据库,直接以键值对存储,简单且效率高。
Redis
概述
用key-value存储,NoSQL的一种
值可以是字符串(String),哈希(Hash),列表(List),集合(Sets),有序集合(Sorted Sets)等类型
优势
- 性能极高:读的速度110000次/s,写的速度是81000次/s
- 支持的数据类型多:支持Strings,Lists,Hashes,Sets及Ordered Sets等数据类型的操作
- 原子:Redis的所有操作都是原子性的,同时还支持对几个操作合并后的原子性执行
- 丰富的特性:Redis还支持publish/subscribe,通知,key过期等特性
安装
1.打开Redis官方网站,下载稳定版本(stable),放到家目录下 cd /home
2.解压安装包
tar -zxvf ./redis.tar.gz # 解压
3.移动
sudo mv ./redis/ /usr/local/
4.编译
cd /usr/local/redis/sudo make
5.测试
sudo make test
6.将Redis的命令安装到/usr/local/bin/目录
sudo make install
启动
redis-server # 启动服务器
redis-cli # 启动客户端
测试连接
ping # 打印PONG表示连接成功
远程访问配置
修改redis.conf配置文件
vim /usr/local/redis/redis.conf
注释bind
protected-mode改为no
bind 127.0.0.1protected-mode no
使用配置文件方式启动
-- 复制配置文件到etc下的redis文件夹中sudo mkdir /etc/redis/
sudo cp /usr/local/redis/redis.conf /etc/redis
-- 指定配置文件启动
sudo redis-server /etc/redis/redis.conf
停止Redis服务
ps ajx|grep redis # 找到Redis的进程idsudo kill -9 redis的进程id
命令操作
Redis地理位置命令
geoadd # 将指定的地理空间位置(纬度,经度,名称添加到指定的key中)geodist # 返回两个给定位置之间的距离
geohash # 返回一个或多个位置元素的Geohash表示
geopos # 从key中返回所有给定位置元素的位置
georadius # 以给定的经纬度为中心,找出某一半径内的元素
georadiusbymember # 找出位于指定范围内的元素中心点由给定的位置元素决定
Redis键(key)命令
del # 该命令用于在key存在时删除keydump # 序列化给定key,并返回被化的值
move # 将当前数据库中的key移动到给定数据库db当中
rename # 修改key的名称
renamenx # 仅当newkey不存在时,将key改名为newkey
exists # 检查给定key是否存在
type # 返回key所储存的值的类型
keys # 查找所有符合给定模式的key
randomkey # 从当前数据库中随机返回一个key
expire # seconds为给定key设置过期时间
expireat # 作用与expire类似,设置key过期时间,接受的时间参数是unix时间戳
persist # 移除key的过期时间,key将持久保持
pttl # 以毫秒为单位,返回key的剩余过期时间
ttl # 以秒为单位,返回给定key的剩余生存时间
Redis字符串(String)命令
set # 设置指定key的值get # 获取指定key的值
getrange # 返回key中字符值的子字符
mget # 获取所有(一个或多个)给定key的值
setbit # 对key所储存的字符串值,设置或清除指定偏移量上的位
setex # 将值value关联到key,并将key的过期时间设为seconds(以秒为单位)
setnx # 只有在key不存在时设置key的值
setrange # 用value参数覆写给定key所储存的字符串值,从偏移量offset开始
strlen # 返回key所储存的字符串值的长度
getset # 将给定key的值设为value,并返回key的旧值
mset # 同时设置一个或多个key-value对
msetnx # 同时设置一个或多个key-value对,当且仅当所有给定key都不存在
psetex # 与setex相似,以毫秒为单位设置key的生存时间
incr # 将key中储存的数字值增一
incrby # 将key所储存的值加上给定的增量值
incrbyfloat # 将key所储存的值加上给定的浮点增量值
decr # 将key中储存的数字值减一
decrby # 将key所储存的值减去给定的减量值
append #如果key已经存在并且是一个字符串,则append将value追加到key原来值的末尾
Redis哈希(hash)命令
hdel # 删除一个或多个哈希表字段hexists # 查看哈希表key中,指字的字段是否存在
hget # 获取存储在哈希表中指定key的所有字段和值
hgetall # 获取在哈希表中指定keyr所有字段和值
hincrby # 为哈希表key中指定字段的整数值加上增量
hincrbyfloat # 为哈希表上指定字段的浮点数值加上增量
hkeys # 获取所有哈希表中的字段
hlen # 获取哈希表中的字段的数量
hmget # 获取所有给定字段的值
hmset # 同时将多个field-value(域-值)对设置到哈希表key中
hset # 将哈希表中的key中的字段field的值设为value
hsetnx # 只有在字段field不存在时,设置哈项表字段的值
hvals # 获取哈希表中所有值
记忆: hash命令和string命令的区别在于,hash前面多了个h,去了h命令简写都和string命令差不多
Redis列表(List)命令
blpop # 移出并获取列表的第一个元素,如果列表中没有元素,则会阻塞列表直到等待超时或发现可弹出元素为止brpop # 移出并获取列表的最后一个元素,如果列表中没有元素,则会阻塞列表直到等待超时或发现可弹出元素为止
brpoplpush # 从列表弹出一个值,将弹出的元素插入另外一个列表蹉返回它;如果列表中没有元素,则会阻塞列表直到等待超时或发现可弹出元素为止
lindex # 通过索引获取列表中的元素
linsert # 在列表的元素前或后插入元素
llen # 获取列表长度
lpop # 移出并获取列表的第一个元素
lpush # 将一个或多个值插入列表头部
lpushx # 将一个或多个值插入已存在的列表头部
lrange # 获取列表指定范围内的元素
lrem # 移除列表元素
lset # 通过索引设置列表元素的值
ltrim # 对一列表进行修剪,也就让列表只保留指定区内的元素,不在指定区间内的元素都将被删除
rpop # 移除并获取列表最后一个元素
rpoplpush # 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
rpush # 在列表中添加一个或多个值
rpushx # 为已存在的列表添加值
Redis集合(set)命令
sadd # 向集合添加一个或多个成员srem # 移除集合中一个或多个成员
sismember # 判断member元素是否集合key的成员
smembers # 返回集合中的所有成员
scard # 获取集合的成员数
sscan #迭代集合中的元素
srandmember # 返回集合中一个或多个随机数
spop # 移除并返回集合中的一个随机元素
smove # 将member元素从source集合到destination集合
sdiff # 返回所有给定集合的差集
sdiffstore # 返回所有给定集合的差集并存储在destination集合中
sinter # 返回所有给定集合的交集
sinterstore # 返回所有给定集合的交集并存储在destination集合中
sunion # 返回所有给定集合的并集
sunionstore # 返回所有给定集合的并集要并存储在destination集合中
记忆:s开头命令代表集合(set)命令
Redis有序集合(Sorted Set)命令
zadd # 添加一个或多个成员,或者更新已存在成员的分数zrem # 移除一个或多个成员
zscan # 迭代元素
�zscore # 返回成员分数值
zcard # 获取成员数
zincraby # 对指定成员的分数加上增量increment
zranbyscore # 通过分数返回指定区间内成员
zrangebylex # 通过字典区间返回成员
zinterstore # 计算给定的一个或多个的有序集合的交集并存储在新的key中
zunionstore # 计算给定的一个或多个有序集合并集并存储在新的key中
zrank # 返回指定成员的索引
zcount # 计算在指定区间分数的成员数
zlexcount # 计算指定字典区间内成员变量
zrange # 通过索引区间返回指定区间内成员数量
zremrangebylex # 移除给定的字典区间所有成员
zremrangebyrank # 移除给定的排名区间所有成员
zremrangebyscore # 移除给定的分数区间所有成员
zrevrank # 返回指定成员,按分数值递减(从大到小)
zrevrange # 返回指定区间内成员,通过索引,分数从高到低排序
zrevrangebyscore # 返回指定分数区间内成员,分数从高到低排序
Redis HyperLogLog命令
pfadd # 添加指定元素到HyperLogLog中pfcount # 返回给定HyperLogLog的基数估算值
pgmerge # 将多个HyperLogLog合并成一个
Redis发布订阅命令
publish # 将信息发送到指定的频道pubsub # 查看订阅与发布系统状态
subscribe # 订阅给定的一个或多个频道的信息
psubscribe # 订阅一个或多个符合给定模式的频道
unsubscribe # 只退订给定的频道
punsubscribe # 退订所有给定模式的频道
Redis事务命令
exec # 执行所有事务块内的命令discard # 取消事务,放弃执行事务块内的所有命令
multi # 标记一个事务块的开始
watch # 监视一个(或多个)key,如果在事务执行之前这个(这些)key被其他命令所改动,则事务将被打断
unwatch # 取消watch命令对所有key的监视
Redis脚本命令
eval # 执行Lua脚本evalsha # 执行Lua脚本
scriptexists # 查看指定的脚本是否已经被在缓存中
scriptflush # 从脚本缓存中移除所有脚本
scriptload # 将脚本script添加到脚本缓存中,但并不立即执行这个脚本
scriptkill # 杀死当前正在运行的Lua脚本
Redis连接命令
bgrewriteaof # 异步执行一个AOF(Append Only File)文件重写操作bgsave # 在后台异步保存当前数据库的数据到磁盘
client kill # 关闭客户端连接
client list # 获取连接到服务器的客户端连接列表
client getname # 获取连接的名称
client pause # 在指定时间内终止运行来自客户端的命令
client setname # 设置当前连接的名称
cluster slots # 获取集群节点的映射数组
command # 获取详情数组
command count # 获取总数
command getkeys # 获取给定的所有键
time # 返回当前服务器时间
command info # 获取指定描述的数组
config get # 获取指定配置参数的值
config rewrite # 对启动服务器时所指定的.conf配置文件进行改写
config set # 修改配置参数,无须重启
config resetstat # 重置INFO中的某些统计数据
dbsize # 返回当前数据库的key的数量
debug object # 获取key的调试信息
debug segfault # 让服务器崩溃
flushall # 删除所有数据库的所有key
flushdb # 删除当前数据库的所有key
info # 获取服务器的各种信息和统计数值 , db=
lastsave # 返回最近一次成功将数据保存到磁盘上的时间,以UNIX时间戳格式表示
monitor # 实时打印出服务器接收到的命令,调试用
role # 返回主从实例所属的角色
save # 异步保存数据到硬盘
shutdown # 异步保存数据到硬盘,并关闭服务器
slaveof # 将当前服务器转变为指定服务器的从属服务器
showlog # 管理Redis的慢日志
sync # 用于复制功能的内部命令
Python与Redis交互
安装模块
pip install redis
创建连接
\'\'\'Python与Redis交互-创建连接\'\'\'import redis
client = redis.StrictRedis(host=\'localhost\', port=6379, db=0)
print(client)
# 简写
# client = redis.StrictRedis()
说明:
Redis的服务器必须启动才可以连接成功
redis默认无密
redis.StrictRedis用来创建数据库连接对象
参数,
host:连接主机
port:主机端口号
db:要连接的数据库
连接对象不需要手动关闭。
当用Redis和StrictRedis创建连接时,内部实现没有主动创建一个连接,获得的连接是连接池提供的,由连接池管理,所以无法关注连接是否需要主动释放。
连接池有自己关闭连接的接口,一旦调用该接口,所有连接都将被关闭。
增删改查
# Python与Redis交互-增删改查from redis import *
def insert_update():
\'\'\'新增/修改\'\'\'
try:
# 创建StrictRedis对象,与Redis服务器建立连接
sr = StrictRedis()
# 添加键name,值为python
# 如果键name不存在,则为新增,否则为修改
result = sr.set(\'name\', \'python\')
# 输出响应结果,如果添加成功,则返回True,否则返回False
print(result)
except Exception as e:
print(e)
def select():
\'\'\'查询\'\'\'
try:
# 连接
sr = StrictRedis()
# 获取键name的值
result = sr.get(\'name\')
# 输出键的值,如果键不存在,则返回None
print(result)
except Exception as e:
print(e)
def delete():
\'\'\'删除\'\'\'
try:
# 连接
sr = StrictRedis()
# 删除
result = sr.delete(\'name\')
# 输出响应结果,删除成功,返回受影响的键数,否则返回0
print(result)
except Exception as e:
print(e)
if __name__ == \'__main__\':
insert_update()
select()
delete()
MongoDB
概念
基于分布式(主从复制,负载均衡)文件存储的NoSQL数据库,由C++语言编写,运行稳定,性能高,旨在为Web应用提供可扩展的高性能数据存储解决方案
特性
- 模式自由:可以把不同结构的文档存储在同一个数据库中
- 面向集合存储:适合存储对象及JSON形式的数据
- 完整的索引支持:对任何属性可索引
- 复制和高可用性:支持服务器之间的数据复制,支持主-从模式及服务器之间的相互复制,复制的主要目的是提供冗余及自动故障转移
- 自动分片以支持云级别的伸缩性:自动分片功能 支持水平的数据库集群,可动态添加额外的机器
- 丰富的查询:支持丰富的查询表达方式,查询指令使用形式的标记,可轩昂查询文档中内嵌的对象及数组
- 快速就地更新:查询优化器会分析查询表达式,并生成一个高效的查询计划
- 高效的传统存储方式:支持二进制数据及大型对象(如照片或图片)
优势
- 更高的写负载
- 处理很大规模的单表。数据库扩展是非常有挑战性的,当表格大小达到5-10GB时,MySQL表格性能会毫无疑问的降低。如果需要分片并分割数据库,MongoDB很容易实现
- 不可靠环境保证高可用性。设置副本集(主-从服务器设置)不仅方便,而且很快。此外,使用MongoDB还可以快速,安全及自动化地实现节点(或数据中心)故障转移
- 使用基于位置的数据查询,查得更快。MongoDB支持二维空间索引,如管道,因此可以快速及精确地从指定位置获取数据据。MongoDB在启动后会将数据库中的数据以文件映射的方式加载到内存中。如果内存资源相当丰富,那么将极大地提高数据库的查询速度,毕竟内存I/O效率比磁盘高很多。
- 非结构化数据的爆发增长 。增加列在有些情况下可能锁定整个数据库,或者增加负载从而导致性能下降,这个问题通常发生在表格大于1GB的情况。鉴于MongoDB的弱数据结构模式,添加一个新字段不会对旧表格有任何影响,整个过程会非常快速;因此,在应用程序发生改变时,不需要专门的一个DBA(数据库管理员)去修改数据库模式。
- 技术门槛相对低。如果没有专业的DBA,同时也不需要结构化数据及做join查询,那么MongoDB将会是首选。MongoDB非常适合类的持久化,类可以被序列化成JSON并储存在MongoDB中。需要注意的是,如果期望获得一个更大的规模,就必须要了解一些最佳实践来避免走入误区。
使用
安装
从官网下载安装包,选择合适的版本下载
32bit的MongoDB最大只能存放2GB的数据,64bit就没有限制
mongodb-linux-x86_64-ubuntu.tgz
解压安装包
tar -zxvf mongodb-linux-x86_64-ubuntu.tgz
移动
sudo mv mongodb-linux-x86_64-ubuntu.tgz/ /usr/local/mongodb
新建配置文件mongod.conf,放到/etc目录下,写入6行命令
port=27017dbpath=/var/lib/mongodb/
logpath=/var/log/mongodb/mongodb.log
fork=true
logappend=true
noauth=true # 无密
创建相关文件和文件
sudo mkdir /var/lib/mongodb/sudo mkdir /var/log/mongodb/
sudo touch /var/log/mongodb/mongodb.log
创建软链接,方便调用mongod和mongo命令
sudo ln -sf /usr/local/mongodb/bin/mongod /usr/local/sbin/mongodsudo ln -sf /usr/local/mongodb/bin/mongo /usr/local/sbin/mongo
启动
启动服务器端
mongod
或
sudo mongod -f /etc/mongod.conf
启动客户端
sudo mongo
查看数据库的状态信息
db.stats()
关闭服务器
use admin db.shutdownServer()
常用的数据类型
object id # 文档id
string # 字符串,最常用,必须是有效的UTF-8
boolean # 布尔值,True或False
integer # 整数可以是32位或64位,取决于服务器
double # 浮点值
array # 数组或列表,多个值存储到一个键
object # 用于嵌入式的文档,即一个值为一个文档
null # 存储null值
timestamp # 时间戳
date # 存储当前日期或时间的UNIX时间格式
说明:
object id。每个文档都有一个属性,为_id,保证每个文档的唯一性,可以自己去设置_id插入文档。
如果没有提供,MonoDB为每个文档提供了一个独特的_id,类型为ObjectID.
ObjectID是一个12字节的十六进制数,前4个字节为当前时间戳,后3个字节为机器ID,后2个字节为MongoDB的服务进程id,最后3个字节为简单的增量值
命令操作
use mydbdb.stu.insert([
{
\'name\': "郭靖",
"hometown": \'蒙古\',
"age": 20,
\'gender\': true
},
{
\'name\': \'黄蓉\',
\'hometown\': \'桃花岛\',
\'age\': 18,
\'gender\': false
}
])
数据库命令
db # 查看当前数据库名称show dbs # 查看所有数据库名称,列出所有在物理上存在的数据库
use 数据库名称 # 切换数据库
�/*如果数据库不存在,则指向数据库,直到插入数据或创建集合时数据库才被创建。
默认的数据库为test,如果没有创建新的数据库,则集合存放在test数据库中*/
db.dropDatabase() # 删除当前指向的数据库,如果数据库不存在,则什么也不做
db相当于MySQL中的database
集合命令
db.createCollection(name, options) # 创建集合 /*name:要创建的集合名称,必须有。db.createCollection(\'stu\')
选项参数options:文档,用于指定集合的配置。
capped:默认False,不设置上限,Ture,设置(集合大小)上限
size:capped值为True时指定,上限大小,文档达到上限时,会覆盖之前数据,单位字节
db.createCollection("sub", {capped:true, size:10})
*/
show collections # 查看当前数据库的集合
db.集合名称.drop() # 删除集合
这里的集合相当于MySQL的表
数据操作命令
db.集合名称.insert(document) # 新增一条文档信息/*
db.stu.insert({name:\'qj\', gender:1})
*/
db.集合名称.find() # 查询当前集合所有文档信息
db.集合名称.update(<query>, <update>, {multi:<boolean>})
/*
参数:
query:查询条件
update:更新操作符
multi:可选,默认False,只更新找到的第一条记录,True,把满足条件的文档全部更新
示例:
全文档更新
db.stu.update({name:\'hr\', {name:\'mnc\'}})
指定属性更新
�db.stu.insert({\'name\':\'hr\', gender:0})
db.stu.update({name:\'hr\',{$set:{name:\'hys\'}}})
修改多条匹配到的数据
db.stu.update({}, {$set:{gender:0}}, {multi:true})��*/
�
db.集合名称.save(document) # 保存
/*
如果文档的_id已存在,则修改;如果文档的_id不存在,则添加
db.stu.save({_id:\'20160102\', \'name\':\'yk\', gender:1})
db.stu.save({_id:\'20160102\', \'name\': \'wyk\'})*/
db.集合名称.remove(<query>, {justOne:<boolean>}) # 删除
/*
参数:
query:删除文档的条件
justOne:设为True或1,则只删除一条,默认为False,删除多条
示例:
只删除一条
db.stu.remove({gender:0}, {justOne:true})
全部删除
db.stu.remove({})*/
这里的文档document相当于MySQL的一行数据,其语法格式相当于JavaScript的JSON对象
数据查询命令
db.集合名称.find({条件文档}) # 根据条件查询,返回结果集db.集合名称.findOne({条件文档}) # 根据条件查询,返回第一个
db.集合名称.find({条件文档}).pretty() # 将查询的结果格式化
$lt, $lte, $gt, $gte, $ne
/*
等于,默认是等于判断,没有运算符
小于$lt
小于或等于$lte
大于$gt
大于或等于$gte
不等于$ne
示例:
查询名称等于\'qj\'的学生
db.stu.find({name:\'gj\'})
查询年龄大于或等于18的学生
db.stu.find({age:{\$gte:18}})
*/
and, or # 逻辑与,逻辑或 默认是逻辑与
/*
示例:
查询年龄大于或等于18,并且性别为1的学生
db.stu.find({age:{$gte:18},gender:1})
查询年龄大于18或性别为1的学生
db.stu.find({$or:[{age:{$gt:18}}, {gender:1}]})
查询年龄大于18或性别为1的学生,并且学生的姓名为gj
db.stu.find({$or[{age:{$gte:18}}, {gender:1}], name:\'gj\'})
*/
$in, $nin # 是否在某个范围内
/*
查询年龄为18,28的学生
db.stu.find({age:{$in:[18, 28]}})
*/
$regex, // # 编写正则表达式
/*
查询姓黄的学生
db.stu.find({name:/^黄/})
db.stu.find({name:{$regex:\'^黄\'}})
*/
$where # 后写一个函数,返回满足条件的数据
/*查询年龄大于20的学生
db.stu.find({$where:function(){return this.age>20}})
*/
limit() # 用于读取指定数量的文档
/*语法:db.集合名称.find().limit(NUMBER)
参数NUMBER表示要获取文档的条数
未指定,则显示集合跌所有文档
例:查询2条学生信息
db.stu.find().limit(2)
*/
skip() # 用于跳过指定数量的文档
/*语法:db.集合名称.find()/skip(NUMBER)
参数number表示跳过的记录条数,默认为0
示例:
查询从第3条开始的学生信息
db.stu.find().skip(2)
方法limit()和skip()可以一起使用,不分先后
sb.stu.find().limit(4).skip(1)
db.stu.find().skip(1).limit(4)
*/
投影 # 在查询的结果中,只选择必要的字段,而不是一个文档的整个字段
/*
参数为字段与值,值1为显示,值0为不显示
db.stu.find({}, {name:1, gender:1})
db.stu.find({}, {_id:0, name:1, gender:1})
*/
sort() # 用于对结果集进行排序
/*
语法:db.集合名称.find().sort({字段1:1, 字段2:-1,...})
参数1为升序,参数-1为降序
db.stu.find().sort({gender:-1, age:1})
*/
count() # 用于统计结果集中文档条数
/*
语法:db.集合名称.find({条件}).count()
db.集合名称.count({条件})
示例:
db.stu.find({gender:1}).count()
db.stu.count({age:{$gt:20}, gender:1})
*/
distinct() # 对数据进行去重
/*
语法:db.集合名称.distinct(\'去重字段\', {条件})
例:查找年龄大于18的性别(去重)
db.stu.distinct(\'gender\', {age:{$gt:18}})
*/
管道命令
linux:将当前命令的输出结果作为下一个命令的输入
mongodb:具有同样作用,文档处理完毕,通过管道进行下一次处理
$group # 将集合的文档分组,可用于统计结果/*
_id表示分组的依据,使用某个字段的格式为\'$字段\'db.stu.aggregate([{$group:{_id:\'$gender\', conter:{$sum:1}}}])
*/
$match # 用于过滤数据,只输出符条件的文档
$project # 修改输入文档的结构,如重命名,增加,删除字段,创建计算结果
$sort # 将输入文档排序后输出
$limit # 限制聚合管道返回的文档数
$skip # 路过指定数量的文档,并返回余下的文档
$limit和$skip # 先写skip,再写limit
$unwind # 将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值
Python与MongoDB交互
安装pymongo模块
pip install pymongo
创建连接
# Python与MongoDB交互--创建连接import pymongo
myclient = pymongo.MongoClient(\'mongodb://localhost:27017/\')
mydb = myclient[\'mydb\']
print(mydb)
myclient.close()
说明:
MongoDB的服务器必须启动才可以连接成功
创建数据库需要使用MongoClient对象,并且指定连接的URL地址和要创建的数据库名
localhost是要连接的主机,也可以用ip地址访问,27017是主机端口号,mydb是要选择的数据库
增删改查
# MongoDB-增删改查import pymongo
def is_having(mydb):
dblist = myclient.list_database_names()
if \'mydb\' in dblist:
print(\'数据库已存在!\')
else:
print(\'数据库不存在!\')
return mydb
def insert(mydb):
stu = mydb[\'stu\']
_id = stu.insert({
\'name\': \'扫地僧\',
\'hometown\':\'少林寺\',
\'age\': 66,
\'gender\': True
})
print(_id)
def select(mydb):
stu = mydb[\'stu\']
ret = stu.find()
for i in ret:
print(i)
def update(mydb):
stu = mydb[\'stu\']
x = stu.update_many({\'age\': {\'$gt\': 20}}, {\'$inc\': {\'age\': 1}})
print(x.modified_count, \'文档已修改\')
def delete(mydb):
stu = mydb[\'stu\']
x = stu.delete_many({\'age\': {\'$gt\': 20}})
print(x.deleted_count, \'个文档已删除\')
myclient.close()
if __name__ == \'__main__\':
myclient = pymongo.MongoClient(\'mongodb://localhost:27017/\')
mydb = myclient[\'mydb\']
is_having(mydb)
insert(mydb)
select(mydb)
update(mydb)
delete(mydb)
myclient.close()
说明:
在MongoDB中,数据库只有在内容插入后才会创建。也就是说,数据库创建后要创建集合(数据表)并插入一个文档(记录),数据库才会真正创建。
MongoClient对象的list_database_names()获取所有数据
爬豆瓣电影,保存到MongoDB
# 爬豆瓣电影-保存到MongoDBimport requests
import random
import time
import threading
import json
import csv
import pymongo
from lxml import etree
from queue import Queue
class DouBanSpider:
\'\'\'爬虫类\'\'\'
def __init__(self):
self.headers = {\'User-Agent\': \'Mozilla/5.0\'}
self.baseURL = \'https://movie.douban.com/top250\'
# MongoDB客户端对象
self.client = pymongo.MongoClient(\'mongodb://localhost:27017/\')[\'mydb\'][\'douban\']
def loadPage(self, url):
\'\'\'向url发送请求,获取响应内容\'\'\'
# 随机休眠0-2秒,避免爬虫过快,会导致爬虫封禁
time.sleep(random.random() * 2)
return requests.get(url, headers=self.headers).content
def parsePage(self, url):
\'\'\'根据起始url提取所有的url\'\'\'
# 获取url对应的响应内容
content = self.loadPage(url)
html = etree.HTML(content)
# 所有电影节点
node_list = html.xpath(\'//div[@class="info"]\')
# 遍历
for node in node_list:
# 使用字典存储数据
item = {}
# 每部电影的标题
item[\'title\'] = node.xpath(\'.//span[@class="title"]/text()\')[0]
# 每部电影的评分
item[\'score\'] = node.xpath(\'.//span[@class="rating_num"]/text()\')[0]
self.client.insert(item)
print(item)
# 只有在第一页时才获取所有url组成的列表,其他页就不获取
if url == self.baseURL:
return [self.baseURL + link for link in html.xpath(\'//div[@class="paginator"]/a/@href\')]
def startWork(self):
\'\'\'开始\'\'\'
print(\'begin....\')
# 第一个页面的请求,需要返回所有页面链接,并提取第一页的电影信息
link_list = self.parsePage(self.baseURL)
thread_list = []
# 循环发送每个页面的请求,并获取所有电影信息
for link in link_list:
# 循环创建了9个线程,每个线程都执行一个任务
thread = threading.Thread(target=self.parsePage, args=[link])
thread.start()
thread_list.append(thread)
# 父线程等待所有子线程结束,自己再结束
for thread in thread_list:
thread.join()
print(\'end...\')
if __name__ == \'__main__\':
# 创建爬虫对象
spider = DouBanSpider()
# 开始爬虫
spider.startWork()
以上是 Python爬虫--数据存储 的全部内容, 来源链接: utcz.com/z/387085.html