昨天是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()