昨天是mongoDB的初步了解,今天是进一步的提高使用,聚合查询,索引操作,以及备份,恢复操作。另外,简单介绍一下,反爬虫,反反爬虫。。。
聚合查询
- 聚合查询是指,利用mongoDB自带的管道以及,方法进行链式查询想要的数据的过程。用于较为复杂的查询需求。
查询一般形式:
db.<集合名>.aggregate($管道名:{表达式})
链式操作:因为支持管道(前一个运行的结果可以作为后一个的输入),所以,可以调用多个管道方法,注意,他们是单向的。
常用的管道
- match:匹配表达式需求的结果,与find()相同,返回所有匹配的数据
- group: 分组,就是按照表达式给的条件对所有数据进行分组,返回匹配的数据
- sort:排序,注意 1 代表升序,-1代表降序,返回数据
- project: 相当于昨天的投影,表是选择想要显示的内容,返回数据
- skip:跳过几个数据,返回剩下的所有
- limmit:限制返回前几条数据
unwind:将数据列表分隔,返回分隔后的数据
常用的表达式
- sum:求和
- avg:求平均数
- max:求最大值
- min:求最小值
- push: 在结果文档中插入想要显示的值
- first:显示查询的文档中的第一条数据
- last:显示查询的文档中的 最后一条数据
试例:
db.xx.aggregate(
[
{管道1},
{管道2},
{...}
]
)
$group: 分组
// 数据按照 性别分组
db.stu.aggregate(
[
{$group:{_id:"$gender"}}
]
)
db.stu.aggregate(
{$group:{_id:"$gender",avg_age:{$avg:"$age"}}}
)
// 表达式: $sum $avg $first $last $max $min $push
// 数据按照 性别分组 求年龄的平均值
db.stu.aggregate(
{$group:{_id:"$gender", avg_age:{$avg:"$age"}}}
)
db.stu.aggregate(
{$group:{_id:"$gender", avg_age:{$avg:"$age"},sum_age:{$sum:"$age"}}}
)
// 按照籍贯分组, 求年龄和
db.stu.aggregate(
{$group:{_id:"$hometown", age_sum:{$sum:"$age"}}}
)
db.stu.aggregate(
{$group:{_id:"$gender", age_sum:{$max:"$age"}}}
)
db.stu.aggregate(
{$group:{_id:"$gender",all_name:{$push:"$name"}}}
)
// $push 将分组想取出来的数据 放入到一个列表
// 取出 按照年龄分组的 所有人的名字
db.stu.aggregate(
{$group:{_id:"$gender", name_list:{$push:"$age"}}}
)
$match: 查找符合条件的数据 ; find 区别
// 区别 : $match可以使用管道 ; find 不可以
// 取出年龄大于20人
db.stu.find({age:{$gt:20}})
db.stu.aggregate(
{
$match:{age:{$gt:20}}
}
)
// 取出年龄小于40的; 按照性别分组 求年龄平均值($avg)
db.stu.aggregate(
{$match:{age:{$lt:40}}},
{$group:{_id:"$gender", avg_age:{$avg:"$age"}}}
)
$project:投影取出部分字段; 显示1 不显示0
// 取出年龄大于20; 按照籍贯分组 求出年龄之和; 查看的时候只想看到之和
db.stu.aggregate(
{$match:{age:{$gt:20}}},
{$group:{_id:"$hometown", age_sum:{$sum:"$age"}}},
{$project:{_id:1, age_sum:1}}
)
db.stu.aggregate(
{$match:{age:{$gt:20}}},
{$group:{_id:"$hometown",age_sum:{$sum:"$age"}}},
{$project:{age_sum:0}}
)
$sort: 排序 1升序 -1降序
//先找 45以下 ;再 安籍贯 求平均值, 在 降序, 在投影
db.stu.aggregate(
{$match:{age:{$lt:45}}},
{$group:{_id:"$hometown", avg_age:{$avg:"$age"}}},
{$sort:{avg_age:-1}},
{$project:{_id:1,avg_age:1}}
)
//注意点: 管道是有顺序的 不能随意颠倒; 根据需求
$skip 跳过几个查看
$limit 允许显示几个
db.stu.aggregate(
{$match:{age:{$lt:60}}},
{$skip:2}
)
db.stu.aggregate(
{$match:{age:{$lt:60}}},
{$limit:3}
)
db.stu.aggregate(
{$match:{age:{$lt:60}}},
{$limit:3},
{$skip:2}
)
db.stu.aggregate(
{$match:{age:{$lt:60}}},
{$skip:2},
{$limit:3}
)
$unwind :将数据列表 分割
//按照 年龄分组, 求出人的名字
db.stu.aggregate(
{$group:{_id:"$gender", name_list:{$push:"$name"}}},
{$unwind:"$name_list"}
)
db.stu.aggregate(
{$group:{_id:"$gender", name_list:{$push:"$name"}}}
)
索引操作
- 索引就是一种以供数据查询结构。有索引的数据集合查询速度会比没有索引的数据集合查询速度快得多。
- mongoDB以及其他数据库中,一般id字段就是一个可供索引查询的字段
- 有时候id一个字段的索引不够使用,这时候,我们就需要给其他字段自定义索引,在mongoDB中,使用ensureIndex({<字段>:1>})来添加索引
代码
1. 创建批量的数据
for (var index = 0; index < 200000; index++) {
db.new.insert({_id:index,name:"name"+index,age:index})
}
db.new.find({name:"name19999"}).explain("executionStats")
db.new.find({_id:"19999"}).explain("executionStats")
2. 查看 数据的时间 对比
db.stu.find({name:"值"}).explain("executionStats")
2.1 查询 name:; -->executionTimeMillis 114毫秒
db.stu.find({name:"name199999"}).explain("executionStats")
2.2 查询 _id: 不足1毫秒 显示都是0
db.stu.find({_id:"199999"}).explain("executionStats")
2.3 查询 age: --> 108毫秒
db.stu.find({age:"199999"}).explain("executionStats")
3. 设置 ID索引ensureIndex
//查询时间 --> 4毫秒
db.stu.ensureIndex({name:1})
// 查询时间 ---> 0毫秒
db.stu.ensureIndex({age:1})
4. 删除 自定义的索引
//查询所有的 索引
db.stu.getIndexes()
db.stu.dropIndex("name_1")
备份&恢复备份
- 数据库的备份很重要,定期,有计划的备份数据库数据,可以保证整体数据的完整性,以防因为服务器的崩溃,异常操作,造成数据的损坏或者丢失。
- 在mongoDB中,备份以及恢复就是两行代码
-h host IP:prot
-d 数据库的名字
-o 路径备份的路径
--dir 从哪个位置 恢复
备份 sudo mongodump -h "127.0.0.1:27017" -d stu -o /Users/lpf/Desktop/save
恢复 sudo mongorestore -h '127.0.0.1:27017' -d stu(可以改) --dir /Users/lpf/Desktop/save/stu
反爬虫
学习爬虫很开心,可以爬到自己想要的目标数据,但是,作为服务器的一方。大量的数据就是他们的资源,他们想被正常的用户,按照正常的流程访问,不想被爬虫程序,自动化,大规模的一次性获取。那么,有些公司就会针对这些爬虫程序进行反爬虫处理。
反爬的方式包括单不限于
- 对客户端访问频次的限制
- 对请求参报文的参数进行校验(User-Agent, Host, refrence)
- 需要请求携带cookie进行校验
- 验证码
- js加密
- 对确认的爬虫程序,在真数据中混合一定量的假数据
。。。。。
反反爬虫
对应有爬虫需求的个人或者集体,当然不会善罢甘休。针对反爬虫的各种设置,也会有相应的对策反击。
反反爬虫的方式包括但不限于:
- 模拟正常的浏览器设置尽可能完整的请求报文(User-Agent,Host,refrence等)
- 使用代理iP池
- 代码模拟登陆获取cookie之后再次自动发起请求
- 调用第三方SDK进行验证码破解
- 内置浏览器引擎
。。。。
理论上讲,只要允许人类正常访问网页,在具有同等资源的情况下,就一定可以爬取到数据。
试例:爬取拉钩网
# !/usr/bin/env python
# _*_ coding:utf-8 _*_
import requests
import json
import jsonpath
import time
class Lagou_Spider(object):
def __init__(self):
self.base_url = "https://www.lagou.com/jobs/positionAjax.json"
self.headers = {
# "Accept": "application/json, text/javascript, */*; q=0.01",
# "Accept-Encoding": "gzip, deflate",
# "Accept-Language": "zh-CN,zh;q=0.9",
# "Connection": "keep-alive",
# "Content-Length": "26",
# "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Cookie": "_ga=GA1.2.1816814429.1523233263; user_trace_token=20180409082107-e5707f68-3b8b-11e8-b740-525400f775ce; LGUID=20180409082107-e5708220-3b8b-11e8-b740-525400f775ce; index_location_city=%E4%B8%8A%E6%B5%B7; _gid=GA1.2.32723810.1523785814; JSESSIONID=ABAAABAAADEAAFIEDDFFB9439BE07D678FAB49E50F70C18; _gat=1; LGSID=20180416120202-eb176a7e-412a-11e8-8701-525400f775ce; PRE_UTM=; PRE_HOST=; PRE_SITE=; PRE_LAND=https%3A%2F%2Fwww.lagou.com%2F; Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1523233263,1523330589,1523785815,1523851325; SEARCH_ID=e227261560fc49ad89d40936beab9504; Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1523851329; LGRID=20180416120209-ef3820d9-412a-11e8-b896-5254005c3644; TG-TRACK-CODE=search_code",
# "Host": "www.lagou.com",
# "Origin": "https://www.lagou.com",
"Referer": "https://www.lagou.com/jobs/list_python?labelWords=sug&fromSearch=true&suginput=p",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
# "X-Anit-Forge-Code": "0",
# "X-Anit-Forge-Token": "None",
# "X-Requested-With": "XMLHttpRequest",
}
# user-池子
# IP代理池子
# 限制频率
# cookit referer host
def send_request(self):
# 拼接参数
params = {
"city": "上海",
"needAddtionalResult": "false"
}
formdatas = {
"first": "true",
"pn": 1,
"kd": "python"
}
# 5.发送请求
try:
response = requests.post(url=self.base_url, params=params, data=formdatas, headers=self.headers
)
# 只有是返回的是json文件才可以使用
data = response.json()
return data
except Exception, err:
print err
def analysis_data(self, data):
pass
def write_file(self, data):
print "[INFO]写入完毕..."
json.dump(data, open("3lagou.html", "w"))
def run(self):
data = self.send_request()
# 解析数据
# self.analysis_data(data)
self.write_file(data)
if __name__ == '__main__':
tool = Lagou_Spider()
tool.run()