zoukankan      html  css  js  c++  java
  • MongoDB数据库

    爬虫流程:
    1. 发送请求 -- 接收响应数据 -- 解析数据 -- 存储数据
    
    1. requests: 专门用于处理HTTP请求
    -- 对应HTTP的方法: GET,POST
    -- GET 参数拼在地址栏  get(url,headers,params,cookies,timeout,proxies)
    -- POST 参数放在请求体中,cookie and token  post(url,headers,data)
    -- user-agent 两种方式都需要
    
    2. selenium模块: 可以模拟手动操作,点击,滑动等等(动态页面)
    -- 下载对应的浏览器驱动
    -- webDriver.Chrome("驱动路径")
    -- 请求页面 driver.get("url")
    -- 解析数据: css_seletor, xpath
    -- 等待元素加载: 显式等待(有条件,元素是满足某种状态,例如标签可以被点击)
    			    隐式等待(只设置时间)
    -- 动作链: 点击,拖拽等
    
    # 如果系统不带界面,需要配置无 ui模式 , 调入options
    # 关键配置项: 无UI, 取消提示,不加载图片
    
    3. 解析数据: re, bs4, (定位元素)xpath,css_selector 
    -- find_all
    -- 点语法 封装了find_all
    -- find(name="aaa",attr={"id":"xx"},id="xxx",text="",_class="aa")(name标签名)
    -- 过滤器:字符串,正则,数据,函数(自定义过滤规则),布尔
    
    4. 定位元素
    -- css_selector 类名 标签名 id 子类 后代
    -- xpath: //全文范围查找   / 跟标签开始查找  //* 查所有
    		 谓语(限制条件) /a/p[@*] 有属性   /a/p/text()查文本 /a/p[@id='a' and @class]
    		 多路径:/a/p/ | /a/m/
    		 轴: 以某一个标签为起始,以相对方式查找标签 子代,兄弟
    

    MongoDB注意事项

    1. 文档中的键值对是有序的
    2. 文档中的值不仅可以是字符串,还可以是其他几种数据类型, 键可以使用任意UTF-8字符
    3. mongoDB区分类型和大小写
    4. MongoDB文档不能有重复的键
    
    文档键的命名规范:
    1. 键不能含有 (空字符)。这个字符用来表示键的结尾。
    2. . 和$有特别的以,只有在特定环境下才能使用
    3. 以下划线"_" 开头的键是保留的
    
    #下载地址: https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-4.0.8-signed.msi
    

    MongoDB初识

    爬虫的数据存储
    mysql: 关系型数据库,基于硬盘存储
           当并发量太大时,mysql无法支撑,mysql 也支持分布式,但不是是强项
    MongoDB: 高并发,分布式 -- 被应用于大数据领域
             是一款基于c++ 编写的分布式非关系型数据库
             noSQL: not only SQL
             最像关系型的非关系型数据库
    Redis: 数据量小的话,效率高 (轻量级) --- 数据小,并发量高
        
    Why MongoDB?? 数据量非常大
    1. 安装mongodb
    2. 初识MongoDB
    --MongoDB: 集合(文档,类似字典)- 键值对
    -- Mysql: 表(记录) - 字段
    -- 默认端口: 27017
    

    使用MongoDB

    # 进入mongodb
    -- 将mongo.exe 添加到环境变量
    -- mongodb
    # 创建账号
    -- use admin
    --  mongoDB 区分大小写(创建用户): db.createUser({"user":"root","pwd":"123",roles:[{"role":"root","db":"admin"}]}) # user和role也固定, role的value有几个值可以选择: root/readwrite/read
    #  mongod.cfg 配置文件修改
    -- # 开启验证,必须先建账户,注意缩进
    -- #security: 
    --   authorization: enabled
    # 退出,重启服务,登录
    -- 登录方式一: mongo -u "用户名" -p "密码"
    -- 登录方式二: mongo (进入游客模式)
    			  use admin (切换到用户所在的数据库)
        		  db.auth("用户名","密码")  1 成功, 0 失败
    # 小结:
    mongodb 中用不同的数据库来区分权限,创建管理员在admin下创建
    db 是一个全局变量,表示当前的数据库
    db.createUser()是调用一个内部函数用于创建用户
    每个账号可以具备多个角色
    # 测试
    1. 进入mongo,查看数据库
    show dbs
    2. 登录 mongo -u "root" -p "123"
       方式二: use admin
                db.auth("root","123")
    3. 删除账号
    db.dropUser('用户名')
    4. 修改密码
    db.changeUserPassword(用户名,新密码)
    

    修改配置文档mongod.cfg

    首先,将bind_ip改为0.0.0.0 (其他电脑可以访问,用于远程连接,如果bind_ip 是127.0.0.1,就只能本地访问)

    20180725182019556

    基本数据类型

    # 概念上,MongoDB的文档和Javascript 队形相近,类似JSON,JSON(http://www.json.org)是一种简单的数据表示方式:其规范仅用一段文字就能描述清楚(其官网证明了这点),且仅包含六种数据类型。
    # JSON缺点: 
    -- 没有日期类型
    -- 只有一种数字类型,无法区分浮点数和整数
    -- 无法区分32 位和64位
    --无法表示其他一些通用类型,如正则表达式或函数。
    # MongoDB 保留了JSON  基本键/值 对特性的基础上,添加了其他一些数据类型。
    
    MongoDB数据类型:
    #1、null:用于表示空或不存在的字段
    d={'x':null}
    #2、布尔型:true和false
    d={'x':true,'y':false}
    #3、数值
    d={'x':3,'y':3.1415926}
    #4、字符串
    d={'x':'egon'}
    #5、日期
    d={'x':new Date()}
    d.x.getHours()
    #6、正则表达式
    d={'pattern':/^egon.*?nb$/i}
    正则写在//内,后面的i代表:
    i 忽略大小写
    m 多行匹配模式
    x 忽略非转义的空白字符
    s 单行匹配模式
    
    #7、数组
    d={'x':[1,'a','v']}
    
    #8、内嵌文档
    user={'name':'jerry','addr':{'country':'China','city':'YT'}}
    user.addr.country
    
    #9、对象id:是一个12字节的ID,是文档的唯一标识,不可变
    d={'x':ObjectId()}
    #案例:
    db.tb.insert({"a":null,"b":1.1,"c":true,"d":100,"e":"aaaaaa","f":new Date(),"g":/^jerry.*nice$/i,"h":[1,2],"j":{"name":"smallJerry"}})
    

    库的操作

    # 创建数据库,有则切换,无则创建
    use 数据库名
    # 删除数据库
    db.dropDatebase()
    # 查看数据库,如果没有数据,不显示数据库
    show dbs
    
    

    集合的操作

    集合是一个存储元素的容器,类比mysql 中的表
    # 首先进入库
    use mydb
    # 创建集合
    db.user
    # 查看集合,没有数据不显示
    show tables 查看所有集合
    show collections 所有集合
    db.user.info.address  
    
    # 删除集合
    db.user.drop() 删除
    
    db.dropUser("username")   只能登录admin 才能删除
    
    

    文档操作

    # 没有指定_id 则默认objectID, 不能重复,插入后不可变
    # use ttt -新建库   db.user --新建表  然后给表添加数据
    user1 = {
        "name":"iris",
        "age":13,
        "hobbies":["music","read","dance"],
        "addr":{
            "country":"China",
            "city":"biejing"
        }
    }
    # 插入单条
    db.user.insert(user0)  
    # 插入多条
    db.user.insertMany([user1,user2,user3])
    # save 覆盖或插入
    db.user.save(user0)  -- 无则插入,有责覆盖
    db.user.find()
    

    查询数据

    =============================比较运算=============================
    find 查找所有匹配的数据, findone 查第一个
    # = , != , > , < , >= , <=
    #      $ne,  $gt,$lt, $gte,$lte
    # {key:value}  代表相等
    db.user.find({"name":"egon"})
    # 查找除 egon以外
    db.user.find({"name":{"$ne":"egon"}})
    # id 大于2 的
    db.user.find({"_id":{"$gt":2}})
    # id 小于3
    db.user.find("_id":{"$lt":3})
    
    =============================逻辑运算=============================
    # not and or
    # MongoDB中: 多个条件是and 关系, "$or" 的条件放在[]内,"$not"
    # and
    db.user.find({"_id":{"$gte":2,"$lte":4}})
    # or  id>=5 or name="cxx"  (外层$or 套列表)
    db.user.find({
        "$or":[
            {"_id":{"$gte":5}},
            {"name":"cxx"}
        ]
    })
    # 基数,偶数
    db.user.find({"_id":{"$mod":[2,1]}})  -- 基数
    db.user.find("_id":{"$mod":[2,0]})  -- 偶数
    
    # not , 取反
    db.user.find("_id":{"$not":{"$mod":[2,1]}})
    
    =============================成员运算=============================
    # in , not in 
    # $in   $nin
    # age in [20,29,30]
    db.user.find({"age":{"$in":[20,29,30]}})
    # not in 
    db.user.find({"age":{"nin":[20,29,30]}})
    =============================正则匹配=============================
    # 语法 /正则表达式/i
    db.user.find({"name":/^e.*/i})
    
    =============================指定字段显示========================
    db.user.find({"_id":3},{"_id":0,"name":1,"age":1})
    0 表示不显示, 1 为显示, 默认为0
    
    =============================查询数组============================
    # 多个兴趣爱好
    # 有dancing爱好的人
    db.user.find({'hobbies':'dancing '})
    # 有dancing and tea 爱好的人
    db.user.find({
        'hobbies':{
            "$all":['dancing','tea']
        }
    })
    # 第四个爱好是tea的人
    db.user.find({"hobbies.3":"tea"})
    # 查看所有人最后两个爱好
    db.user.find({},{"hobbies":{"$slice":-2},"age":0,"_id":0...})
    # 查看所有人第二个到第三个爱好
    db.user.find({},{"hobbies":"slice":[1,2],"age":0....})
    # db.user.find().pretty()   -- 格式化查询结果
    
    ===============================其他===============================
    # 排序 sort 1 代表升序 -1代表降序
    db.user.find().sort("name":1)
    # 分页:limit代表取多少个文档,skip 代表跳过多少个文档
    db.user.find().sort({"age":1}).limit(1).skip(2)
    # 获取数量
    db.user.find({"age":{"$gt":30}}).count()
    db.user.count({"age":{"$gt":30}})
    
    # 匹配key 的值为null 或者没有这个key
    db.t2.insert({'a':10,'b':111})
    db.t2.insert({'a':20})
    db.t2.insert({'b':null})
    
    db.t2.find({"b":null})  -- 查出后两个结果
    

    修改数据

    update() 用于更新已存在的文档,语法如下:
    db.collection.update(
        <query>,    # 相当where条件
        <update>,   # update的对象和一些更新的操作符(相当set后面的内容)
        {
            upsert:<boolean>,  #默认false,不存在时不更新也不插入
            multi:<boolean>,   # 默认false,只更新找到的第一条记录,true为更新所有
            writeConcern: <document>  # 抛出异常的级别
        }
    )
    =========================================覆盖式=========================================
    #注意:除非是删除,否则_id是始终不会变的
    #1、覆盖式:
    db.user.update({'age':20},{"name":"Wxx","hobbies_count":3})
    是用{"_id":2,"name":"Wxx","hobbies_count":3}覆盖原来的记录
    #2、用一个新的文档完全替换匹配的文档,适用于大规模式迁移的情况
    var obj=db.user.findOne({"_id":2})
    obj.username = obj.name + 'SB'
    obj.hobbies_count++
    delete obj.age
    # 结果: {"_id":2,"name":"Wxx","hobbies_count":4,"username":"WxxSB"}
    db.user.update({"_id":2},obj)
    
    =========================================设置:$set=========================================
    # 1. update db1.user set name='egon' where id=2
    db.user.update({"_id":2},{"$set":{"name":"egon"}})
    # 没匹配成功就新增一条,有就修改set 指定的字段
    db.user.update({"_id":2},{"$set":{"name":"iris","age":38}},{"upsert":true})
    # 匹配多条  {"multi":true}
    db.user.update({"_id":{"$gt":4}},{"$set":{"age":38}},{"multi":true})
     # 修改嵌入文档
    db.user.update({"name":"alex"},{"$set":{"addr.country":"Japan"}})
    # 修改名为alex 的人的第二个爱好成pingpang
    db.user.update({"name":"alex"},{"$set":{"hobbies.1":'pingpang'}})
    # 删除alex 的爱好, $unset
    db.user.update({"name":"alex"},{"$unset":{"hobbies":""}})
    
    =========================================增加和减$inc=====================================
     # 1. 所有人年龄增加一岁
     db.user.update({},
                    {
                        "$inc":{"age":1}
                    },{
                        "multi":true
                    })
        
     #2. 所有人年龄减少2岁
    db.user.update({},
                   {
                       "$inc":{"age":-2}
                   },
                   {
                       "multi":true
                   })
    ========================================= 添加,删除数组元素===============================   
    # 数据添加元素: $push
    # 为alex 添加爱好 read
    db.user.update({"name":"alex"},{"$push":{"hobbies":"read"}})
    #添加多个爱好 tea,dancing ($push, $each)
    db.user.update({"name":"alex"},{"$push":{"hobbies":{"$each":['tea','dancing']}}}
    # 开头或结尾删除元素: $pop
    {"$pop":{"key":1}}  从数组末尾删除一个元素, -1 从头部删除
    db.user.update({"name":"egon"},{"$pop":{"hobbies":1}})
    #按条件删除元素: $pull 把符号条件的统统删除,$pop只能从两端删除
    db.user.update({"addr.country":"China"},{"$pull":{"hobbies":"read"}},{"multi":true})
        
    =====================================避免添加重复:$addToSet===========================
    db.urls.insert({"_id":1,"urls":[]})
    # 更新一条,自动去除重复
    db.urls.update({"_id":1},{"addToSet":{"urls":'http://www.baidu.com'}})
    db.urls.update({"_id":1},{"addToSet":{"urls":'http://www.baidu.com'}})
    # 更新添加多条
                   db.urls.update({"_id":1},{
                       "addToSet":{
                           "urls":{
                               "$each":[
                                  'http://www.baidu.com',
                				'http://www.xxxx.com'    # 出现重复,自动去重
                               ]
                           }
                       }
                   })
    =====================================其他========================================
    #1、了解:限制大小"$slice",只留最后n个
    
    db.user.update({"_id":5},{
        "$push":{"hobbies":{
            "$each":["read",'music','dancing'],
            "$slice":-2
        }
        }
    })
    
    #2、了解:排序The $sort element value must be either 1 or -1"
    db.user.update({"_id":5},{
        "$push":{"hobbies":{
            "$each":["read",'music','dancing'],
            "$slice":-1,
            "$sort":-1
        }
        }
    })
    
    #注意:不能只将"$slice"或者"$sort"与"$push"配合使用,且必须使用"$eah"
                   
    

    删除数据

    # 删除多个中的一个
    db.user.deleteOne({'age':19})
    # 删除满足条件的多个
    db.user.deleteMany({"addr.country":"China"})
    # 删全部
    db.user.deleteMany({})
    
    

    Mongo DB 数据库

    
    # 用户管理 --- 登录(先创建用户在修改配置文件)
    
    
    --
    
    MongoDB 命令使用:
    
    
    # use admin: 切换数据库,如果不存在会自动创建
    db: 当前数据库
    db.user  相当建了一个表
    db.user.insert({"_id":1,"name":"egon"})
    show tables  -- show dbs
    exit 退出
    db.help 查看帮助信息
    db.dropDatabase()  删除数据库
    
    
    
    
    
    记录的操作
    db.user.insertMany([
        {"_id":3,"name":"octivia"},
        {"_id":4,"name":"lily"}
    ])
    db.user.find() -- 查询所有 == select * from user
    
    db.user.find({"name":"octivia","_id":3})  -- 条件可单可多
    
    
    
    
    
    
        
    save()
    db.user.save({"_id":6,"name":"clerk"})  # 如果id存在就覆盖,id不同就新增
    
    mongoDB的语法就是JS 语法,所以json支持的数据类型mongo都支持
    字符串,整型,浮点,列表,字典,布尔(小写), new Date(), /^a.*c$/i
    
    

    _id和ObjectId

    """
    MongoDB中存储的文档必须有一个"_id"键。这个键的值可以是任意类型,默认是个ObjectId对象。
    在一个集合里,每个文档都有唯一的“_id”,确保集合里每个文档都能被唯一标识。
    不同集合"_id"的值可以重复,但同一集合内"_id"的值必须唯一
    
    #1、ObjectId
    ObjectId是"_id"的默认类型。因为设计MongoDb的初衷就是用作分布式数据库,所以能够在分片环境中生成
    唯一的标识符非常重要,而常规的做法:在多个服务器上同步自动增加主键既费时又费力,这就是MongoDB采用
    ObjectId的原因。
    ObjectId采用12字节的存储空间,是一个由24个十六进制数字组成的字符串
        0|1|2|3|   4|5|6|     7|8    9|10|11    
        时间戳      机器      PID    计数器
    如果快速创建多个ObjectId,会发现每次只有最后几位有变化。另外,中间的几位数字也会变化(要是在创建过程中停顿几秒)。
    这是ObjectId的创建方式导致的,如上图
    
    时间戳单位为秒,与随后5个字节组合起来,提供了秒级的唯一性。这个4个字节隐藏了文档的创建时间,绝大多数驱动程序都会提供
    一个方法,用于从ObjectId中获取这些信息。
    
    因为使用的是当前时间,很多用户担心要对服务器进行时钟同步。其实没必要,因为时间戳的实际值并不重要,只要它总是不停增加就好。
    接下来3个字节是所在主机的唯一标识符。通常是机器主机名的散列值。这样就可以保证不同主机生成不同的ObjectId,不产生冲突
    
    接下来2个字节确保了在同一台机器上并发的多个进程产生的ObjectId是唯一的
    
    前9个字节确保了同一秒钟不同机器不同进程产生的ObjectId是唯一的。最后3个字节是一个自动增加的 计数器。确保相同进程的同一秒产生的
    ObjectId也是不一样的。
    
    #2、自动生成_id
    如果插入文档时没有"_id"键,系统会自帮你创建 一个。可以由MongoDb服务器来做这件事。
    但通常会在客户端由驱动程序完成。这一做法非常好地体现了MongoDb的哲学:能交给客户端驱动程序来做的事情就不要交给服务器来做。
    这种理念背后的原因是:即便是像MongoDB这样扩展性非常好的数据库,扩展应用层也要比扩展数据库层容易的多。将工作交给客户端做就
    减轻了数据库扩展的负担。
    """
    0|1|2|3|       4|5|6|             7|8        9|10|11    
     时间戳          机器              PID         计数器
    秒级的唯一性    主机的唯一标识符    不同进程     自动增加的 计数器
    
  • 相关阅读:
    Gridview常用操作
    在DataGridView列中嵌入ComboBox(vb.net版)【原创】
    使用net创建Access存储过程
    C博客作业00我的第一篇博客 1911
    C博客作业01分支、顺序结构 1911
    Lazy load image for listview and beging separate thread
    Android Send Email
    MySQL修复表数据
    Insertion and Deletion of Calendar Events
    TechCrunch:移动社交应用开创社交网络新格局
  • 原文地址:https://www.cnblogs.com/Afrafre/p/10712515.html
Copyright © 2011-2022 走看看