逆向爬虫14 Mongo入门

逆向爬虫14 Mongo入门

一、MongoDB和MySQL的区别

MongoDB 是一种 非关系型数据库,存放任意形式的 json 格式数据;而 MySQL 是一种 关系型数据库,只能存放事先定义好 字段 的表格数据。下面是 MongoDBMySQL 对数据叫法不同的比较。

MySQLMongoDB
数据库(文件夹)数据库(文件夹)
表(文件,不同的表之间可以有关系)集合(文件,不同的集合之间没有关系)
记录(表格的一行)文档(一个json格式数据)

二、何时使用关系型?何时使用非关系型?

关系型数据库 比较合适用于需要对数据进行业务逻辑开发的场景,大量应用于Web全栈开发中,用户通过前端将信息提交给后端,后端再通过业务逻辑处理后,将需要存储的数据保存到 关系型数据库 中;当用户在前端申请查看信息后,后端从 关系型数据库 中读取数据,经业务逻辑处理后,发送给前端,再经过前端渲染后呈现在用户面前。在这个过程中,数据库中所存放的内容,严格的受到业务逻辑的控制,因此在创建数据库之前,就需要根据业务逻辑先确定每一张表的字段名,不同表之间的关系,这些关系确定好后就很少再会变动,除非业务逻辑需要。

非关系型数据库 相比于 关系型数据库 来说使用起来更为方便,即插即用。使用前无需事先确定字段,表与表关系等信息。数据格式只要满足 json 就可以存储。这对于需要存储大量不规则数据来说方便极了,爬虫所爬的每个网站的数据都是没有标准统一的,如果使用 关系型数据库,在数据入库之前,就需要针对每一个网站需要爬取的不同信息,新建一张表。而 非关系型数据库 则无需这步操作,获取到数据后整理成 json 格式后即可以插入到数据库,十分方便。

因此,在只需要保存数据,且无需对数据进行业务逻辑处理的业务场景下,使用 非关系型数据库 更为合适,这也是我们要学习 MongoDB 的原因。

三、MongoDB的简单使用(了解)

MongoDB的安装这里就不赘述了,网上到处都有。这里直接进入正题。

show dbs			显示所有数据库(简写)
show databases		显示所有数据库(全写)
db					查看当前使用的数据库
use xxx				切换数据库
db.dropDatabase()	删除数据库
show collections	显示当前数据库中所有的集合
db.collection_name.insert({})	往集合中插入一条数据{}中放json格式数据,如果集合不存在则创建,且没有大小限制
db.createCollection(name, {options})	手动创建集合,可以增加options来限制集合,下面给个例子
db.createCollection("xxx_log", {capped:true, size:255})		capped:是否卷动, size:大小
上面这种创建方式特别适合用来存放日志类型的数据,当日志数据大于size大小后,会自动清除时间最早的数据,插入最新的数据
db.collection_name.isCapped()	判断集合是否有容量上限

四、MongoDB的增删改查

1. mongodb中常见的数据类型(了解)

Object ID: 主键ID
String: 字符串
Boolean: 布尔值
Integer: 数字
Double: 小数
Arrays: 数组
Object: 文档(关联其他对象) {sname: 李嘉诚, sage: 18, class: {cccc}}
Null: 空值
Timestamp: 时间戳
Date: 时间日期

2. mongodb添加数据

db.collection_name.insert({字段1:值1, 字段2:值2})
db.student.insert({name: '周杰伦', age: 18, hobby: ['哎哟,不错哦!', '耍酷']})

注意:如果集合不存在会自动创建

3. mongodb修改数据

3.1 update更新
db.collection_name.update({查询条件}, {待修改内容}, {multi: false, upsert: true})
multi 默认为false,只会修改一条数据
upsert 默认为true,待修改内容中如果存在新的数据则添加进去
db.student.update({name: '周杰伦'}, {$set: {title: '华语流行天王', age: 16}})

s e t 和 没 有 set和没有 setset的区别:

​ $set只会修改当前给出的字段,其他内容保留

​ 没有$set只会保留当前给出字段,其他内容删除

multi如果为true,必须使用$set,否则报错。

3.2 保存(save,了解)
db.collection_name.save({待保存的数据})
db.student.save({name: '王力宏', age: 188})

相当于新增了一条王力宏数据,如果待保存数据中包含已经存在数据的’_id’信息,则相当于update功能

4. mongodb删除数据

4.1 remove()
db.collection_name.remove({条件}, {justOne: true|false})
db.student.remove({name: '王力宏'}, {justOne: true})
4.2 deleteOne()
db.collection_name.deleteOne({条件})
db.student.deleteOne({name: '蔡依林'})
4.3 deleteMany()
db.collection_name.deleteMany({条件})
db.student.deleteMany({type: '歌手'})

5. mongodb查询数据

准备数据:

db.student.insert([
	{name: "朱元璋", age:800, address:'安徽省凤阳', score: 160},
	{name: "朱棣", age:750, address:'江苏省南京市', score: 120},
	{name: "朱高炽", age:700, address:'北京紫禁城', score: 90},
	{name: "李嘉诚", age:38, address:'香港xxx街道', score: 70},
	{name: "麻花藤", age:28, address:'广东省xxx市', score: 80},
	{name: "大老王", age:33, address:'火星第一卫星', score: -60},
	{name: "咩咩", age:33, address:'开普勒225旁边的黑洞', score: -160}
])
5.1 普通查询
db.student.find()		查询所有
db.student.findOne()	查询一个
db.student.find({条件})  条件查询
5.2 比较运算
等于:默认是等于判断,$eq
小于:$lt (less than)
小于等于:$lte (less than equal)
大于:$gt (greater than)
大于等于:$gte (greater than equal)
不等于:$ne (not equal)
db.student.find({age:28})			// 查询年龄为28的学生
db.student.find({age:{$eq:28}})		// 查询年龄为28的学生
db.student.find({age:{$gt:28}})		// 查询年龄大于28的学生
db.student.find({age:{$gte:28}})	// 查询年龄大于等于28的学生
db.student.find({age:{$lt:38}})		// 查询年龄小于38的学生
db.student.find({age:{$lte:38}})	// 查询年龄小于等于38的学生
db.student.find({age:{$ne:38}})		// 查询年龄不等于38的学生
5.3 逻辑运算符
  1. and

    $and: [条件1,条件2,条件3]

查询年龄等于33,并且,名字是'大老王'的学生
db.student.find({$and: [{age: {$eq:33}}, {name: '大老王'}]})
  1. or

    $or: [条件1,条件2,条件3]

查询名字叫'李嘉诚',或者,年龄大于100岁的学生
db.student.find({$or: [{name: '李嘉诚'}, {age: {$gt: 100}}]})
  1. nor

    $nor: [条件1,条件2,条件3]

查询年龄不等于38,并且,名字不叫'朱元璋'的学生
db.student.find({$nor: [{age: {$lt:38}}, {name: '朱元璋'}]})
5.4 范围运算符

使用 i n , in, innin判断数据是否在某个数组内

查询年龄是28或38的学生
db.student.find({age: {$in: [28, 38]}})
5.5 正则表达式

使用$regex进行正则表达式匹配

查询地址是北京的学生信息
db.student.find({address: {$regex: '^北京'}})
db.student.find({address: /^北京/})
5.6 自定义查询 (了解)

mongo shell是一个js的执行环境

使用 $where 写一个函数,返回满足条件的数据

查询年龄大于38岁的学生信息
db.student.find({$where: function(){return this.age > 38}})
5.7 skip 和 limit
db.student.find().skip(3).limit(3)

跳过3个,提取3个,类似limit 3,3 可以用来做分页

5.8 投影

投影可以控制最终查询的结果(字段筛选)

查询所有学生的数据的姓名,年龄,分数,但不显示它们的_id
db.student.find({}, {_id: 0, name: 1, age: 1, score: 1})

需要看的字段给1

注意,除了_id外,0,1不能共存

5.9 排序

sort({字段:1, 字段:-1})

1表示升序

-1表示降序

将所有学生的成绩按照降序排列
db.student.find().sort({score:-1})
5.10 统计数量

count(条件) 查询数量

统计年龄为33的学生个数
db.student.count({age: 33})

五、pymongo的使用

1. 增删改查操作

from audioop import add
from pymongo import MongoClient

def get_db(database, user=None, pwd=None):
    client = MongoClient(host='localhost', port=27017)  # 默认端口号:27017
    # 如果有账号,则需要登录
    # admin = client['admin']
    # admin.authenticate(user, pwd)
    # 如果没有设置用户名密码,直接切换就可以了
    db = client[database]     # use haha
    return db

def add_one(database, table, data):
    db = get_db(database)
    result = db[table].insert_one(data)
    return result

def add_many(database, table, data_list):
    db = get_db(database)
    result = db[table].insert_many(data_list)
    return result

def upd(database, table, condition, data):
    db = get_db(database)
    result = db[table].update_many(condition, {'$set': data})
    return result

def delete(database, table, condition):
    db = get_db(database)
    result = db[table].delete_many(condition)
    return result

def query(database, table, condition):
    db = get_db(database)
    result = db[table].find(condition)
    return list(result)

if __name__ == '__main__':
    # 增加一条学生信息
    ret = add_one('haha', 'student', {'name': '周杰伦', 'age': 18, 'address': '元宇宙', 'score': '无穷大'})
    print(ret)

    # 增加多条学生信息
    data_list = [
        {'name': '蔡依林', 'age': 17, 'address': '元宇宙', 'score': '无穷大大'},
        {'name': '陈奕迅', 'age': 19, 'address': '元宇宙', 'score': '无穷小'},
        {'name': '张学友', 'age': 20, 'address': '元宇宙', 'score': '无穷小小'}
    ]
    ret = add_many('haha', 'student', data_list)
    print(ret)

    # 修改学生信息
    ret = upd('haha', 'student', {"address": "元宇宙"}, {"score": 100})
    print(ret)

    # 删除学生信息
    ret = delete('haha', 'student', {"address": "元宇宙"})
    print(ret)

    # 查询年纪大于33岁的学生信息
    ret = query('haha', 'student', {"age": {"$gt": 33}})
    for r in ret:
        print(r)
        
    # 查询北京学生的信息
    ret = query('haha', 'student', {"address": {"$regex": "^北"}})
    for r in ret:
        print(r)

2. 抓取二手房信息

import requests
from lxml import etree
from mangodb import add_many
import pymysql

def get_page_source(url):
    resp = requests.get(url)
    page_source = resp.text
    return page_source

def parse(html):
    tree = etree.HTML(html)
    li_list = tree.xpath('//ul[@class="sellListContent"]/li')
    result = []
    for li in li_list:
        title = li.xpath('./div[1]/div[1]/a/text()')[0]
        address = ' '.join(li.xpath('./div[1]/div[2]/div/a/text()'))
        houseInfo = li.xpath('./div[1]/div[3]/div/text()')[0]
        starInfo = li.xpath('./div[1]/div[4]/text()')[0]
        tag = ' '.join(li.xpath('./div[1]/div[5]/span/text()'))
        total_price = li.xpath('./div[1]/div[6]/div[1]/span/text()')[0] + '万元'
        per_price = li.xpath('./div[1]/div[6]/div[2]/span/text()')[0]
        
        dic = {
            "title": title,
            "address": address,
            "houseInfo": houseInfo,
            "starInfo": starInfo,
            "tag": tag,
            "total_price": total_price,
            "per_price": per_price
        }
        result.append(dic)
    return result

def save_to_mongo(data_list):
    add_many('ershoufang', 'ershoufang', data_list)
    print("一页保存完毕!")

def save_to_mysql(data_list):
    try:
        conn = pymysql.connect(
            host='localhost',
            port=3306,
            user='root',  # The first four arguments is based on DB-API 2.0 recommendation.
            password="xxxxxx",
            database='spider'
        )
        cursor = conn.cursor()
        sql = """
        insert into ershoufang(title, address, houseInfo, startInfo, tag, total_price, per_price) values
        (%s, %s, %s, %s, %s, %s, %s)
        """
        lst = (tuple(dic.values()) for dic in data_list)
        cursor.executemany(sql, lst)
        conn.commit()
        print("一页保存完毕!")
    except:
        conn.rollback()
    finally:
        if cursor:
            cursor.close()
        if conn:
            conn.close()

if __name__ == '__main__':
    for i in range(1, 31):
        url = "https://bj.lianjia.com/ershoufang/pg{i}/"
        page_source = get_page_source(url)
        data_list = parse(page_source)
        # save_to_mongo(data_list)
        save_to_mysql(data_list)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值