【Python爬虫】第11篇:Mongodb数据库进阶使用。从0到scrapy高手笔记(附代码,可自取)

举报
程序员一诺112 发表于 2023/11/28 19:06:31 2023/11/28
【摘要】 在前面的本文中我们学习了mysql这种关系型数据库,那么接下来,我们会来学习一种非关系型数据库mongodb,mongodb数据库主要用于海量存储,常被用在数据采集项目中。

本文主要学习一下关于爬虫的相关前置知识和一些理论性的知识,通过本文我们能够知道什么是爬虫,都有那些分类,爬虫能干什么等,同时还会站在爬虫的角度复习一下http协议。


全套笔记和代码自取地址: 请移步这里

感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~



共 8 章,37 子模块





Mongodb数据库




介绍


在前面的本文中我们学习了mysql这种关系型数据库,那么接下来,我们会来学习一种非关系型数据库mongodb,mongodb数据库主要用于海量存储,常被用在数据采集项目中。


内容


  • mongodb的介绍和安装

  • mongodb的简单使用

  • mongodb的增删改查

  • mongodb的聚合操作

  • mongodb的索引操作

  • mongodb的权限管理

  • mongodb和python交互(pymongo模块)


mongodb文档


https://docs.mongodb.com/


mongodb的聚合操作




学习目标


  1. 了解 mongodb的聚合原理

  2. 掌握 mongdb的管道命令

  3. 掌握 mongdb的表达式


1 mongodb的聚合是什么


聚合(aggregate)是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。

语法:db.集合名称.aggregate({管道:{表达式}})


2 mongodb的常用管道和表达式


知识点:

  • 掌握mongodb中管道的语法

  • 掌握mongodb中管道命令


2.1 常用管道命令


在mongodb中,⽂档处理完毕后, 通过管道进⾏下⼀次处理 常用管道命令如下:

  • $group: 将集合中的⽂档分组, 可⽤于统计结果

  • $match: 过滤数据, 只输出符合条件的⽂档

  • $project: 修改输⼊⽂档的结构, 如重命名、 增加、 删除字段、 创建计算结果

  • $sort: 将输⼊⽂档排序后输出

  • $limit: 限制聚合管道返回的⽂档数

  • $skip: 跳过指定数量的⽂档, 并返回余下的⽂档


2.2 常用表达式


表达式:处理输⼊⽂档并输出 语法:表达式:'$列名' 常⽤表达式:

  • $sum: 计算总和, $sum:1 表示以⼀倍计数

  • $avg: 计算平均值

  • $min: 最⼩值

  • $max: 最⼤值

  • $push: 在结果⽂档中插⼊值到⼀个数组中


3 管道命令之$group




3.1 按照某个字段进行分组


$group是所有聚合命令中用的最多的一个命令,用来将集合中的文档分组,可用于统计结果

使用示例如下

db.stu.aggregate(
    {$group:
        {
            _id:"$gender",
            counter:{$sum:1}
        }
    }
)


其中注意点:

  • db.db_name.aggregate是语法,所有的管道命令都需要写在其中

  • _id 表示分组的依据,按照哪个字段进行分组,需要使用$gender表示选择这个字段进行分组

  • $sum:1 表示把每条数据作为1进行统计,统计的是该分组下面数据的条数


3.2 group by null


当我们需要统计整个文档的时候,$group 的另一种用途就是把整个文档分为一组进行统计

使用实例如下:

db.stu.aggregate(
    {$group:
        {
            _id:null,
            counter:{$sum:1}
        }
    }
)


其中注意点:

  • _id:null 表示不指定分组的字段,即统计整个文档,此时的counter表示整个文档的个数


3.3 数据透视


正常情况在统计的不同性别的数据的时候,需要知道所有的name,需要逐条观察,如果通过某种方式把所有的name放到一起,那么此时就可以理解为数据透视

使用示例如下:

  1. 统计不同性别的学生

db.stu.aggregate(
     {$group:
         {
             _id:null,
             name:{$push:"$name"}
         }
     }
 )


  1. 使用$$ROOT可以将整个文档放入数组中

db.stu.aggregate(
     {$group:
         {
             _id:null,
             name:{$push:"$$ROOT"}
         }
     }
 )




3.4 动手


对于如下数据,需要统计出每个country/province下的userid的数量(同一个userid只统计一次)

{ "country" : "china", "province" : "sh", "userid" : "a" }  
{  "country" : "china", "province" : "sh", "userid" : "b" }  
{  "country" : "china", "province" : "sh", "userid" : "a" }  
{  "country" : "china", "province" : "sh", "userid" : "c" }  
{  "country" : "china", "province" : "bj", "userid" : "da" }  
{  "country" : "china", "province" : "bj", "userid" : "fa" }


参考答案

db.tv3.aggregate(
  {$group:{_id:{country:'$country',province:'$province',userid:'$userid'}}},
  {$group:{_id:{country:'$_id.country',province:'$_id.province'},count:{$sum:1}}}



4 管道命令之$match


$match用于进行数据的过滤,是在能够在聚合操作中使用的命令,和find区别在于$match 操作可以把结果交给下一个管道处理,而find不行

使用示例如下:

  1. 查询年龄大于20的学生

db.stu.aggregate(
     {$match:{age:{$gt:20}}
     )


  1. 查询年龄大于20的男女学生的人数

db.stu.aggregate(
     {$match:{age:{$gt:20}}
     {$group:{_id:"$gender",counter:{$sum:1}}}
     )




5 管道命令之$project


$project用于修改文档的输入输出结构,例如重命名,增加,删除字段

使用示例如下:

  1. 查询学生的年龄、姓名,仅输出年龄姓名

db.stu.aggregate(
     {$project:{_id:0,name:1,age:1}}
     )


  1. 查询男女生人生,输出人数

db.stu.aggregate(
     {$group:{_id:"$gender",counter:{$sum:1}}}
     {$project:{_id:0,counter:1}}
     )




5.1 动手练习


对于如下数据:统计出每个country/province下的userid的数量(同一个userid只统计一次),结果中的字段为{country:"",province:"",counter:"*"}

{ "country" : "china", "province" : "sh", "userid" : "a" }  
{  "country" : "china", "province" : "sh", "userid" : "b" }  
{  "country" : "china", "province" : "sh", "userid" : "a" }  
{  "country" : "china", "province" : "sh", "userid" : "c" }  
{  "country" : "china", "province" : "bj", "userid" : "da" }  
{  "country" : "china", "province" : "bj", "userid" : "fa" }


参考答案

db.tv3.aggregate(
  {$group:{_id:{country:'$country',province:'$province',userid:'$userid'}}},
  {$group:{_id:{country:'$_id.country',province:'$_id.province'},count:{$sum:1}}},
  {$project:{_id:0,country:'$_id.country',province:'$_id.province',counter:'$count'}}
  )



6 管道命令之$sort


$sort用于将输入的文档排序后输出

使用示例如下:

  1. 查询学生信息,按照年龄升序

db.stu.aggregate({$sort:{age:1}})


  1. 查询男女人数,按照人数降序

db.stu.aggregate(
     {$group:{_id:"$gender",counter:{$sum:1}}},
     {$sort:{counter:-1}}
 )




7 管道命令之$skip$limit


  • $limit限制返回数据的条数

  • $skip 跳过指定的文档数,并返回剩下的文档数

  • 同时使用时先使用skip在使用limit

使用示例如下:

  1. 查询2条学生信息

db.stu.aggregate(
     {$limit:2}
 )


  1. 查询从第三条开始的学生信息

db.stu.aggregate(
     {$skip:3}
 )


  1. 统计男女生人数,按照人数升序,返回第二条数据

db.stu.aggregate(
     {$group:{_id:"$gender",counter:{$sum:1}}},
     {$sort:{counter:-1}},
     {$skip:1},
     {$limit:1}
 )




8 小结


  1. 理解聚合操作的是在干什么

  2. 掌握$group,$match,$project的使用

  3. 熟悉$sort,$limit,$skip的使用

  4. 实现常用的表达式


Mongodb的索引操作




学习目标


  1. 掌握 mongodb索引的创建,删除操作

  2. 掌握 mongodb查看索引的方法

  3. 掌握 mongodb创建唯一索引的方法



1. 为什么mongdb需要创建索引


  • 加快查询速度

  • 进行数据的去重


2. mongodb创建简单的索引方法


  • 语法:db.集合名.ensureIndex({属性:1}),1表示升序, -1表示降序


3. 创建索引前后查询速度对比


测试:插入10万条数据到数据库中

插入数据:

for(i=0;i<100000;i++){db.t1.insert({name:'test'+i,age:i})}


创建索引前:

db.t1.find({name:'test10000'})
db.t1.find({name:'test10000'}).explain('executionStats') # 显示查询操作的详细信息


创建索引:

db.t1.ensureIndex({name:1})


创建索引后:

db.t1.find({name:'test10000'}).explain('executionStats')


前后速度对比


4. 索引的查看


默认情况下_id是集合的索引 查看方式:db.集合名.getIndexes()


5. 删除索引


语法:db.集合名.dropIndex({'索引名称':1})

db.t1.dropIndex({name:1})
db.t1.getIndexes()



6. mongodb创建唯一索引


在默认情况下mongdb的索引域的值是可以相同的,创建唯一索引之后,数据库会在插入数据的时候检查创建索引域的值是否存在,如果存在则不会插入该条数据,但是创建索引仅仅能够提高查询速度,同时降低数据库的插入速度。


6.1 添加唯一索引的语法:


db.集合名.ensureIndex({"字段名":1}, {"unique":true})



6.2 利用唯一索引进行数据去重


根据唯一索引指定的字段的值,如果相同,则无法插入数据

db.t1.ensureIndex({"name":1}, {"unique":true})
db.t1.insert({name: 'test10000'})



7. 建立复合索引


在进行数据去重的时候,可能用一个域来保证数据的唯一性,这个时候可以考虑建立复合索引来实现。

例如:抓全贴吧信息,如果把帖子的名字作为唯一索引对数据进行去重是不可取的,因为可能有很多帖子名字相同

建立复合索引的语法:db.collection_name.ensureIndex({字段1:1,字段2:1})


8. 建立索引注意点


  • 根据需要选择是否需要建立唯一索引

  • 索引字段是升序还是降序在单个索引的情况下不影响查询效率,但是带复合索引的条件下会有影响

  • 数据量巨大并且数据库的读出操作非常频繁的时候才需要创建索引,如果写入操作非常频繁,创建索引会影响写入速度

例如:在进行查询的时候如果字段1需要升序的方式排序输出,字段2需要降序的方式排序输出,那么此时复合索引的建立需要把字段1设置为1,字段2设置为-1



课后思考


数据库为什么要做读写分离(读写分离的意义)?


小结


  1. 掌握mongodb索引的创建,删除操作

  2. 掌握mongodb查看索引的方法

  3. 掌握mongodb创建唯一索引的方法



Mongodb的权限管理




学习目标


1.了解 mongodb的权限管理



1. 为什么要进行权限管理的设置


刚安装完毕的mongodb默认不使用权限认证方式启动,与MySQL不同,mongodb在安装的时候并没有设置权限,然而公网运行系统需要设置权限以保证数据安全,所以我们要学习mongodb的权限管理


2. mongodb的权限管理方案


  • MongoDB是没有默认管理员账号,所以要先添加管理员账号,并且mongodb服务器需要在运行的时候开启验证模式

    • 用户只能在用户所在数据库登录(创建用户的数据库),包括管理员账号。

    • 管理员可以管理所有数据库,但是不能直接管理其他数据库,要先认证后才可以。



3. mongodb超级管理员账号的创建




3.1 创建超级用户


进入mongo shell

sudo mongod


使用admin数据库(超级管理员账号必须创建在该数据库上)

use admin


创建超级用户

db.createUser({"user":"python","pwd":"python","roles":["root"]})


创建成功会显示如下信息

Successfully added user: { "user" : "python", "roles" : [ "root" ] }


退出mongo shell

exit



3.2 以权限认证的方式启动mongodb数据库


sudo mongod --auth


启动之后在启动信息中会有如下信息,说明mongodb以权限认证的方式启动成功

[initandlisten] options: { security: { authorization: "enabled" } }



3.3 登录验证


此时再使用数据库各命令的时候会报权限错误,需要认证才能执行相应操作、

use admin
db.auth('python','python')


  • python用户是创建在admin数据库上的所以必须来到admin数据库上进行认证

  • 认证成功会返回1,失败返回0


4. 创建普通用户




4.1 在使用的数据库上创建普通用户


1.选择需要创建用户的数据库

use test1


  1. 创建用户

db.createUser("user":"user1", "pwd":"pwd1", roles:["read"])
创建普通用户user1,该用户在test1上的权限是只读
db.createUser("user":"user1", "pwd":"pwd1", roles:["readWrite"])
创建普通用户user1,该用户在test1上的权限是读写




4.2 在admin用户数据库上创建普通用户


use admin
db.createUser({"user":"python1", "pwd":"python1", roles:[{"role":"read","db":"dbname1"},{"role":"readWrite","db":"dbname2"}
]})


在admin上创建python1用户,python1用户的权限有两个,一个再dbname1上的只读,另一个是在dbname2上的读写


5. 查看创建的用户


show users
{
    "_id" : "admin.python",
    "user" : "python",
    "db" : "admin",
    "roles" : [
        {
            "role" : "root",
            "db" : "admin"
        }
    ]
}



6. 删除用户




6.1 进入账号数据所在的数据库


use db_name



6.2 删除用户


db.dropUser('python')



小结


  1. 了解mongodb的权限管理

  2. 熟悉创建用户的相应流程




未完待续, 同学们请等待下一期


全套笔记和代码自取地址: 请移步这里

感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。