• python mongo存在插入不存在更新,同时指定如果不存在才插入的字段


    python爬虫的任务数据操作的小技巧

    好久没写公众号了,最近太忙了,这里就不多说了。直接根据需求上代码,我想这个应该是大家比较喜欢的,

    需求

    爬取某网站的项目列表页,获取其url,标题等信息,作为后续爬取详情页的任务url。

    先上代码

    代码

    # -*- coding: utf-8 -*-
    # @Time : 2019-11-08 14:04
    # @Author : cxa
    # @File : motor_helper.py
    # @Software: PyCharm
    
    import asyncio 
    import datetime
    from loguru import logger
    from motor.motor_asyncio import AsyncIOMotorClient
    from collections import Iterable
    
    try:
        import uvloop
    
        asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
    except ImportError:
        pass
    
    db_configs = {
        'host': '127.0.0.1',
        'port': '27017',
        'db_name': 'mafengwo',
        'user': ''
    }
    
    class MotorOperation:
        def __init__(self):
            self.__dict__.update(**db_configs)
            if self.user:
                self.motor_uri = f"mongodb://{self.user}:{self.passwd}@{self.host}:{self.port}/{self.db_name}?authSource={self.db_name}"
            else:
                self.motor_uri = f"mongodb://{self.host}:{self.port}/{self.db_name}"
            self.client = AsyncIOMotorClient(self.motor_uri)
            self.mb = self.client[self.db_name]
        async def save_data_with_status(self, items, col="seed_data"):
            for item in items:
                data = dict()
                data["update_time"] = datetime.datetime.now()
                data["status"] = 0  # 0初始
                data.update(item)
                print("data", data)
                await self.mb[col].update_one({
                    "url": item.get("url")},
                    {'$set': data, '$setOnInsert': {'create_time': datetime.datetime.now()}},
                    upsert=True)
    
         async def add_index(self, col="seed_data"):
            # 添加索引
            await self.mb[col].create_index('url')
    

    因为我的爬虫是异步网络模块aiohttp写的,所以选择了pymongo的异步版本motor进行操作。
    异步代码的基本属性就是async/await成对的出现,如果把上面的await和async去掉,就是类似pymongo的写法了,这里异步不是重点,重点是我们怎么处理每条数据。

    这里除了网页的url,标题等信息,我需要附加3个字段。分别是create_time, status,update_time。
    这三个字段分别代表,数据插入数据,状态和更新时间。

    那么我为什么添加三个字段呢?

    首先,我们需要判断每次的任务数据是否存在,我这里的情况是存在就更新不存在就插入,那么我就需要一个查询条件,作为更新的条件,很显然这里可以使用任务的url作为唯一条件(你还可以使用url+标题做个md5然后保存)。好了查询条件确定,
    下面说create_time这个比较好理解就是数据插入时间,关键是为什么还要一个update_time,这个的话和status字段有一定的关系。 画重点:这个status作为后续爬虫进行爬取的一个标志用。目前这个status有4个值,0-4,我这是这样定义的,
    0:初始状态 1:抓取中的任务 2:抓取成功 3:抓取失败 4:抓取成功但是没有匹配到任务。
    后面随着任务的爬取,状态也是不断变化的,同时我们需要更新update_time为最新的时间。这个目前的话是体现不出来什么作用,它的使用场景是,重复任务的抓取,比如今天我抓取了任务列表里的url1,url2,第二天的时候我如果再抓到,为了区分是抓取失败还是抓取成功,我们根据create_time和update_time就可以进行推断了,如果两者相同而且是当前的日期说明刚抓的,如果update_time的日期比create_time新可以说明,抓到了重复的任务。关于字段的设计就啰嗦这么写。

    下面是实现,我们可以通过update_one方法,对数据作存在或者插入操作,因为url作为查询条件,后面量大的话就最好添加一个索引。也就是上面的 add_index方法。

    好了最好说插入更新的具体代码

    需要注意的是

    {'$set': data, '$setOnInsert': {'create_time': datetime.datetime.now()}}
    

    $setOnInsert里面使用的字段是数据不存在的时候才插入的,存在就不动了,只插入$set里面指定的。
    另外$setOnInsert里面使用的字段不能在$set里面再次出现
    upsert=True代表的是不存在就插入。

    大概就这么多,不明白的可以给我留言,或者添加微信进群交流。

  • 相关阅读:
    SpringCloud Ribbon实现负载均衡,SpringCloud Ribbon自定义策略
    springCloud zookeeper整合,Java Zookeeper微服务注册中心整合
    SpringCloud Eureka安装和使用,SpringCloud使用Eureka作为服务注册中心
    Linux yum安装Consul服务中心,Centos7在线安装consul
    SpringCloud consul安装和使用,Windows Consul安装和使用,Java consul服务中心安装和使用
    哔哩哔哩视频下载到电脑,bilibili UWP下载的视频重命名,blibli视频下载到电脑
    elasticsearch kibana安装和配置
    elasticsearch安装和配置,elasticsearch启动报错:can not run elasticsearch as root
    cmd打开当前文件所在目录,cmd进入当前文件目录,cmd进入指定目录
    京东到家 首页 笔记
  • 原文地址:https://www.cnblogs.com/c-x-a/p/11895685.html
Copyright © 2020-2023  润新知