Fork me on Gitee

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.1
protected-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的进程id
sudo kill -9 redis的进程id

命令操作

Redis地理位置命令

geoadd # 将指定的地理空间位置(纬度,经度,名称添加到指定的key中)
geodist  # 返回两个给定位置之间的距离
geohash  # 返回一个或多个位置元素的Geohash表示
geopos  # 从key中返回所有给定位置元素的位置
georadius  # 以给定的经纬度为中心,找出某一半径内的元素
georadiusbymember # 找出位于指定范围内的元素中心点由给定的位置元素决定

Redis键(key)命令

del  # 该命令用于在key存在时删除key
dump  # 序列化给定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=27017
dbpath=/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/mongod
sudo 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 mydb
db.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

# 爬豆瓣电影-保存到MongoDB

import 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()
posted @ 2021-09-26 12:43  Veryl  阅读(146)  评论(0编辑  收藏  举报
动态线条
动态线条end